Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: NITF Read/Write Library 4 : * Purpose: Manages writing offsets to file locations 5 : * Author: Even Rouault, even dot rouault at spatialys dot com 6 : * 7 : ********************************************************************** 8 : * Copyright (c) 2026, T-Kartor 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #ifndef OFFSET_PATCHER_INCLUDED 14 : #define OFFSET_PATCHER_INCLUDED 15 : 16 : #include "cpl_vsi_virtual.h" 17 : 18 : #include <cstdint> 19 : 20 : #include <map> 21 : #include <memory> 22 : #include <string> 23 : #include <vector> 24 : 25 : namespace GDALOffsetPatcher 26 : { 27 : 28 : class OffsetPatcher; 29 : class OffsetPatcherBuffer; 30 : 31 : constexpr vsi_l_offset INVALID_OFFSET = static_cast<vsi_l_offset>(-1); 32 : 33 : /************************************************************************/ 34 : /* OffsetOrSizeLocation */ 35 : /************************************************************************/ 36 : 37 : /** Location of an offset or size */ 38 : struct OffsetOrSizeLocation 39 : { 40 : OffsetPatcherBuffer *buffer = nullptr; 41 : size_t offsetInBuffer = 0; 42 : }; 43 : 44 : /************************************************************************/ 45 : /* OffsetOrSizeReference */ 46 : /************************************************************************/ 47 : 48 : /** Reference to an offset or size */ 49 : struct OffsetOrSizeReference 50 : { 51 : OffsetPatcherBuffer *buffer = nullptr; 52 : size_t offsetInBuffer = 0; 53 : int objectSizeBytes = 0; 54 : bool bEndiannessIsLittle = true; 55 : }; 56 : 57 : /************************************************************************/ 58 : /* OffsetOrSizeDeclaration */ 59 : /************************************************************************/ 60 : 61 : /** Declaration of a to-be-resolved offset location or size. */ 62 : class OffsetOrSizeDeclaration 63 : { 64 : public: 65 1177 : explicit OffsetOrSizeDeclaration(const std::string &osName, 66 : bool bRelativeToStartOfBuffer = false) 67 1177 : : m_osName(osName), m_bRelativeToStartOfBuffer(bRelativeToStartOfBuffer) 68 : { 69 1177 : } 70 : 71 : bool HasAlreadyRegisteredLocation() const 72 : { 73 : return m_location.buffer != nullptr; 74 : } 75 : 76 : const OffsetOrSizeLocation &GetLocation() const 77 : { 78 : return m_location; 79 : } 80 : 81 : bool SetLocation(OffsetPatcherBuffer *buffer, size_t offsetInBuffer); 82 : void SetReference(OffsetPatcherBuffer *buffer, size_t offsetInBuffer, 83 : int objectSizeBytes, bool bEndiannessIsLittle); 84 : 85 : private: 86 : friend class OffsetPatcher; 87 : 88 : const std::string m_osName; 89 : const bool m_bRelativeToStartOfBuffer; 90 : OffsetOrSizeLocation m_location{}; 91 : std::vector<OffsetOrSizeReference> m_references{}; 92 : }; 93 : 94 : /************************************************************************/ 95 : /* OffsetPatcherBuffer */ 96 : /************************************************************************/ 97 : 98 : /** Buffer that can contain unresolved references to an offset in another 99 : * buffer or the size of another buffer. 100 : */ 101 : class OffsetPatcherBuffer 102 : { 103 : public: 104 570 : explicit OffsetPatcherBuffer(const std::string &osName, 105 : OffsetPatcher &offsetPatcher, 106 : bool bEndiannessIsLittle) 107 570 : : m_osName(osName), m_offsetPatcher(offsetPatcher), 108 570 : m_bEndiannessIsLittle(bEndiannessIsLittle) 109 : { 110 570 : } 111 : 112 : void AppendUInt32RefForOffset(const std::string &osName, 113 : bool bRelativeToStartOfBuffer = false); 114 : void AppendUInt16RefForSizeOfBuffer(const std::string &osBufferName); 115 : void AppendUInt32RefForSizeOfBuffer(const std::string &osBufferName); 116 : void AppendByte(uint8_t byVal); 117 : void AppendUInt16(uint16_t nVal); 118 : void AppendUInt32(uint32_t nVal); 119 : void AppendFloat64(double dfVal); 120 : void AppendString(const std::string &s); 121 : 122 : bool DeclareOffsetAtCurrentPosition(const std::string &osName); 123 : 124 : void DeclareBufferWrittenAtPosition(vsi_l_offset nFileOffset); 125 : 126 3046 : const std::vector<uint8_t> &GetBuffer() const 127 : { 128 3046 : return m_abyBuffer; 129 : } 130 : 131 : vsi_l_offset GetFileLocation() const 132 : { 133 : return m_nOffset; 134 : } 135 : 136 : private: 137 : friend class OffsetPatcher; 138 : 139 : const std::string m_osName; 140 : OffsetPatcher &m_offsetPatcher; 141 : const bool m_bEndiannessIsLittle; 142 : std::vector<uint8_t> m_abyBuffer{}; 143 : vsi_l_offset m_nOffset = INVALID_OFFSET; 144 : 145 28967 : bool NeedByteSwap() const 146 : { 147 : #if CPL_IS_LSB 148 28967 : return !m_bEndiannessIsLittle; 149 : #else 150 : return m_bEndiannessIsLittle; 151 : #endif 152 : } 153 : }; 154 : 155 : /************************************************************************/ 156 : /* OffsetPatcher */ 157 : /************************************************************************/ 158 : 159 : /** Higher level class managing buffers, offset and sizes declarations */ 160 : class OffsetPatcher 161 : { 162 : public: 163 161 : OffsetPatcher() = default; 164 : 165 : OffsetPatcherBuffer *CreateBuffer(const std::string &osName, 166 : bool bEndiannessIsLittle); 167 : 168 : OffsetPatcherBuffer *GetBufferFromName(const std::string &osName) const; 169 : OffsetOrSizeDeclaration * 170 : GetOffsetDeclaration(const std::string &osName) const; 171 : 172 : bool Finalize(VSILFILE *fp); 173 : 174 : private: 175 : friend class OffsetPatcherBuffer; 176 : 177 : std::map<std::string, std::unique_ptr<OffsetPatcherBuffer>> m_buffers{}; 178 : std::map<std::string, std::unique_ptr<OffsetOrSizeDeclaration>> m_offsets{}; 179 : std::map<std::string, std::unique_ptr<OffsetOrSizeDeclaration>> m_sizes{}; 180 : 181 : OffsetPatcher(const OffsetPatcher &) = delete; 182 : OffsetPatcher &operator=(const OffsetPatcher &) = delete; 183 : }; 184 : 185 : } // namespace GDALOffsetPatcher 186 : 187 : #endif // OFFSET_PATCHER_INCLUDED