diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp index bee31e3200..7035d8fc54 100644 --- a/libraries/ktx/src/ktx/KTX.cpp +++ b/libraries/ktx/src/ktx/KTX.cpp @@ -71,6 +71,35 @@ size_t Header::evalImageSize(uint32_t level) const { } +KeyValue::KeyValue(const std::string& key, uint32_t valueByteSize, const Byte* value) : + _byteSize((uint32_t) key.size() + valueByteSize), + _key(key), + _value(valueByteSize) +{ + if (_value.size() && value) { + memcpy(_value.data(), value, valueByteSize); + } +} + +KeyValue::KeyValue(const std::string& key, const std::string& value) : + KeyValue(key, (uint32_t) value.size(), (const Byte*) value.data()) +{ + +} + +uint32_t KeyValue::serializedByteSize() const { + return (uint32_t) (sizeof(uint32_t) + _byteSize + Header::evalPadding(_byteSize)); +} + +uint32_t KeyValue::serializedKeyValuesByteSize(const KeyValues& keyValues) { + size_t keyValuesSize = 0; + for (auto& keyval : keyValues) { + keyValuesSize += keyval.serializedByteSize(); + } + return (keyValuesSize + Header::evalPadding(keyValuesSize)); +} + + KTX::KTX() { } diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index 3ea14b2cb5..8fdbe25ac9 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -385,9 +386,27 @@ namespace ktx { }; // Key Values - using KeyValue = std::pair; - using KeyValues = std::list; - + struct KeyValue { + uint32_t _byteSize { 0 }; + std::string _key; + std::vector _value; + + + KeyValue(const std::string& key, uint32_t valueByteSize, const Byte* value); + + KeyValue(const std::string& key, const std::string& value); + + uint32_t serializedByteSize() const; + + static KeyValue parseKeyAndValue(uint32_t keyAndValueByteSize, const Byte* bytes); + static KeyValue parseSerializedKeyAndValue(uint32_t byteSizeAhead, const Byte* bytes); + + using KeyValues = std::list; + static uint32_t serializedKeyValuesByteSize(const KeyValues& keyValues); + + }; + using KeyValues = KeyValue::KeyValues; + struct Image { using FaceBytes = std::vector; @@ -445,12 +464,14 @@ namespace ktx { // This is exactly what is done in the create function static size_t evalStorageSize(const Header& header, const Images& images, const KeyValues& keyValues = KeyValues()); static size_t write(Byte* destBytes, size_t destByteSize, const Header& header, const Images& images, const KeyValues& keyValues = KeyValues()); + static size_t writeKeyValues(Byte* destBytes, size_t destByteSize, const KeyValues& keyValues); static Images writeImages(Byte* destBytes, size_t destByteSize, const Images& images); // Parse a block of memory and create a KTX object from it static std::unique_ptr create(const StoragePointer& src); static bool checkHeaderFromStorage(size_t srcSize, const Byte* srcBytes); + static KeyValues parseKeyValues(size_t srcSize, const Byte* srcBytes); static Images parseImages(const Header& header, size_t srcSize, const Byte* srcBytes); // Access raw pointers to the main sections of the KTX diff --git a/libraries/ktx/src/ktx/Reader.cpp b/libraries/ktx/src/ktx/Reader.cpp index f8004cf21a..10a75ddfe7 100644 --- a/libraries/ktx/src/ktx/Reader.cpp +++ b/libraries/ktx/src/ktx/Reader.cpp @@ -56,38 +56,52 @@ namespace ktx { return true; } - KeyValues getKeyValues(size_t length, const Byte* src) { - KeyValues keyValues; - size_t offset = 0; - while (offset < length) { - // determine byte size - uint32_t keyValueByteSize; - memcpy(&keyValueByteSize, src, sizeof(uint32_t)); - if (keyValueByteSize > length - offset) { - throw ReaderException("invalid key-value size"); + KeyValue KeyValue::parseKeyAndValue(uint32_t keyAndValueByteSize, const Byte* bytes) { + // find the first null character \0 + uint32_t keyLength = 0; + while (reinterpret_cast(bytes[++keyLength]) != '\0') { + if (keyLength == keyAndValueByteSize) { + // key must be null-terminated, and there must be space for the value + throw ReaderException("invalid key-value " + std::string(reinterpret_cast(bytes), keyLength)); } - - // find the first null character \0 - uint32_t keyLength = 0; - while (reinterpret_cast(src[++keyLength]) != '\0') { - if (keyLength == keyValueByteSize) { - // key must be null-terminated, and there must be space for the value - throw ReaderException("invalid key-value " + std::string(reinterpret_cast(src), keyLength)); - } - } - - // populate the key-value - keyValues.emplace_back( - std::move(std::string(reinterpret_cast(src), keyLength)), - std::move(std::string(reinterpret_cast(src + keyLength), keyValueByteSize - keyLength))); - - // advance offset/src - uint32_t keyValuePadding = 3 - ((keyValueByteSize + 3) % PACKING_SIZE); - offset += keyValueByteSize + keyValuePadding; - src += keyValueByteSize + keyValuePadding; } + return KeyValue(std::string(reinterpret_cast(bytes), keyLength), keyAndValueByteSize - keyLength, bytes + keyLength); + } + + static KeyValue parseSerializedKeyAndValue(uint32_t byteSizeAhead, const Byte* bytes) { + uint32_t keyValueByteSize; + memcpy(&keyValueByteSize, bytes, sizeof(uint32_t)); + if (keyValueByteSize > byteSizeAhead) { + throw ReaderException("invalid key-value size"); + } + + auto keyValueBytes = bytes + sizeof(uint32_t); + + // parse the key-value + return KeyValue::parseKeyAndValue(keyValueByteSize, keyValueBytes); + } + + static KeyValues parseKeyValues(size_t srcSize, const Byte* srcBytes); + + KeyValues KTX::parseKeyValues(size_t srcSize, const Byte* src) { + KeyValues keyValues; + try { + uint32_t length = (uint32_t) srcSize; + uint32_t offset = 0; + while (offset < length) { + auto keyValue = parseSerializedKeyAndValue(length - offset, src); + keyValues.emplace_back(keyValue); + + // advance offset/src + offset += keyValue.serializedByteSize(); + src += keyValue.serializedByteSize(); + } + } + catch (const ReaderException& e) { + qWarning() << e.what(); + } return keyValues; } @@ -176,7 +190,7 @@ namespace ktx { result->resetStorage(src); // read metadata - // result->_keyValues = getKeyValues(result->getHeader()->bytesOfKeyValueData, result->getKeyValueData()); + result->_keyValues = parseKeyValues(result->getHeader()->bytesOfKeyValueData, result->getKeyValueData()); // populate image table result->_images = parseImages(*result->getHeader(), result->getTexelsDataSize(), result->getTexelsData()); diff --git a/libraries/ktx/src/ktx/Writer.cpp b/libraries/ktx/src/ktx/Writer.cpp index 005b8e9e45..1a1c39e2c6 100644 --- a/libraries/ktx/src/ktx/Writer.cpp +++ b/libraries/ktx/src/ktx/Writer.cpp @@ -29,9 +29,9 @@ namespace ktx { std::unique_ptr KTX::create(const Header& header, const Images& images, const KeyValues& keyValues) { StoragePointer storagePointer; { - auto storageSize = ktx::KTX::evalStorageSize(header, images); + auto storageSize = ktx::KTX::evalStorageSize(header, images, keyValues); auto memoryStorage = new storage::MemoryStorage(storageSize); - ktx::KTX::write(memoryStorage->data(), memoryStorage->size(), header, images); + ktx::KTX::write(memoryStorage->data(), memoryStorage->size(), header, images, keyValues); storagePointer.reset(memoryStorage); } return create(storagePointer); @@ -40,8 +40,9 @@ namespace ktx { size_t KTX::evalStorageSize(const Header& header, const Images& images, const KeyValues& keyValues) { size_t storageSize = sizeof(Header); - if (header.bytesOfKeyValueData && !keyValues.empty()) { - + if (!keyValues.empty()) { + size_t keyValuesSize = KeyValue::serializedKeyValuesByteSize(keyValues); + storageSize += keyValuesSize; } auto numMips = header.getNumberOfLevels(); @@ -68,11 +69,12 @@ namespace ktx { currentDestPtr += sizeof(Header); // KeyValues - // Skip for now - if (header.bytesOfKeyValueData && !keyValues.empty()) { - + if (!keyValues.empty()) { + destHeader->bytesOfKeyValueData = writeKeyValues(currentDestPtr, destByteSize - sizeof(Header), keyValues); + } else { + // Make sure the header contains the right bytesOfKeyValueData size + destHeader->bytesOfKeyValueData = 0; } - destHeader->bytesOfKeyValueData = 0; currentDestPtr += destHeader->bytesOfKeyValueData; // Images @@ -82,6 +84,11 @@ namespace ktx { return destByteSize; } + static size_t writeKeyValues(Byte* destBytes, size_t destByteSize, const KeyValues& keyValues) { + + + } + Images KTX::writeImages(Byte* destBytes, size_t destByteSize, const Images& srcImages) { Images destImages; auto imagesDataPtr = destBytes;