// slang-serialize-types.cpp #include "slang-serialize-types.h" #include "../core/slang-byte-encode-util.h" #include "../core/slang-math.h" #include "../core/slang-text-io.h" namespace Slang { // Needed for linkage with some compilers /* static */ const SerialStringData::StringIndex SerialStringData::kNullStringIndex; /* static */ const SerialStringData::StringIndex SerialStringData::kEmptyStringIndex; namespace { // anonymous struct ByteReader { Byte operator()() const { return Byte(*m_pos++); } ByteReader(const char* pos) : m_pos(pos) { } mutable const char* m_pos; }; } // namespace // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SerialStringTableUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /* static */ void SerialStringTableUtil::encodeStringTable( const StringSlicePool& pool, List& stringTable) { // Skip the default handles -> nothing is encoded via them return encodeStringTable(pool.getAdded(), stringTable); } /* static */ void SerialStringTableUtil::encodeStringTable( const ConstArrayView& slices, List& stringTable) { stringTable.clear(); for (const auto& slice : slices) { // TODO(JS): // This is a bit of a hack. We need to store the string length, along with the string // contents. We don't want to write the size as (say) uint32, because most strings are // short. So we just save off the length as a utf8 encoding. As it stands this *does* have // an arguable problem because encoding isn't of the full 32 bits. const int len = int(slice.getLength()); // We need to write into the the string array char prefixBytes[6]; const int numPrefixBytes = encodeUnicodePointToUTF8(len, prefixBytes); const Index baseIndex = stringTable.getCount(); auto newCount = baseIndex + numPrefixBytes + len; stringTable.growToCount(newCount); char* dst = stringTable.begin() + baseIndex; memcpy(dst, prefixBytes, numPrefixBytes); memcpy(dst + numPrefixBytes, slice.begin(), len); } } /* static */ void SerialStringTableUtil::appendDecodedStringTable( const char* table, size_t tableSize, List& slicesOut) { const char* start = table; const char* cur = start; const char* end = table + tableSize; while (cur < end) { ByteReader reader(cur); const int len = getUnicodePointFromUTF8(reader); slicesOut.add(UnownedStringSlice(reader.m_pos, len)); cur = reader.m_pos + len; } } /* static */ void SerialStringTableUtil::decodeStringTable( const char* table, size_t tableSize, List& slicesOut) { slicesOut.setCount(2); slicesOut[0] = UnownedStringSlice(nullptr, size_t(0)); slicesOut[1] = UnownedStringSlice("", size_t(0)); appendDecodedStringTable(table, tableSize, slicesOut); } /* static */ void SerialStringTableUtil::decodeStringTable( const char* table, size_t tableSize, StringSlicePool& outPool) { outPool.clear(); const char* start = table; const char* cur = start; const char* end = table + tableSize; while (cur < end) { ByteReader reader(cur); const int len = getUnicodePointFromUTF8(reader); outPool.add(UnownedStringSlice(reader.m_pos, len)); cur = reader.m_pos + len; } } /* static */ void SerialStringTableUtil::calcStringSlicePoolMap( const List& slices, StringSlicePool& pool, List& indexMapOut) { SLANG_ASSERT(slices.getCount() >= StringSlicePool::kDefaultHandlesCount); SLANG_ASSERT( slices[int(StringSlicePool::kNullHandle)] == "" && slices[int(StringSlicePool::kNullHandle)].begin() == nullptr); SLANG_ASSERT(slices[int(StringSlicePool::kEmptyHandle)] == ""); indexMapOut.setCount(slices.getCount()); // Set up all of the defaults for (int i = 0; i < StringSlicePool::kDefaultHandlesCount; ++i) { indexMapOut[i] = StringSlicePool::Handle(i); } const Index numSlices = slices.getCount(); for (Index i = StringSlicePool::kDefaultHandlesCount; i < numSlices; ++i) { indexMapOut[i] = pool.add(slices[i]); } } // !!!!!!!!!!!!!!!!!!!!!!!!!!!! SerialRiffUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /* static */ Result SerialRiffUtil::writeArrayChunk( FourCC chunkId, const void* data, size_t numEntries, size_t typeSize, RIFF::BuildCursor& cursor) { if (numEntries == 0) { return SLANG_OK; } SLANG_SCOPED_RIFF_BUILDER_DATA_CHUNK(cursor, chunkId); SerialBinary::ArrayHeader header; header.numEntries = uint32_t(numEntries); cursor.addData(&header, sizeof(header)); cursor.addData(data, typeSize * numEntries); return SLANG_OK; } /* static */ Result SerialRiffUtil::readArrayChunk( RIFF::DataChunk const* dataChunk, ListResizer& listOut) { typedef SerialBinary Bin; MemoryReader reader(dataChunk->getPayload(), dataChunk->getPayloadSize()); const Size typeSize = listOut.getTypeSize(); Bin::ArrayHeader header; SLANG_RETURN_ON_FAIL(reader.read(header)); const Size payloadSize = header.numEntries * typeSize; SLANG_ASSERT(payloadSize == reader.getRemainingSize()); void* dst = listOut.setSize(header.numEntries); ::memcpy(dst, reader.getRemainingData(), payloadSize); return SLANG_OK; } } // namespace Slang