XRefTable.h 3.3 KB

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