XRefTable.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Format.h>
  8. namespace PDF {
  9. constexpr long invalid_byte_offset = NumericLimits<long>::max();
  10. struct XRefEntry {
  11. long byte_offset { invalid_byte_offset };
  12. u16 generation_number { 0 };
  13. bool in_use { false };
  14. };
  15. struct XRefSection {
  16. int starting_index;
  17. int count;
  18. Vector<XRefEntry> entries;
  19. };
  20. class XRefTable final : public RefCounted<XRefTable> {
  21. public:
  22. bool merge(XRefTable&& other)
  23. {
  24. auto this_size = m_entries.size();
  25. auto other_size = other.m_entries.size();
  26. m_entries.ensure_capacity(other_size);
  27. for (size_t i = 0; i < other_size; i++) {
  28. auto other_entry = other.m_entries[i];
  29. if (i >= this_size) {
  30. m_entries.unchecked_append(other_entry);
  31. continue;
  32. }
  33. auto this_entry = m_entries[i];
  34. if (this_entry.byte_offset == invalid_byte_offset) {
  35. m_entries[i] = other_entry;
  36. } else if (other_entry.byte_offset != invalid_byte_offset) {
  37. // Both xref tables have an entry for the same object index
  38. return false;
  39. }
  40. }
  41. return true;
  42. }
  43. void add_section(XRefSection const& section)
  44. {
  45. m_entries.ensure_capacity(section.starting_index + section.count);
  46. for (int i = static_cast<int>(m_entries.size()); i < section.starting_index; i++)
  47. m_entries.append(XRefEntry {});
  48. for (auto& entry : section.entries)
  49. m_entries.append(entry);
  50. }
  51. [[nodiscard]] ALWAYS_INLINE bool has_object(size_t index) const
  52. {
  53. return index < m_entries.size() && m_entries[index].byte_offset != -1;
  54. }
  55. [[nodiscard]] ALWAYS_INLINE long byte_offset_for_object(size_t index) const
  56. {
  57. VERIFY(has_object(index));
  58. return m_entries[index].byte_offset;
  59. }
  60. [[nodiscard]] ALWAYS_INLINE u16 generation_number_for_object(size_t index) const
  61. {
  62. VERIFY(has_object(index));
  63. return m_entries[index].generation_number;
  64. }
  65. [[nodiscard]] ALWAYS_INLINE bool is_object_in_use(size_t index) const
  66. {
  67. VERIFY(has_object(index));
  68. return m_entries[index].in_use;
  69. }
  70. private:
  71. friend struct AK::Formatter<PDF::XRefTable>;
  72. Vector<XRefEntry> m_entries;
  73. };
  74. }
  75. namespace AK {
  76. template<>
  77. struct Formatter<PDF::XRefEntry> : Formatter<StringView> {
  78. void format(FormatBuilder& builder, PDF::XRefEntry const& entry)
  79. {
  80. Formatter<StringView>::format(builder,
  81. String::formatted("XRefEntry {{ offset={} generation={} used={} }}",
  82. entry.byte_offset,
  83. entry.generation_number,
  84. entry.in_use));
  85. }
  86. };
  87. template<>
  88. struct Formatter<PDF::XRefTable> : Formatter<StringView> {
  89. void format(FormatBuilder& format_builder, PDF::XRefTable const& table)
  90. {
  91. StringBuilder builder;
  92. builder.append("XRefTable {");
  93. for (auto& entry : table.m_entries)
  94. builder.appendff("\n {}", entry);
  95. builder.append("\n}");
  96. Formatter<StringView>::format(format_builder, builder.to_string());
  97. }
  98. };
  99. }