XRefTable.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. * Copyright (c) 2021-2022, Matthew Olsson <mattco@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/ByteString.h>
  8. #include <AK/Format.h>
  9. #include <AK/RefCounted.h>
  10. #include <AK/Vector.h>
  11. #include <LibPDF/Error.h>
  12. namespace PDF {
  13. constexpr long invalid_byte_offset = NumericLimits<long>::max();
  14. struct XRefEntry {
  15. long byte_offset { invalid_byte_offset };
  16. u16 generation_number { 0 };
  17. bool in_use { false };
  18. bool compressed { false };
  19. };
  20. struct XRefSection {
  21. int starting_index;
  22. int count;
  23. Vector<XRefEntry> entries;
  24. };
  25. class XRefTable final : public RefCounted<XRefTable> {
  26. public:
  27. PDFErrorOr<void> merge(XRefTable&& other)
  28. {
  29. auto this_size = m_entries.size();
  30. auto other_size = other.m_entries.size();
  31. TRY(m_entries.try_ensure_capacity(other_size));
  32. for (size_t i = 0; i < other_size; i++) {
  33. auto other_entry = other.m_entries[i];
  34. if (i >= this_size) {
  35. m_entries.unchecked_append(other_entry);
  36. continue;
  37. }
  38. auto this_entry = m_entries[i];
  39. // Only add values that we don't already have.
  40. if (this_entry.byte_offset == invalid_byte_offset)
  41. m_entries[i] = other_entry;
  42. }
  43. return {};
  44. }
  45. void add_section(XRefSection const& section)
  46. {
  47. m_entries.ensure_capacity(section.starting_index + section.count);
  48. for (int i = static_cast<int>(m_entries.size()); i < section.starting_index; i++)
  49. m_entries.append(XRefEntry {});
  50. for (auto& entry : section.entries)
  51. m_entries.append(entry);
  52. }
  53. void set_trailer(RefPtr<DictObject> trailer) { m_trailer = trailer; }
  54. ALWAYS_INLINE Vector<XRefEntry>& entries() { return m_entries; }
  55. ALWAYS_INLINE RefPtr<DictObject> const& trailer() const { return m_trailer; }
  56. [[nodiscard]] ALWAYS_INLINE bool has_object(size_t index) const
  57. {
  58. return index < m_entries.size() && m_entries[index].byte_offset != -1;
  59. }
  60. [[nodiscard]] ALWAYS_INLINE long byte_offset_for_object(size_t index) const
  61. {
  62. VERIFY(has_object(index));
  63. return m_entries[index].byte_offset;
  64. }
  65. [[nodiscard]] ALWAYS_INLINE long object_stream_for_object(size_t index) const
  66. {
  67. return byte_offset_for_object(index);
  68. }
  69. [[nodiscard]] ALWAYS_INLINE u16 generation_number_for_object(size_t index) const
  70. {
  71. VERIFY(has_object(index));
  72. return m_entries[index].generation_number;
  73. }
  74. [[nodiscard]] ALWAYS_INLINE u16 object_stream_index_for_object(size_t index) const
  75. {
  76. return generation_number_for_object(index);
  77. }
  78. [[nodiscard]] ALWAYS_INLINE bool is_object_in_use(size_t index) const
  79. {
  80. VERIFY(has_object(index));
  81. return m_entries[index].in_use;
  82. }
  83. [[nodiscard]] ALWAYS_INLINE bool is_object_compressed(size_t index) const
  84. {
  85. VERIFY(has_object(index));
  86. return m_entries[index].compressed;
  87. }
  88. private:
  89. friend struct AK::Formatter<PDF::XRefTable>;
  90. Vector<XRefEntry> m_entries;
  91. RefPtr<DictObject> m_trailer;
  92. };
  93. }
  94. namespace AK {
  95. template<>
  96. struct Formatter<PDF::XRefEntry> : Formatter<StringView> {
  97. ErrorOr<void> format(FormatBuilder& builder, PDF::XRefEntry const& entry)
  98. {
  99. return Formatter<StringView>::format(builder,
  100. ByteString::formatted("XRefEntry {{ offset={} generation={} used={} }}",
  101. entry.byte_offset,
  102. entry.generation_number,
  103. entry.in_use));
  104. }
  105. };
  106. template<>
  107. struct Formatter<PDF::XRefTable> : Formatter<StringView> {
  108. ErrorOr<void> format(FormatBuilder& format_builder, PDF::XRefTable const& table)
  109. {
  110. StringBuilder builder;
  111. builder.append("XRefTable {"sv);
  112. for (auto& entry : table.m_entries)
  113. builder.appendff("\n {}", entry);
  114. builder.append("\n}"sv);
  115. return Formatter<StringView>::format(format_builder, builder.to_byte_string());
  116. }
  117. };
  118. }