XRefTable.h 3.3 KB

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