| #ifndef _RIVE_RUNTIME_HEADER_HPP_ | |
| #define _RIVE_RUNTIME_HEADER_HPP_ | |
| #include "rive/core/binary_reader.hpp" | |
| #include <unordered_map> | |
| namespace rive { | |
| /// Rive file runtime header. The header is fonud at the beginning of every | |
| /// Rive runtime file, and begins with a specific 4-byte format: "RIVE". | |
| /// This is followed by the major and minor version of Rive used to create | |
| /// the file. Finally the owner and file ids are at the end of header; these | |
| /// unsigned integers may be zero. | |
| class RuntimeHeader { | |
| private: | |
| static constexpr char fingerprint[] = "RIVE"; | |
| int m_MajorVersion; | |
| int m_MinorVersion; | |
| int m_FileId; | |
| std::unordered_map<int, int> m_PropertyToFieldIndex; | |
| public: | |
| /// @returns the file's major version | |
| int majorVersion() const { return m_MajorVersion; } | |
| /// @returns the file's minor version | |
| int minorVersion() const { return m_MinorVersion; } | |
| /// @returns the file's id; may be zero | |
| int fileId() const { return m_FileId; } | |
| int propertyFieldId(int propertyKey) const { | |
| auto itr = m_PropertyToFieldIndex.find(propertyKey); | |
| if (itr == m_PropertyToFieldIndex.end()) { | |
| return -1; | |
| } | |
| return itr->second; | |
| } | |
| /// Reads the header from a binary buffer/ | |
| /// @param reader the binary reader attached to the buffer | |
| /// @param header a pointer to the header where the data will be stored. | |
| /// @returns true if the header is successfully read | |
| static bool read(BinaryReader& reader, RuntimeHeader& header) { | |
| for (int i = 0; i < 4; i++) { | |
| auto b = reader.readByte(); | |
| if (fingerprint[i] != b) { | |
| return false; | |
| } | |
| } | |
| header.m_MajorVersion = (int)reader.readVarUint64(); | |
| if (reader.didOverflow()) { | |
| return false; | |
| } | |
| header.m_MinorVersion = (int)reader.readVarUint64(); | |
| if (reader.didOverflow()) { | |
| return false; | |
| } | |
| header.m_FileId = (int)reader.readVarUint64(); | |
| if (reader.didOverflow()) { | |
| return false; | |
| } | |
| std::vector<int> propertyKeys; | |
| for (int propertyKey = (int)reader.readVarUint64(); propertyKey != 0; | |
| propertyKey = (int)reader.readVarUint64()) | |
| { | |
| propertyKeys.push_back(propertyKey); | |
| if (reader.didOverflow()) { | |
| return false; | |
| } | |
| } | |
| int currentInt = 0; | |
| int currentBit = 8; | |
| for (auto propertyKey : propertyKeys) { | |
| if (currentBit == 8) { | |
| currentInt = reader.readUint32(); | |
| currentBit = 0; | |
| } | |
| int fieldIndex = (currentInt >> currentBit) & 3; | |
| header.m_PropertyToFieldIndex[propertyKey] = fieldIndex; | |
| currentBit += 2; | |
| if (reader.didOverflow()) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| }; | |
| } // namespace rive | |
| #endif |