diff options
| author | Bryan Galdrikian <[email protected]> | 2018-05-31 11:36:08 -0700 |
|---|---|---|
| committer | Bryan Galdrikian <[email protected]> | 2018-05-31 11:36:08 -0700 |
| commit | 7115f60b91b5717d90f643fd692010905c7004db (patch) | |
| tree | effd68c6978751c517d54c2f2bb5bb6e7dc93e18 /sdk/extensions/import/apexmodules/NvParameterized/src/BinSerializer.cpp | |
| parent | Updating BlastTool zip (diff) | |
| download | blast-7115f60b91b5717d90f643fd692010905c7004db.tar.xz blast-7115f60b91b5717d90f643fd692010905c7004db.zip | |
Blast 1.1.3. See docs/release_notes.txt.v1.1.3_rc1
Diffstat (limited to 'sdk/extensions/import/apexmodules/NvParameterized/src/BinSerializer.cpp')
| -rwxr-xr-x[-rw-r--r--] | sdk/extensions/import/apexmodules/NvParameterized/src/BinSerializer.cpp | 3656 |
1 files changed, 1828 insertions, 1828 deletions
diff --git a/sdk/extensions/import/apexmodules/NvParameterized/src/BinSerializer.cpp b/sdk/extensions/import/apexmodules/NvParameterized/src/BinSerializer.cpp index 623c020..420a171 100644..100755 --- a/sdk/extensions/import/apexmodules/NvParameterized/src/BinSerializer.cpp +++ b/sdk/extensions/import/apexmodules/NvParameterized/src/BinSerializer.cpp @@ -1,1828 +1,1828 @@ -// This code contains NVIDIA Confidential Information and is disclosed to you -// under a form of NVIDIA software license agreement provided separately to you. -// -// Notice -// NVIDIA Corporation and its licensors retain all intellectual property and -// proprietary rights in and to this software and related documentation and -// any modifications thereto. Any use, reproduction, disclosure, or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA Corporation is strictly prohibited. -// -// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES -// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO -// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, -// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. -// -// Information and code furnished is believed to be accurate and reliable. -// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such -// information or for any infringement of patents or other rights of third parties that may -// result from its use. No license is granted by implication or otherwise under any patent -// or patent rights of NVIDIA Corporation. Details are subject to change without notice. -// This code supersedes and replaces all information previously supplied. -// NVIDIA Corporation products are not authorized for use as critical -// components in life support devices or systems without express written approval of -// NVIDIA Corporation. -// -// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved. - -/* - Binary serialization is very complex and error-prone - process. Ensuring that it works properly is _critically_ - important for the engine. - - Before you do any significant changes to this code - please get familiar with C/C++ object layouts. - You may find these links helpful: - - * APEX binary file format - https://wiki.nvidia.com/engwiki/index.php/PhysX/APEX/architecture/design/File_Formats - (may not be up-to-date) - - * C++ data alignment and portability - http://www.codesynthesis.com/~boris/blog/2009/04/06/cxx-data-alignment-portability/ - - * Data structure alignment - http://en.wikipedia.org/wiki/Data_structure_alignment - - * About Data Alignment - http://msdn.microsoft.com/en-us/library/ms253949%28v=VS.80%29.aspx - - * Types and Storage - http://msdn.microsoft.com/en-us/library/02c56cw3.aspx - - * Jan Gray's article in "C++: Under the Hood" - http://www.openrce.org/articles/files/jangrayhood.pdf - - * Windows Data Alignment on IPF, x86, and x64 - http://msdn.microsoft.com/en-us/library/aa290049%28VS.71%29.aspx - - * GCC alignment in classes gotcha - https://ps3.scedev.net/forums/thread/41593/ - - * all messages in thread http://compilers.iecc.com/comparch/article/94-08-119 - - * Memory Layout for Multiple and Virtual Inheritance - http://www.phpcompiler.org/articles/virtualinheritance.html - - * The "Empty Member" C++ Optimization - http://www.cantrip.org/emptyopt.html - - You may also want to see examples of existing ABI - for various platforms: - - * Agner Fog's Calling conventions for different C++ compilers - and operating systems, - http://www.agner.org/optimize/calling_conventions.pdf - - * Itanium C++ ABI Data Layout - http://www.codesourcery.com/public/cxx-abi/abi.html#layout - - * Introduction to Mac OS X ABI Function Call Guide - http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/000-Introduction/introduction.html - - After you implement you changes be sure to check that ALL - NvParameterized unit tests - * Test/MediaTest - * Test/RandomClasses - * Test/ParamRandomTest - run without errors on ALL supported platforms: - * Win32 - * Win64 - * PS3 - * XBOX 360 - (in future we may also have Mac, Tegra, Linux on PC, etc.). - - If you need to add new platform to this list, be sure to - analyze it's ABI with ABIDumper - (//sw/nvidia/shared/general/ABIDumper) and check whether - it requires special changes in current serialization code - (Mac does). - - If you ever implement new features be sure to cover them - in random schema generator - NvParameterized/scripts/RandomSchema.pl, generate a bunch - (10 at least) of new random schemas for Test/RandomClasses - and add them to p4 (and verify that they work on all - platforms!). -*/ - -#include <PxSimpleTypes.h> - -#include "PsArray.h" -#include "PsHash.h" -#include "PsHashMap.h" - -#include "NvParameters.h" -#include "nvparameterized/NvParamUtils.h" -#include "NvTraitsInternal.h" - -#include "BinaryHelper.h" - -#include "PlatformABI.h" -#include "PlatformInputStream.h" -#include "PlatformOutputStream.h" - -#include "BinSerializer.h" - -namespace NvParameterized -{ - -// Verify that file header is ok -Serializer::ErrorType BinSerializer::verifyFileHeader( - const BinaryHeader &hdr, - const BinaryHeaderExt *ext, - uint32_t dataLen ) const -{ - NV_BOOL_ERR_CHECK_WARN_RETURN( BinSerializer::Magic == hdr.magic, Serializer::ERROR_INVALID_MAGIC, "Invalid APB file: magic number does not match: %x", hdr.magic ); - NV_BOOL_ERR_CHECK_WARN_RETURN( (uint32_t)BINARY_TYPE_PLAIN == hdr.type, Serializer::ERROR_INVALID_FILE_FORMAT, "Invalid APB file: unknown file format: %d", hdr.type ); - - NV_BOOL_ERR_CHECK_WARN_RETURN( - BinVersions::WithExtendedHeader == hdr.version || BinVersions::WithAlignment == hdr.version, - Serializer::ERROR_INVALID_FILE_VERSION, "Invalid APB header: unexpected version: %x", hdr.version ); - - // Verify offsets - NV_BOOL_ERR_CHECK_WARN_RETURN( hdr.fileLength <= dataLen - && hdr.dataOffset < hdr.fileLength - && hdr.relocOffset < hdr.fileLength - && hdr.dictOffset < hdr.fileLength - && hdr.metadataOffset < hdr.fileLength, - Serializer::ERROR_INVALID_INTERNAL_PTR, - "Invalid APB file: section offsets do not match file length" ); - - if( ext ) - { - NV_BOOL_ERR_CHECK_WARN_RETURN( - 0 == memcmp((const char *)&ext->vcsSafetyFlags, VCS_SAFETY_FLAGS, 4), - Serializer::ERROR_INVALID_CHAR, - "Invalid APB file: perhaps your editor inserts redundant carriage returns?" - ); - } - - return Serializer::ERROR_NONE; -} - -// Peeks APB header from stream -static Serializer::ErrorType peekFileHeader(physx::PxFileBuf &stream, BinaryHeader &hdr, BinaryHeaderExt &ext, bool doDecanonize = true) -{ - NV_BOOL_ERR_CHECK_RETURN( - sizeof(BinaryHeader) == stream.peek(&hdr, sizeof(BinaryHeader)), - Serializer::ERROR_INVALID_FILE_FORMAT ); - - if( hdr.version >= BinVersions::WithExtendedHeader ) - { - uint32_t fileOff = stream.tellRead(); - - stream.seekRead(fileOff + sizeof(BinaryHeader)); - NV_BOOL_ERR_CHECK_RETURN( - sizeof(BinaryHeaderExt) == stream.peek(&ext, sizeof(BinaryHeaderExt)), - Serializer::ERROR_INVALID_FILE_FORMAT ); - - stream.seekRead(fileOff); - } - - if( doDecanonize ) - hdr.decanonize(); - - return Serializer::ERROR_NONE; -} - -// Extract platform ABI from file header -Serializer::ErrorType BinSerializer::getPlatformInfo( - BinaryHeader &hdr, - BinaryHeaderExt *ext, - PlatformABI &abi ) const -{ - //Difference between these versions is not important for non-inplace serializer - if( hdr.version == BinVersions::Initial || hdr.version == BinVersions::AllRefsCounted ) - hdr.version = BinVersions::WithAlignment; - - NV_ERR_CHECK_RETURN( verifyFileHeader(hdr, ext, hdr.fileLength) ); - - SerializePlatform platform; - NV_ERR_CHECK_WARN_RETURN(hdr.getPlatform(platform), "Invalid platform"); - - NV_ERR_CHECK_WARN_RETURN( PlatformABI::GetPredefinedABI(platform, abi), "Unknown platform" ); - - return Serializer::ERROR_NONE; -} - -Serializer::ErrorType BinSerializer::peekInplaceAlignment(physx::PxFileBuf& stream, uint32_t& align) -{ - BinaryHeader hdr; - BinaryHeaderExt ext; - NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext, false) ); - align = Canonize(hdr.alignment); - return Serializer::ERROR_NONE; -} - -// Verify that object matches its header -Serializer::ErrorType BinSerializer::verifyObjectHeader(const ObjHeader &hdr, const Interface *obj, Traits *traits) const -{ - DEBUG_ASSERT(obj); - NV_BOOL_ERR_CHECK_WARN_RETURN( - obj->version() == hdr.version, - Serializer::ERROR_UNKNOWN, - "Invalid object: version does not match object header" ); - - PX_UNUSED(traits); - - uint32_t bits = UINT32_MAX; - const uint32_t *checksum = obj->checksum(bits); - - if( !DoIgnoreChecksum(*obj) || hdr.version != obj->version() ) - { - if( bits != 32 * hdr.checksumSize ) - NV_PARAM_TRAITS_WARNING( - traits, - "Schema checksum is different for object of class %s and version %u, asset may be corrupted", - hdr.className, (unsigned)hdr.version - ); - else - { - for(uint32_t i = 0; i < hdr.checksumSize; ++i) - if( checksum[i] != hdr.checksum[i] ) - { - NV_PARAM_TRAITS_WARNING( - traits, - "Schema checksum is different for object of class %s and version %u, asset may be corrupted", - hdr.className, (unsigned)hdr.version - ); - break; - } - } - } - - return Serializer::ERROR_NONE; -} - -#if 0 -//TODO: this is just for tests, remove it after metadata works -static void DumpDefinition(const Definition *def, const char *className, uint32_t version, uint32_t off = 0) -{ - char *tab = (char *)::malloc(off + 1); - memset(tab, ' ', off); - tab[off] = 0; - - if( className ) - printf("%sClass %s:%d\n", tab, className, version); - - printf("%sDefinition at 0x%p:\n", tab, def); - printf("%s name = %s\n", tab, def->name()); - printf("%s type = %s\n", tab, typeToStr(def->type())); - printf("%s align = %d\n", tab, def->alignment()); - printf("%s pad = %d\n", tab, def->padding()); - - printf("%s %d hints:\n", tab, def->numHints()); - for(uint32_t i = 0; i < def->numHints(); ++i) - { - const Hint *hint = def->hint(i); - - printf("%s %s => ", tab, hint->name()); - switch( hint->type() ) - { - case TYPE_U64: - printf("%llu", hint->asUInt()); - break; - case TYPE_F64: - printf("%f", hint->asFloat()); - break; - case TYPE_STRING: - printf("\"%s\"", hint->asString()); - break; - default: - DEBUG_ALWAYS_ASSERT(); - } - printf("\n"); - } - - printf("%s %d enums: ", tab, def->numEnumVals()); - for(uint32_t i = 0; i < def->numEnumVals(); ++i) - printf("\"%s\", ", def->enumVal(i)); - printf("\n"); - - printf("%s %d refVariants: ", tab, def->numRefVariants()); - for(uint32_t i = 0; i < def->numRefVariants(); ++i) - printf("\"%s\", ", def->refVariantVal(i)); - printf("\n"); - - printf("%s %d children:\n", tab, def->numChildren()); - for(uint32_t i = 0; i < def->numChildren(); ++i) - { - printf("%sChild %d:\n", tab, i); - DumpDefinition(def->child(i), 0, 0, off + 1); - } - - ::free(tab); - - fflush(stdout); -} -#endif - -Serializer::ErrorType BinSerializer::peekNumObjects(physx::PxFileBuf &stream, uint32_t &numObjects) -{ - BinaryHeader hdr; - BinaryHeaderExt ext; - NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext, false) ); - - return peekNumObjectsInplace((const void *)&hdr, sizeof(hdr), numObjects); -} - -Serializer::ErrorType BinSerializer::peekNumObjectsInplace(const void *data, uint32_t dataLen, uint32_t &numObjects) -{ - NV_BOOL_ERR_CHECK_RETURN( dataLen >= sizeof(BinaryHeader), Serializer::ERROR_INVALID_FILE_FORMAT ); - numObjects = static_cast<uint32_t>(Canonize( ((const BinaryHeader *)data)->numObjects)); - return Serializer::ERROR_NONE; -} - -Serializer::ErrorType BinSerializer::peekClassNames(physx::PxFileBuf &stream, char **classNames, uint32_t &numClassNames) -{ - BinaryHeader hdr; - BinaryHeaderExt ext; - NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext) ); - - PlatformABI targetParams; - NV_ERR_CHECK_RETURN(getPlatformInfo( - hdr, - hdr.version >= BinVersions::WithExtendedHeader ? &ext : 0, - targetParams - )); - - PlatformInputStream objectTable(stream, targetParams, mTraits); - objectTable.skipBytes(hdr.dataOffset); - - numClassNames = physx::PxMin(numClassNames, (uint32_t)hdr.numObjects); - for(uint32_t i = 0; i < numClassNames; ++i) - { - uint32_t tmp; - NV_ERR_CHECK_RETURN( objectTable.readPtr(tmp) ); // Pointer to object data - - uint32_t classNameOff; - NV_ERR_CHECK_RETURN( objectTable.readPtr(classNameOff) ); // Pointer to className - - const char *className; - NV_ERR_CHECK_RETURN( objectTable.readString(classNameOff, className) ); - classNames[i] = mTraits->strdup(className); //User will call Traits::strfree - mTraits->free((void *)className); - - NV_ERR_CHECK_RETURN( objectTable.readPtr(tmp) ); // Pointer to name - NV_ERR_CHECK_RETURN( objectTable.readPtr(tmp) ); // Pointer to filename - } - - return Serializer::ERROR_NONE; -} - -Serializer::ErrorType BinSerializer::readMetadataInfo(const BinaryHeader &hdr, PlatformInputStream &s, DefinitionImpl *def) -{ - PX_PLACEMENT_NEW(def, DefinitionImpl)(*mTraits, false); - - s.beginStruct(s.getTargetABI().getMetaInfoAlignment()); - - //type - uint32_t type; - NV_ERR_CHECK_RETURN( s.read(type) ); - NV_BOOL_ERR_CHECK_WARN_RETURN( type < TYPE_LAST, Serializer::ERROR_INVALID_DATA_TYPE, "Unknown data type: %d", (int)type); - - //arraySize - int32_t arraySize; - NV_ERR_CHECK_RETURN( s.read(arraySize) ); - - //shortName - uint32_t nameOff; - NV_ERR_CHECK_RETURN( s.readPtr(nameOff) ); - - const char *name; - NV_ERR_CHECK_RETURN( s.readString(nameOff, name) ); //NOTE: we do not release name because DefinitionImpl does not copy it - - //structName - uint32_t structNameOff; - NV_ERR_CHECK_RETURN( s.readPtr(structNameOff) ); - - const char *structName; - NV_ERR_CHECK_RETURN( s.readString(structNameOff, structName) ); //NOTE: we do not release name because DefinitionImpl does not copy it - - // We do not have metadata for older formats without alignment - NV_BOOL_ERR_CHECK_WARN_RETURN( hdr.version >= BinVersions::WithAlignment, Serializer::ERROR_INVALID_FILE_VERSION, "Unable to deserialize metadata: file format does not support it" ); - - //alignment - uint32_t alignment; - NV_ERR_CHECK_RETURN( s.read(alignment) ); - - //padding - uint32_t padding; - NV_ERR_CHECK_RETURN( s.read(padding) ); - - def->init(name, (DataType)type, structName); - def->setArraySize(arraySize); - if( alignment ) def->setAlignment(alignment); - if( padding ) def->setPadding(padding); - - //numChildren - uint32_t numChildren; - NV_ERR_CHECK_RETURN( s.read(numChildren) ); - - //children - for(uint32_t i = 0; i < numChildren; ++i) - { - DefinitionImpl *childDef = (DefinitionImpl *)mTraits->alloc(sizeof(DefinitionImpl)); - - uint32_t off; - NV_ERR_CHECK_RETURN( s.readPtr(off) ); - - NV_ERR_CHECK_RETURN( s.pushPos(off) ); - NV_ERR_CHECK_RETURN( readMetadataInfo(hdr, s, childDef) ); - s.popPos(); - - def->addChild(childDef); - } - - //numHints - uint32_t numHints; - NV_ERR_CHECK_RETURN( s.read(numHints) ); - - //hints - for(uint32_t i = 0; i < numHints; ++i) - { - HintImpl *hint = (HintImpl *)mTraits->alloc(sizeof(HintImpl)); - PX_PLACEMENT_NEW(hint, HintImpl)(); - - s.beginStruct(s.getTargetABI().getHintAlignment()); - - //type - uint32_t hintType; - NV_ERR_CHECK_RETURN( s.read(hintType) ); - - //name - uint32_t hintNameOff; - NV_ERR_CHECK_RETURN( s.readPtr(hintNameOff) ); - - const char *hintName; - NV_ERR_CHECK_RETURN( s.readString(hintNameOff, hintName) ); - Releaser releaseName((void *)hintName, mTraits); - - //val - s.beginStruct(s.getTargetABI().getHintValueAlignment()); - switch( hintType ) - { - case TYPE_U64: - { - uint64_t val; - NV_ERR_CHECK_RETURN( s.read(val) ); - hint->init(hintName, val, false); - - break; - } - case TYPE_F64: - { - double val; - NV_ERR_CHECK_RETURN( s.read(val) ); - hint->init(hintName, val, false); - - break; - } - case TYPE_STRING: - { - uint32_t off; - NV_ERR_CHECK_RETURN( s.readPtr(off) ); - - const char *val; - NV_ERR_CHECK_RETURN( s.readString(off, val) ); - Releaser releaseVal((void *)val, mTraits); - - hint->init(hintName, val, false); - - break; - } - default: - DEBUG_ALWAYS_ASSERT(); - return Serializer::ERROR_INVALID_DATA_TYPE; - } - s.align(s.getTargetABI().getHintValueSize()); - s.closeStruct(); - - s.closeStruct(); - - def->addHint(hint); - } //i - - //numEnumVals - uint32_t numEnumVals; - NV_ERR_CHECK_RETURN( s.read(numEnumVals) ); - - //enumVals - for(uint32_t i = 0; i < numEnumVals; ++i) - { - uint32_t off; - NV_ERR_CHECK_RETURN( s.readPtr(off) ); - - const char *val; - NV_ERR_CHECK_RETURN( s.readString(off, val) ); - Releaser releaseVal((void *)val, mTraits); - - def->addEnumVal(val); - } - - //numRefVariants - uint32_t numRefVariants; - NV_ERR_CHECK_RETURN( s.read(numRefVariants) ); - - //refVariants - for(uint32_t i = 0; i < numRefVariants; ++i) - { - uint32_t off; - NV_ERR_CHECK_RETURN( s.readPtr(off) ); - - const char *val; - NV_ERR_CHECK_RETURN( s.readString(off, val) ); - Releaser releaseVal((void *)val, mTraits); - - def->addRefVariantVal(val); - } - - s.closeStruct(); - - return Serializer::ERROR_NONE; -} - -Serializer::ErrorType BinSerializer::deserializeMetadata(physx::PxFileBuf &stream, DeserializedMetadata &desData) -{ - BinaryHeader hdr; - BinaryHeaderExt ext; - NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext) ); - NV_ERR_CHECK_RETURN(verifyFileHeader( - hdr, - hdr.version >= BinVersions::WithExtendedHeader ? &ext : 0, - hdr.fileLength - )); - - PlatformABI targetParams; - NV_ERR_CHECK_RETURN(getPlatformInfo( - hdr, - hdr.version >= BinVersions::WithExtendedHeader ? &ext : 0, - targetParams - )); - - PlatformInputStream s(stream, targetParams, mTraits); - s.skipBytes(hdr.metadataOffset); - - uint32_t numMetadata = hdr.numMetadata; - - desData.init(mTraits, numMetadata); - - for(uint32_t i = 0; i < numMetadata; ++i) - { - uint32_t classNameOff; - NV_ERR_CHECK_RETURN( s.readPtr(classNameOff) ); - - const char *className; - NV_ERR_CHECK_RETURN( s.readString(classNameOff, className) ); - - uint32_t version; - NV_ERR_CHECK_RETURN( s.read(version) ); - - uint32_t entryOff; - NV_ERR_CHECK_RETURN( s.readPtr(entryOff) ); - - s.pushPos(entryOff); - - DefinitionImpl *def = (DefinitionImpl *)mTraits->alloc(sizeof(DefinitionImpl)); - NV_ERR_CHECK_WARN_RETURN( readMetadataInfo(hdr, s, def), "Failed to read metadata info" ); - -// DumpDefinition(def, className, version); - - desData[i].def = def; - desData[i].version = version; - desData[i].className = className; - - s.popPos(); - } - - return Serializer::ERROR_NONE; -} - -Serializer::ErrorType BinSerializer::internalDeserialize(physx::PxFileBuf &stream, Serializer::DeserializedData &res, bool & /*doesNeedUpdate*/) -{ - NV_BOOL_ERR_CHECK_WARN_RETURN( - PlatformABI::VerifyCurrentPlatform(), - Serializer::ERROR_INVALID_PLATFORM, - "Current platform is not supported, aborting" ); - - NV_BOOL_ERR_CHECK_RETURN( BinaryHeader::CheckAlignment(), Serializer::ERROR_INVALID_PLATFORM ); - - BinaryHeader hdr; - BinaryHeaderExt ext; - NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext) ); - - PlatformABI abi; - NV_ERR_CHECK_RETURN(getPlatformInfo( - hdr, - hdr.version >= BinVersions::WithExtendedHeader ? &ext : 0, - abi - )); - - uint32_t fileOff = stream.tellRead(); - - PlatformInputStream data(stream, abi, mTraits); - NV_ERR_CHECK_RETURN( data.skipBytes(hdr.dataOffset) ); - - res.init(mTraits, static_cast<uint32_t>(hdr.numObjects)); - for(uint32_t i = 0; i < static_cast<uint32_t>(hdr.numObjects); ++i) - { - uint32_t objOff; - NV_ERR_CHECK_RETURN( data.readPtr(objOff) ); - - if( !objOff ) - res[i] = 0; - else - { - NV_ERR_CHECK_RETURN( data.pushPos(objOff) ); - - Serializer::ErrorType error = readObject(res[i], data); - if( Serializer::ERROR_NONE != error ) - { - for(uint32_t j = 0; j < i; ++j) //Last object was destroyed in readObject - res[j]->destroy(); - - res.init(0, 0); - - return error; - } - - data.popPos(); - } - - uint32_t tmp; - NV_ERR_CHECK_RETURN( data.readPtr(tmp) ); // className - NV_ERR_CHECK_RETURN( data.readPtr(tmp) ); // name - NV_ERR_CHECK_RETURN( data.readPtr(tmp) ); // filename - } //i - - stream.seekRead(fileOff + hdr.fileLength); //Goto end of stream - - return Serializer::ERROR_NONE; -} - -static BinaryReloc *getRelocationTable(const BinaryHeader &hdr, char *start, uint32_t &nrelocs) -{ - char *ptrTable = start + hdr.relocOffset; - nrelocs = *reinterpret_cast<uint32_t *>(ptrTable); - - ptrTable += PlatformABI::align(4, GetAlignment<BinaryReloc>::value); - - return reinterpret_cast<BinaryReloc *>(ptrTable); //Alignment is ok -} - -Serializer::ErrorType BinSerializer::internalDeserializeInplace(void *mdata, uint32_t dataLen, Serializer::DeserializedData &res, bool & doesNeedUpdate) -{ - doesNeedUpdate = false; - - NV_BOOL_ERR_CHECK_WARN_RETURN( - PlatformABI::VerifyCurrentPlatform(), - Serializer::ERROR_INVALID_PLATFORM, - "Current platform is not supported, aborting" ); - - char *start = (char *)mdata; - - //Header - BinaryHeader &hdr = *reinterpret_cast<BinaryHeader *>(start); - hdr.decanonize(); //Make platform-dependent - - //Extended header - BinaryHeaderExt *ext = hdr.version >= BinVersions::WithExtendedHeader - ? reinterpret_cast<BinaryHeaderExt *>(start + sizeof(BinaryHeader)) - : 0; - if( ext ) ext->decanonize(); - - //This particular updates can be done on the fly - //Probably there is no need to set isUpdated because updates can be done on the fly - - if( hdr.version == BinVersions::Initial ) - NV_ERR_CHECK_WARN_RETURN( updateInitial2AllCounted(hdr, start), "Failed to update binary asset from 1.0 to 1.1" ); - - if( hdr.version == BinVersions::AllRefsCounted ) - NV_ERR_CHECK_WARN_RETURN( updateAllCounted2WithAlignment(hdr, start), "Failed to update binary asset from 1.1 to 1.2" ); - - NV_ERR_CHECK_RETURN( verifyFileHeader(hdr, ext, dataLen) ); - - NV_BOOL_ERR_CHECK_RETURN( IsAligned(mdata, hdr.alignment), Serializer::ERROR_UNALIGNED_MEMORY); - - //Verify platform - SerializePlatform filePlatform; - NV_ERR_CHECK_WARN_RETURN( hdr.getPlatform(filePlatform), "Unknown platform" ); - NV_BOOL_ERR_CHECK_WARN_RETURN( - GetCurrentPlatform() == filePlatform, - Serializer::ERROR_INVALID_PLATFORM, - "Failed to inplace deserialize: platforms do not match" ); - - //Fix pointers - - uint32_t nrelocs; - BinaryReloc *relocs = getRelocationTable(hdr, start, nrelocs); - - //Using refOffs-array causes a memory allocation hence it's bad. - //But we have to fix all pointers prior to calling finishNvParameterized(). - //Basically we have 3 opportunities: - // - reorder relocs s.t. NvParameterized-objects go after all other relocs (strings, etc.) - // (but this limits our binary file format + it turns out to be tricky to implement) - // - walk through array once again - // (but this may have a significant time penalty) - // - reuse space in relocation table to store offsets of references - // (this sounds nice and easy enough!) - // - or maybe just process relocations in reverse order - // (this one should be the fastest but once again this limits our format) - //For now we just keep the dynamic array as it seems to be pretty fast. - - physx::shdfnd::Array<uint32_t, Traits::Allocator> refOffs((Traits::Allocator(mTraits))); - refOffs.reserve(nrelocs / 10); - - for(uint32_t i = 0; i < nrelocs; ++i) - { - BinaryReloc &reloc = relocs[i]; - - NV_BOOL_ERR_CHECK_RETURN( - reloc.type < static_cast<uint32_t>(RELOC_LAST), - Serializer::ERROR_INVALID_RELOC_TYPE ); - - switch( reloc.type ) - { - case uint32_t(RELOC_ABS_RAW): - //Raw data, do nothing - break; - case uint32_t(RELOC_ABS_REF): - //Reference, init later - refOffs.pushBack(reloc.off); - break; - default: - DEBUG_ALWAYS_ASSERT(); - return Serializer::ERROR_INVALID_INTERNAL_PTR; - } - - char *&ptr = *reinterpret_cast<char **>(start + reloc.off); - - size_t off = reinterpret_cast<size_t>(ptr); //size_t == uintptr_t - NV_BOOL_ERR_CHECK_RETURN( off < dataLen, Serializer::ERROR_INVALID_INTERNAL_PTR ); - - ptr = start + off; - } - - uint32_t *refCount = reinterpret_cast<uint32_t*>(&hdr.numObjects); - - //Init references (vtables and stuff) - for(uint32_t i = 0; i < refOffs.size(); ++i) - { - char *&p = *reinterpret_cast<char **>(start + refOffs[i]); - - const ObjHeader &objHdr = *reinterpret_cast<const ObjHeader *>(p); - - const char *className = objHdr.className; - NV_BOOL_ERR_CHECK_RETURN( className, Serializer::ERROR_INVALID_INTERNAL_PTR ); - - p += objHdr.dataOffset; - - if( !objHdr.isIncluded ) - { - Interface *obj = PX_PLACEMENT_NEW(p, NvParameters)(mTraits, start, reinterpret_cast<int32_t*>(refCount)); - PX_UNUSED(obj); - - //We do not want objHdr.verify() here - } - else - { - Interface *obj = mTraits->finishNvParameterized(className, objHdr.version, p, start, reinterpret_cast<int32_t*>(refCount)); - NV_BOOL_ERR_CHECK_RETURN( obj, Serializer::ERROR_OBJECT_CREATION_FAILED ); - NV_ERR_CHECK_RETURN( verifyObjectHeader(objHdr, obj, mTraits) ); - - if( objHdr.version != mTraits->getCurrentVersion(className) ) - doesNeedUpdate = true; - } //if( !objHdr.isIncluded ) - } //i - - // Table of root references - ObjectTableEntry *objectTable = reinterpret_cast<ObjectTableEntry *>(start + hdr.dataOffset); //At start of data section - - //Init results - res.init(mTraits, static_cast<uint32_t>(hdr.numObjects)); - for(uint32_t i = 0; i < static_cast<uint32_t>(hdr.numObjects); ++i) - res[i] = objectTable[i].obj; - - *refCount = refOffs.size(); //Release after all inplace references are destroyed - - // Conversion will be done after deserialization to avoid releasing inplace memory if all objects are destroyed - //(otherwise we may have data corruption) - - return Serializer::ERROR_NONE; -} - -Serializer::ErrorType BinSerializer::updateAllCounted2WithAlignment(BinaryHeader &hdr, char * /*start*/) -{ - hdr.version = BinVersions::WithAlignment; - hdr.alignment = 8; - return Serializer::ERROR_NONE; -} - -Serializer::ErrorType BinSerializer::updateInitial2AllCounted(BinaryHeader &hdr, char *start) -{ - // versionAllRefsCounted counts all references instead of just top-level references; - // to achieve this we simply set mDoDeallocateSelf to true in all references - - uint32_t nrelocs; - BinaryReloc *relocs = getRelocationTable(hdr, start, nrelocs); - - for(uint32_t i = 0; i < nrelocs; ++i) - { - BinaryReloc &reloc = relocs[i]; - - if( reloc.type != static_cast<uint32_t>(RELOC_ABS_REF) ) - continue; - - size_t targetOff = *reinterpret_cast<size_t *>(start + reloc.off); //size_t == uintptr_t - - const ObjHeader &objHdr = *reinterpret_cast<const ObjHeader *>(start + targetOff); - - targetOff += objHdr.dataOffset; //Points to start of NvParameters - -#if PX_PS4 == 1 -#pragma GCC diagnostic ignored "-Wunused-private-field" -#endif - // MyNvParameters has the same layout as NvParameters - class MyNvParameters - { - void *vtable; - void *mParameterizedTraits; - void *mSerializationCb; - void *mCbUserData; - void *mBuffer; - void *mRefCount; - void *mName; - void *mClassName; - bool mDoDeallocateSelf; - bool mDoDeallocateName; - bool mDoDeallocateClassName; - - public: - void setDoDeallocateSelf() { mDoDeallocateSelf = true; } - }; -#if PX_PS4 == 1 -#pragma GCC diagnostic warning "-Wunused-private-field" -#endif - MyNvParameters *pAsNvParameters = reinterpret_cast<MyNvParameters *>(start + targetOff); - pAsNvParameters->setDoDeallocateSelf(); - } - - hdr.version = BinVersions::AllRefsCounted; - - return Serializer::ERROR_NONE; -} - -Serializer::ErrorType BinSerializer::readArraySlow(Handle &handle, PlatformInputStream &s) -{ - int32_t n; - NV_PARAM_ERR_CHECK_RETURN( handle.getArraySize(n), Serializer::ERROR_INVALID_ARRAY ); - - for(int32_t i = 0; i < n; ++i) - { - handle.set(i); - NV_ERR_CHECK_RETURN( readBinaryData(handle, s) ); - handle.popIndex(); - } - - return Serializer::ERROR_NONE; -} - -static bool IsSimpleStruct(const Definition *pd) -{ - // Empty structs are special - if( 0 == pd->numChildren() ) - return false; - - for(int32_t i = 0; i < pd->numChildren(); ++i) - { - if (pd->child(i)->type() == TYPE_STRING || pd->child(i)->type() == TYPE_ENUM || pd->child(i)->type() == TYPE_ARRAY || - pd->child(i)->type() == TYPE_REF || pd->child(i)->type() == TYPE_STRUCT - ) - { - return false; - } - } - - return true; -} - -#ifndef WITHOUT_APEX_SERIALIZATION - -Serializer::ErrorType BinSerializer::internalSerialize(physx::PxFileBuf &stream, const Interface **objs, uint32_t nobjs, bool doMetadata) -{ - NV_BOOL_ERR_CHECK_WARN_RETURN( - PlatformABI::VerifyCurrentPlatform(), - Serializer::ERROR_INVALID_PLATFORM , - "Current platform is not supported, aborting" ); - - NV_BOOL_ERR_CHECK_RETURN( BinaryHeader::CheckAlignment(), Serializer::ERROR_INVALID_PLATFORM ); - - PlatformABI targetParams; - NV_ERR_CHECK_WARN_RETURN( PlatformABI::GetPredefinedABI(mPlatform, targetParams), "Unknown platform" ); - NV_BOOL_ERR_CHECK_WARN_RETURN( - targetParams.isNormal(), - Serializer::ERROR_INVALID_PLATFORM, - "Target platform is not supported, aborting" ); - - PlatformABI curParams; - NV_ERR_CHECK_WARN_RETURN( PlatformABI::GetPredefinedABI(GetCurrentPlatform(), curParams), "Unknown platform" ); - NV_BOOL_ERR_CHECK_RETURN( curParams.isNormal(), Serializer::ERROR_INVALID_PLATFORM ); - - Dictionary dict(mTraits); //Dictionary is updated in other routines - - // Compute object data - - typedef physx::shdfnd::Array<PlatformOutputStream, Traits::Allocator> StreamArray; - StreamArray dataStreams((Traits::Allocator(mTraits))); - dataStreams.reserve(nobjs); - for(uint32_t i = 0; i < nobjs; ++i) - { - Handle handle(*objs[i], ""); - NV_BOOL_ERR_CHECK_RETURN( handle.isValid(), Serializer::ERROR_UNKNOWN ); - - dataStreams.pushBack(PlatformOutputStream(targetParams, mTraits, dict)); - dataStreams.back().setAlignment(16); // 16 for safety - - NV_ERR_CHECK_WARN_RETURN( storeBinaryData(*objs[i], handle, dataStreams.back()), "Failed to serialize data for object %d", i ); - } - - // Compute metadata - - PlatformOutputStream metadataStream(targetParams, mTraits, dict); - metadataStream.setAlignment(16); // 16 for safety - uint32_t numMetadata = 0; - if( doMetadata ) - { - typedef physx::shdfnd::Pair<const char *, uint32_t> VersionedClass; - typedef physx::shdfnd::HashMap<VersionedClass, const Definition *, physx::shdfnd::Hash<VersionedClass>, Traits::Allocator> MapClass2Def; - MapClass2Def mapClass2Def((Traits::Allocator(mTraits))); - - //We track all classes that were saved to avoid duplicate metadata info - class MyRefCallback: public ReferenceInterface - { - MapClass2Def &mapClass2Def; - - //Silence warnings on unable to generate assignment operator - void operator =(MyRefCallback) {} - public: - MyRefCallback(MapClass2Def &mapClass2Def_): mapClass2Def(mapClass2Def_) {} - - void referenceCallback(Handle &handle) - { - Interface *iface; - handle.getParamRef(iface); - if( iface ) - mapClass2Def[ VersionedClass(iface->className(), iface->version()) ] = iface->rootParameterDefinition(); - } - } cb(mapClass2Def); - - for(uint32_t i = 0; i < nobjs; ++i) - { - if( !objs[i] ) - continue; - - mapClass2Def[ VersionedClass(objs[i]->className(), objs[i]->version()) ] = objs[i]->rootParameterDefinition(); - getReferences(*objs[i], cb, false, true, true); - } - - numMetadata = mapClass2Def.size(); - - for(MapClass2Def::Iterator i = mapClass2Def.getIterator(); !i.done(); ++i) - { - metadataStream.beginStruct(targetParams.getMetaEntryAlignment()); - - metadataStream.storeStringPtr(i->first.first); //className - metadataStream.storeSimple<uint32_t>(i->first.second); //classVersion - - //info - Reloc &reloc = metadataStream.storePtr(RELOC_ABS_RAW, targetParams.getMetaInfoAlignment()); - NV_ERR_CHECK_RETURN( storeMetadataInfo(i->second, *reloc.ptrData) ); - - metadataStream.closeStruct(); - } //i - } - - // Init header - - BinaryHeader hdr; - - hdr.magic = Magic; - hdr.type = BINARY_TYPE_PLAIN; - hdr.version = Version; - hdr.numObjects = static_cast<int32_t>(nobjs); - hdr.fileLength = 0; - hdr.dictOffset = 0; - hdr.dataOffset = 0; - hdr.relocOffset = 0; - hdr.metadataOffset = 0; - - hdr.archType = static_cast<uint32_t>(mPlatform.archType); - hdr.compilerType = static_cast<uint32_t>(mPlatform.compilerType); - hdr.compilerVer = mPlatform.compilerVer; - hdr.osType = static_cast<uint32_t>(mPlatform.osType); - hdr.osVer = mPlatform.osVer; - - hdr.numMetadata = numMetadata; - hdr.alignment = 0; - - BinaryHeaderExt ext; - memset(&ext, 0, sizeof(ext)); - memcpy(&ext.vcsSafetyFlags, VCS_SAFETY_FLAGS, 4); - - // Resulting stream - - PlatformOutputStream joinStream(targetParams, mTraits, dict); - - // Merge header - - joinStream.storeBytes(reinterpret_cast<const char *>(&hdr), sizeof(hdr)); - joinStream.storeBytes(reinterpret_cast<const char *>(&ext), sizeof(ext)); - joinStream.align(16); - - // Merge dictionary - - uint32_t dictOffset = joinStream.size(); - joinStream.mergeDict(); - - // Merge data - - uint32_t dataOffset = 0; - { - joinStream.align(joinStream.getTargetABI().aligns.pointer); - dataOffset = joinStream.size(); - - //Create object table - for(uint32_t i = 0; i < nobjs; ++i) - { - dataStreams[i].flatten(); - - Reloc &reloc = joinStream.storePtr(RELOC_ABS_REF, dataStreams[i].alignment()); - reloc.ptrData->merge(dataStreams[i]); - - //This was requested for faster peeking of contained assets - joinStream.storeStringPtr(objs[i]->className()); - joinStream.storeStringPtr(objs[i]->name()); - - //UE3 was once using this - joinStream.storeNullPtr(); - } - - joinStream.flatten(); //Merge all data-related pointers - } - - // Merge metadata - - uint32_t metadataOffset = 0; - if( doMetadata ) - { - metadataOffset = joinStream.merge(metadataStream); - joinStream.flatten(); //Merge all metadata-related pointers - } - - // Merge relocation data - - uint32_t relocOffset = joinStream.writeRelocs(); - - // Update offsets in header - - void *data = joinStream.getData(); - - BinaryHeader &hdrFinal = *reinterpret_cast<BinaryHeader *>(data); - hdrFinal.fileLength = joinStream.size(); - hdrFinal.dictOffset = dictOffset; - hdrFinal.dataOffset = dataOffset; - hdrFinal.metadataOffset = metadataOffset; - hdrFinal.relocOffset = relocOffset; - hdrFinal.alignment = joinStream.alignment(); - - BinaryHeaderExt &extFinal = *reinterpret_cast<BinaryHeaderExt *>((char *)data + sizeof(BinaryHeader)); - - //Make platform-independent - hdrFinal.canonize(); - extFinal.canonize(); - - // Write data to stream - - if( stream.tellWrite() % joinStream.alignment() ) - { - NV_PARAM_TRAITS_WARNING( - mTraits, - "Input stream is unaligned, " - "you will not be able to inplace deserialize it " - "without copying to intermediate buffer" - ); - } - - NV_BOOL_ERR_CHECK_RETURN( - joinStream.size() == stream.write(data, joinStream.size()), - Serializer::ERROR_STREAM_ERROR ); - - return Serializer::ERROR_NONE; -} - -Serializer::ErrorType BinSerializer::storeMetadataInfo(const Definition *def, PlatformOutputStream &s) -{ - s.beginStruct(s.getTargetABI().getMetaInfoAlignment()); - - //type - s.storeSimple((uint32_t)def->type()); - - //arraySize - s.storeSimple(TYPE_ARRAY == def->type() ? (int32_t)def->arraySize() : -1); - - //shortName - s.storeStringPtr(def->name()); - - //structName - s.storeStringPtr(def->structName()); - - //alignment - s.storeSimple(def->alignment()); - - //padding - s.storeSimple(def->padding()); - - //numChildren - s.storeSimple(def->numChildren()); - - //children - for(int32_t i = 0; i < def->numChildren(); ++i) - { - Reloc &childrenReloc = s.storePtr(RELOC_ABS_RAW, s.getTargetABI().getMetaInfoAlignment()); - NV_ERR_CHECK_RETURN( storeMetadataInfo(def->child(i), *childrenReloc.ptrData) ); - } - - //numHints - s.storeSimple(def->numHints()); - - //hints - for(int32_t i = 0; i < def->numHints(); ++i) - { - const Hint *hint = def->hint(i); - - s.beginStruct(s.getTargetABI().getHintAlignment()); - - s.storeSimple((uint32_t)hint->type()); - s.storeStringPtr(hint->name()); - - s.beginStruct(s.getTargetABI().getHintValueAlignment()); - switch( hint->type() ) - { - case TYPE_U64: - s.storeSimple(hint->asUInt()); - break; - case TYPE_F64: - s.storeSimple(hint->asFloat()); - break; - case TYPE_STRING: - s.storeStringPtr(hint->asString()); - break; - -NV_PARAMETRIZED_LINAL_DATATYPE_LABELS -NV_PARAMETRIZED_REF_DATATYPE_LABELS -NV_PARAMETRIZED_ENUM_DATATYPE_LABELS -NV_PARAMETRIZED_SERVICE_DATATYPE_LABELS -NV_PARAMETRIZED_UNDEFINED_AND_LAST_DATATYPE_LABELS -NV_PARAMETRIZED_AGGREGATE_DATATYPE_LABELS - case TYPE_F32: - case TYPE_U32: case TYPE_U16: case TYPE_U8: - case TYPE_I64: case TYPE_I32: case TYPE_I16: case TYPE_I8: case TYPE_BOOL: - default: - DEBUG_ALWAYS_ASSERT(); - return Serializer::ERROR_INVALID_DATA_TYPE; - } - s.align(s.getTargetABI().getHintValueSize()); - s.closeStruct(); - - s.closeStruct(); - } - - //numEnumVals - s.storeSimple(def->numEnumVals()); - - //enumVals - for(int32_t i = 0; i < def->numEnumVals(); ++i) - s.storeStringPtr(def->enumVal(i)); - - //numRefVariantVals - s.storeSimple(def->numRefVariants()); - - //refVariants - for(int32_t i = 0; i < def->numRefVariants(); ++i) - s.storeStringPtr(def->refVariantVal(i)); - - s.closeStruct(); - - return Serializer::ERROR_NONE; -} - -//Store array of arbitrary type (slow version) -Serializer::ErrorType BinSerializer::storeArraySlow(Handle &handle, PlatformOutputStream &s) -{ - int32_t size; - NV_PARAM_ERR_CHECK_RETURN( handle.getArraySize(size), Serializer::ERROR_INVALID_ARRAY ); - - const Interface &obj = *handle.getConstInterface(); - for(int32_t i = 0; i < size; ++i) - { - handle.set(i); - NV_ERR_CHECK_RETURN( storeBinaryData(obj, handle, s) ); - handle.popIndex(); - } - - return Serializer::ERROR_NONE; -} - -//Print binary data for part of NvParameterized object addressed by handle -Serializer::ErrorType BinSerializer::storeBinaryData(const Interface &obj, Handle &handle, PlatformOutputStream &res, bool isRootObject) -{ - bool isObject = !handle.numIndexes(); - - if( isObject ) - res.storeObjHeader(obj); - - const Definition *pd = handle.parameterDefinition(); - - bool doNotSerialize = 0 != pd->hint("DONOTSERIALIZE"), - isDynamicArray = pd->type() == TYPE_ARRAY && !pd->arraySizeIsFixed(); - - // Alignment in dynamic array means alignment of dynamic memory - // so we do not insert it here - if( pd->alignment() && !isDynamicArray ) - res.align(pd->alignment()); - - //Dynamic arrays are special because we need some of their fields for correct inplace deserialization - if( doNotSerialize && !isDynamicArray ) - { - //Simply skip bytes - res.align(res.getTargetAlignment(pd)); - res.skipBytes(res.getTargetSize(pd)); - - return Serializer::ERROR_NONE; - } - - switch( pd->type() ) - { - case TYPE_ARRAY: - { - if( pd->arraySizeIsFixed() ) - { - res.beginArray(pd); - storeArraySlow(handle, res); - res.closeArray(); - } - else - { - res.beginStruct(pd); //Dynamic arrays are implemented as structs - - bool isEmpty = false; - if( doNotSerialize ) - isEmpty = true; - else - { - for(int32_t i = 0; i < pd->arrayDimension(); ++i) - { - int32_t size = 0; - NV_PARAM_ERR_CHECK_RETURN( handle.getArraySize(size, i), Serializer::ERROR_INVALID_ARRAY ); - - if( 0 == size ) - { - isEmpty = true; - break; - } - } - } - - const Definition *elemPd = pd; - for(int32_t i = 0; i < pd->arrayDimension(); ++i) - elemPd = elemPd->child(0); - - //Pointer-to-data - Reloc *reloc = 0; - if( isEmpty ) - res.storeNullPtr(); - else - { - reloc = &res.storePtr(RELOC_ABS_RAW, elemPd); - if( pd->alignment() ) - reloc->ptrData->setAlignment(physx::PxMax(reloc->ptrData->alignment(), pd->alignment())); - } - - //isAllocated - res.storeSimple(false); - - //elementSize - res.storeSimple<uint32_t>(res.getTargetSize(elemPd)); - - //arraySizes - const Definition *subArrayPd = pd; - res.beginArray(res.getTargetABI().getAlignment<int32_t>()); - for(int32_t dim = 0; dim < pd->arrayDimension(); ++dim) - { - // Store size of static dimensions even if doNotSerialize is on - int32_t size = 0; - if( !doNotSerialize || subArrayPd->arraySizeIsFixed() ) - NV_PARAM_ERR_CHECK_RETURN( handle.getArraySize(size, dim), Serializer::ERROR_INVALID_ARRAY ); - - res.storeSimple(size); - - NV_BOOL_ERR_CHECK_RETURN( 1 == subArrayPd->numChildren(), Serializer::ERROR_UNKNOWN ); - subArrayPd = subArrayPd->child(0); - } - res.closeArray(); - - //Data - if( !isEmpty ) - { - reloc->ptrData->beginArray(elemPd); - - int32_t size = -1; - NV_PARAM_ERR_CHECK_RETURN( handle.getArraySize(size), Serializer::ERROR_INVALID_ARRAY ); - - const Definition *child = pd->child(0); - switch( child->type() ) - { -# define NV_PARAMETERIZED_TYPES_NO_LEGACY_TYPES -# define NV_PARAMETERIZED_TYPES_ONLY_SIMPLE_TYPES -# define NV_PARAMETERIZED_TYPES_NO_STRING_TYPES -# define NV_PARAMETERIZED_TYPE(type_name, enum_name, c_type) \ - case TYPE_##enum_name: \ - { \ - reloc->ptrData->storeSimpleArray<c_type>(handle); \ - break; \ - } -# include "nvparameterized/NvParameterized_types.h" - - case TYPE_STRUCT: - if( IsSimpleStruct(child) ) - { - //Fast path for simple structs - reloc->ptrData->storeSimpleStructArray(handle); - break; - } - - //Else fall through to default, includes TYPE_MAT34 case -NV_PARAMETRIZED_UNDEFINED_AND_LAST_DATATYPE_LABELS -NV_PARAMETRIZED_LEGACY_DATATYPE_LABELS -NV_PARAMETRIZED_STRING_DATATYPE_LABELS -NV_PARAMETRIZED_REF_DATATYPE_LABELS -NV_PARAMETRIZED_ENUM_DATATYPE_LABELS -NV_PARAMETRIZED_SERVICE_DATATYPE_LABELS - case TYPE_ARRAY: - default: - storeArraySlow(handle, *reloc->ptrData); - break; - } - - reloc->ptrData->closeArray(); - } - - res.closeStruct(); - } - break; - } - - case TYPE_STRUCT: - { - uint32_t oldSize = isObject ? res.beginObject(obj, isRootObject, pd) : res.beginStruct(pd); - - for(int32_t i = 0; i < pd->numChildren(); ++i) - { - handle.set(i); - NV_ERR_CHECK_RETURN( storeBinaryData(obj, handle, res) ); - handle.popIndex(); - } - - //Empty structs are at least 1 char long - if( res.size() == oldSize ) - res.storeSimple((uint8_t)0); - - if( isObject ) - res.closeObject(); - else - res.closeStruct(); - - break; - } - - case TYPE_STRING: - { - const char *s = 0; - handle.getParamString(s); - - res.beginString(); - - //buf - res.storeStringPtr(s); - - //isAllocated - res.storeSimple(false); - - res.closeString(); - - break; - } - - case TYPE_ENUM: - { - const char *s = 0; - handle.getParamEnum(s); - - res.storeStringPtr(s); - - break; - } - - case TYPE_REF: - { - Interface *refObj = 0; - handle.getParamRef(refObj); - - if( !refObj ) - res.storeNullPtr(); - else if( pd->isIncludedRef() ) - { - Handle refHandle(*refObj, ""); - NV_BOOL_ERR_CHECK_RETURN( refHandle.isValid(), Serializer::ERROR_UNKNOWN ); - - Reloc &reloc = res.storePtr(RELOC_ABS_REF, 16); //16 for safety - NV_ERR_CHECK_RETURN( storeBinaryData(*refObj, refHandle, *reloc.ptrData, false) ); - } - else //Named reference - { - Reloc &reloc = res.storePtr(RELOC_ABS_REF, 16); //16 for safety - reloc.ptrData->storeObjHeader(*refObj, false); - reloc.ptrData->beginObject(*refObj, false, 0); - reloc.ptrData->closeObject(); //Named references are instances of NvParameters => no additional fields - } - - break; - } - - case TYPE_POINTER: - { - res.storeNullPtr(); - break; - } - - -# define NV_PARAMETERIZED_TYPES_NO_LEGACY_TYPES -# define NV_PARAMETERIZED_TYPES_ONLY_SIMPLE_TYPES -# define NV_PARAMETERIZED_TYPES_NO_STRING_TYPES -# define NV_PARAMETERIZED_TYPE(type_name, enum_name, c_type) \ - case TYPE_##enum_name: \ - { \ - c_type val; \ - NV_PARAM_ERR_CHECK_RETURN( handle.getParam##type_name(val), Serializer::ERROR_INVALID_VALUE ); \ - res.storeSimple<c_type>(val); \ - break; \ - } -# include "nvparameterized/NvParameterized_types.h" - - case TYPE_MAT34: - { - float val[12]; - NV_PARAM_ERR_CHECK_RETURN( handle.getParamMat34Legacy(val), Serializer::ERROR_INVALID_VALUE ); - res.storeSimple(val, 12); - break; - } - -NV_PARAMETRIZED_UNDEFINED_AND_LAST_DATATYPE_LABELS - default: - DEBUG_ASSERT(0 && "Unknown type"); - return Serializer::ERROR_INVALID_DATA_TYPE; - } - - return Serializer::ERROR_NONE; -} - -#endif - -//Read NvParameterized object data -Serializer::ErrorType BinSerializer::readObject(Interface *&obj, PlatformInputStream &data) -{ - ObjHeader objHdr; - NV_ERR_CHECK_WARN_RETURN( data.readObjHeader(objHdr), "Failed to deserialize object header" ); - Releaser releaseClassName((void *)objHdr.className, mTraits), - releaseName((void *)objHdr.name, mTraits), - releaseChecksum((void *)objHdr.checksum, mTraits); - - if( !objHdr.isIncluded ) - { - void *buf = mTraits->alloc(sizeof(NvParameters)); - NV_BOOL_ERR_CHECK_RETURN( buf, Serializer::ERROR_MEMORY_ALLOCATION_FAILURE ); - - obj = PX_PLACEMENT_NEW(buf, NvParameters)(mTraits); - obj->setClassName(objHdr.className); - - if( objHdr.name ) - obj->setName(objHdr.name); - - //We do not want objHdr.verify() here - } - else - { - NV_BOOL_ERR_CHECK_RETURN( objHdr.className, Serializer::ERROR_OBJECT_CREATION_FAILED ); - - obj = mTraits->createNvParameterized(objHdr.className, objHdr.version); - NV_BOOL_ERR_CHECK_RETURN( obj, Serializer::ERROR_OBJECT_CREATION_FAILED ); - - if( objHdr.name ) - obj->setName(objHdr.name); - - NV_ERR_CHECK_RETURN( verifyObjectHeader(objHdr, obj, mTraits) ); - - Handle handle(*obj, ""); - NV_BOOL_ERR_CHECK_RETURN( handle.isValid(), Serializer::ERROR_UNKNOWN ); - - NV_ERR_CHECK_RETURN( data.pushPos(objHdr.dataOffset) ); - NV_ERR_CHECK_RETURN( readBinaryData(handle, data) ); - data.popPos(); - } - - return Serializer::ERROR_NONE; -} - -//Read binary data of NvParameterized object addressed by handle -Serializer::ErrorType BinSerializer::readBinaryData(Handle &handle, PlatformInputStream &data) -{ - const Definition *pd = handle.parameterDefinition(); - - bool isDynamicArray = TYPE_ARRAY == pd->type() && !pd->arraySizeIsFixed(); - - // See comment in storeBinaryData - if( pd->alignment() && !isDynamicArray ) - data.align(pd->alignment()); - - if( pd->hint("DONOTSERIALIZE") ) - { - //Simply skip DONOTSERIALIZE - data.align(data.getTargetAlignment(pd)); - NV_ERR_CHECK_RETURN( data.skipBytes(data.getTargetSize(pd)) ); - return Serializer::ERROR_NONE; - } - - switch( pd->type() ) - { - case TYPE_ARRAY: - { - if( pd->arraySizeIsFixed() ) - { - data.beginArray(pd); - for(int32_t i = 0; i < pd->arraySize(); ++i) - { - handle.set(i); - NV_ERR_CHECK_RETURN( readBinaryData(handle, data) ); - handle.popIndex(); - } - data.closeArray(); - } - else - { - data.beginStruct(pd); //Dynamic arrays are implemented as structs - - uint32_t elemOff; - NV_ERR_CHECK_RETURN( data.readPtr(elemOff) ); - - bool isAllocated; - NV_ERR_CHECK_RETURN( data.read(isAllocated) ); - - int32_t elementSize; - NV_ERR_CHECK_RETURN( data.read(elementSize) ); //elementSize - - data.beginStruct(data.getTargetABI().aligns.i32); //Start array of sizes - - int32_t arraySize; - NV_ERR_CHECK_RETURN( data.read(arraySize) ); //We need only the first size - - const Definition *subArrayPd = pd->child(0); - for(int32_t dim = 1; dim < pd->arrayDimension(); ++dim) - { - int32_t size; - NV_ERR_CHECK_RETURN( data.read(size) ); - - // We do not support nested dynamic arrays - if( subArrayPd->arraySizeIsFixed() ) - NV_BOOL_ERR_CHECK_RETURN( size == subArrayPd->arraySize(), Serializer::ERROR_INVALID_ARRAY ); - - subArrayPd = subArrayPd->child(0); - } - data.closeStruct(); //End array of sizes - - NV_PARAM_ERR_CHECK_RETURN( handle.resizeArray(arraySize), Serializer::ERROR_INVALID_ARRAY ); - - if( elemOff ) - { - // Check alignment - uint32_t align = pd->alignment(); - if( align && elemOff % align ) { - char longName[256]; - handle.getLongName(longName, sizeof(longName)); - NV_PARAM_TRAITS_WARNING( - mTraits, - "%s: array is unaligned, " - "you will not be able to inplace deserialize it " - "without copying to intermediate buffer.", - longName - ); - } - - NV_ERR_CHECK_RETURN( data.pushPos(elemOff) ); - - switch( pd->child(0)->type() ) - { -# define NV_PARAMETERIZED_TYPES_NO_LEGACY_TYPES -# define NV_PARAMETERIZED_TYPES_ONLY_SIMPLE_TYPES -# define NV_PARAMETERIZED_TYPES_NO_STRING_TYPES -# define NV_PARAMETERIZED_TYPE(type_name, enum_name, c_type) \ - case TYPE_##enum_name: \ - { \ - NV_ERR_CHECK_RETURN( data.readSimpleArray<c_type>(handle) ); \ - break; \ - } -# include "nvparameterized/NvParameterized_types.h" - - case TYPE_STRUCT: - { - const Definition *child = pd->child(0); - if( IsSimpleStruct(child) ) - { - //Fast path for simple structs - NV_ERR_CHECK_RETURN( data.readSimpleStructArray(handle) ); - break; - } - - //Else fall through to default, including TYPE_MAT34 case - } - -NV_PARAMETRIZED_UNDEFINED_AND_LAST_DATATYPE_LABELS -NV_PARAMETRIZED_LEGACY_DATATYPE_LABELS -NV_PARAMETRIZED_STRING_DATATYPE_LABELS -NV_PARAMETRIZED_REF_DATATYPE_LABELS -NV_PARAMETRIZED_ENUM_DATATYPE_LABELS -NV_PARAMETRIZED_SERVICE_DATATYPE_LABELS -case TYPE_ARRAY: - default: - NV_ERR_CHECK_RETURN( readArraySlow(handle, data) ); - break; - } - - data.popPos(); - } - - data.closeStruct(); - } - break; - } - - case TYPE_STRUCT: - { - uint32_t oldPos = data.getPos(); - - data.beginStruct(pd); - for(int32_t i = 0; i < pd->numChildren(); ++i) - { - handle.set(i); - NV_ERR_CHECK_RETURN( readBinaryData(handle, data) ); - handle.popIndex(); - } - - //Empty structs are at least 1 char long - if( data.getPos() == oldPos ) - { - uint8_t tmp; - NV_ERR_CHECK_RETURN( data.read(tmp) ); - } - - data.closeStruct(); - - break; - } - - case TYPE_STRING: - { - data.beginString(); - - uint32_t off; - NV_ERR_CHECK_RETURN( data.readPtr(off) ); - - const char *s; - NV_ERR_CHECK_RETURN( data.readString(off, s) ); - - NV_PARAM_ERR_CHECK_RETURN( handle.setParamString(s), Serializer::ERROR_INVALID_VALUE ); - mTraits->free((char *)s); - - bool isAllocated; - NV_ERR_CHECK_RETURN( data.read(isAllocated) ); - - data.closeString(); - - break; - } - - case TYPE_ENUM: - { - uint32_t off; - NV_ERR_CHECK_RETURN( data.readPtr(off) ); - - const char *s; - NV_ERR_CHECK_RETURN( data.readString(off, s) ); - - NV_BOOL_ERR_CHECK_RETURN( s, Serializer::ERROR_INVALID_VALUE ); - NV_PARAM_ERR_CHECK_RETURN( handle.setParamEnum(s), Serializer::ERROR_INVALID_VALUE ); - - mTraits->free((char *)s); - - break; - } - - case TYPE_REF: - { - uint32_t objPos; - NV_ERR_CHECK_RETURN( data.readPtr(objPos) ); - - Interface *refObj = 0; - - if( objPos ) - { - NV_ERR_CHECK_RETURN( data.pushPos(objPos) ); - NV_ERR_CHECK_RETURN( readObject(refObj, data) ); - data.popPos(); - } - - if( refObj && (-1 == handle.parameterDefinition()->refVariantValIndex(refObj->className())) ) - { - char longName[256]; - handle.getLongName(longName, sizeof(longName)); - NV_PARAM_TRAITS_WARNING( - mTraits, - "%s: setting reference of invalid class %s", - longName, - refObj->className() - ); - } - - NV_PARAM_ERR_CHECK_RETURN( handle.setParamRef(refObj), Serializer::ERROR_INVALID_REFERENCE ); - - break; - } - - case TYPE_POINTER: - { - void *tmp; - NV_ERR_CHECK_RETURN( data.read(tmp) ); - break; - } - - -# define NV_PARAMETERIZED_TYPES_NO_LEGACY_TYPES -# define NV_PARAMETERIZED_TYPES_ONLY_SIMPLE_TYPES -# define NV_PARAMETERIZED_TYPES_NO_STRING_TYPES -# define NV_PARAMETERIZED_TYPE(type_name, enum_name, c_type) \ - case TYPE_##enum_name: \ - { \ - c_type val; \ - NV_ERR_CHECK_RETURN(data.read(val)); \ - NV_PARAM_ERR_CHECK_RETURN( handle.setParam##type_name(val), Serializer::ERROR_INVALID_VALUE ); \ - break; \ - } -# include "nvparameterized/NvParameterized_types.h" - - case TYPE_MAT34: - { - float val[12]; - for (int k = 0; k < 12; ++k) - { - NV_ERR_CHECK_RETURN(data.read(val[k])); - } - NV_PARAM_ERR_CHECK_RETURN( handle.setParamMat34Legacy(val), Serializer::ERROR_INVALID_VALUE ); - break; - } - -NV_PARAMETRIZED_UNDEFINED_AND_LAST_DATATYPE_LABELS - default: - DEBUG_ASSERT(0 && "Unknown type"); - return Serializer::ERROR_INVALID_DATA_TYPE; - } - - return Serializer::ERROR_NONE; -} - -bool isBinaryFormat(physx::PxFileBuf &stream) -{ - uint32_t magic; - stream.peek(&magic, 4); - return Canonize(magic) == BinSerializer::Magic; -} - -Serializer::ErrorType peekBinaryPlatform(physx::PxFileBuf &stream, SerializePlatform &platform) -{ - BinaryHeader hdr; - BinaryHeaderExt ext; - NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext) ); - NV_ERR_CHECK_RETURN( hdr.getPlatform(platform) ); - return Serializer::ERROR_NONE; -} - -} // namespace NvParameterized +// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved.
+
+/*
+ Binary serialization is very complex and error-prone
+ process. Ensuring that it works properly is _critically_
+ important for the engine.
+
+ Before you do any significant changes to this code
+ please get familiar with C/C++ object layouts.
+ You may find these links helpful:
+
+ * APEX binary file format
+ https://wiki.nvidia.com/engwiki/index.php/PhysX/APEX/architecture/design/File_Formats
+ (may not be up-to-date)
+
+ * C++ data alignment and portability
+ http://www.codesynthesis.com/~boris/blog/2009/04/06/cxx-data-alignment-portability/
+
+ * Data structure alignment
+ http://en.wikipedia.org/wiki/Data_structure_alignment
+
+ * About Data Alignment
+ http://msdn.microsoft.com/en-us/library/ms253949%28v=VS.80%29.aspx
+
+ * Types and Storage
+ http://msdn.microsoft.com/en-us/library/02c56cw3.aspx
+
+ * Jan Gray's article in "C++: Under the Hood"
+ http://www.openrce.org/articles/files/jangrayhood.pdf
+
+ * Windows Data Alignment on IPF, x86, and x64
+ http://msdn.microsoft.com/en-us/library/aa290049%28VS.71%29.aspx
+
+ * GCC alignment in classes gotcha
+ https://ps3.scedev.net/forums/thread/41593/
+
+ * all messages in thread http://compilers.iecc.com/comparch/article/94-08-119
+
+ * Memory Layout for Multiple and Virtual Inheritance
+ http://www.phpcompiler.org/articles/virtualinheritance.html
+
+ * The "Empty Member" C++ Optimization
+ http://www.cantrip.org/emptyopt.html
+
+ You may also want to see examples of existing ABI
+ for various platforms:
+
+ * Agner Fog's Calling conventions for different C++ compilers
+ and operating systems,
+ http://www.agner.org/optimize/calling_conventions.pdf
+
+ * Itanium C++ ABI Data Layout
+ http://www.codesourcery.com/public/cxx-abi/abi.html#layout
+
+ * Introduction to Mac OS X ABI Function Call Guide
+ http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/000-Introduction/introduction.html
+
+ After you implement you changes be sure to check that ALL
+ NvParameterized unit tests
+ * Test/MediaTest
+ * Test/RandomClasses
+ * Test/ParamRandomTest
+ run without errors on ALL supported platforms:
+ * Win32
+ * Win64
+ * PS3
+ * XBOX 360
+ (in future we may also have Mac, Tegra, Linux on PC, etc.).
+
+ If you need to add new platform to this list, be sure to
+ analyze it's ABI with ABIDumper
+ (//sw/nvidia/shared/general/ABIDumper) and check whether
+ it requires special changes in current serialization code
+ (Mac does).
+
+ If you ever implement new features be sure to cover them
+ in random schema generator
+ NvParameterized/scripts/RandomSchema.pl, generate a bunch
+ (10 at least) of new random schemas for Test/RandomClasses
+ and add them to p4 (and verify that they work on all
+ platforms!).
+*/
+
+#include <PxSimpleTypes.h>
+
+#include "PsArray.h"
+#include "PsHash.h"
+#include "PsHashMap.h"
+
+#include "NvParameters.h"
+#include "nvparameterized/NvParamUtils.h"
+#include "NvTraitsInternal.h"
+
+#include "BinaryHelper.h"
+
+#include "PlatformABI.h"
+#include "PlatformInputStream.h"
+#include "PlatformOutputStream.h"
+
+#include "BinSerializer.h"
+
+namespace NvParameterized
+{
+
+// Verify that file header is ok
+Serializer::ErrorType BinSerializer::verifyFileHeader(
+ const BinaryHeader &hdr,
+ const BinaryHeaderExt *ext,
+ uint32_t dataLen ) const
+{
+ NV_BOOL_ERR_CHECK_WARN_RETURN( BinSerializer::Magic == hdr.magic, Serializer::ERROR_INVALID_MAGIC, "Invalid APB file: magic number does not match: %x", hdr.magic );
+ NV_BOOL_ERR_CHECK_WARN_RETURN( (uint32_t)BINARY_TYPE_PLAIN == hdr.type, Serializer::ERROR_INVALID_FILE_FORMAT, "Invalid APB file: unknown file format: %d", hdr.type );
+
+ NV_BOOL_ERR_CHECK_WARN_RETURN(
+ BinVersions::WithExtendedHeader == hdr.version || BinVersions::WithAlignment == hdr.version,
+ Serializer::ERROR_INVALID_FILE_VERSION, "Invalid APB header: unexpected version: %x", hdr.version );
+
+ // Verify offsets
+ NV_BOOL_ERR_CHECK_WARN_RETURN( hdr.fileLength <= dataLen
+ && hdr.dataOffset < hdr.fileLength
+ && hdr.relocOffset < hdr.fileLength
+ && hdr.dictOffset < hdr.fileLength
+ && hdr.metadataOffset < hdr.fileLength,
+ Serializer::ERROR_INVALID_INTERNAL_PTR,
+ "Invalid APB file: section offsets do not match file length" );
+
+ if( ext )
+ {
+ NV_BOOL_ERR_CHECK_WARN_RETURN(
+ 0 == memcmp((const char *)&ext->vcsSafetyFlags, VCS_SAFETY_FLAGS, 4),
+ Serializer::ERROR_INVALID_CHAR,
+ "Invalid APB file: perhaps your editor inserts redundant carriage returns?"
+ );
+ }
+
+ return Serializer::ERROR_NONE;
+}
+
+// Peeks APB header from stream
+static Serializer::ErrorType peekFileHeader(physx::PxFileBuf &stream, BinaryHeader &hdr, BinaryHeaderExt &ext, bool doDecanonize = true)
+{
+ NV_BOOL_ERR_CHECK_RETURN(
+ sizeof(BinaryHeader) == stream.peek(&hdr, sizeof(BinaryHeader)),
+ Serializer::ERROR_INVALID_FILE_FORMAT );
+
+ if( hdr.version >= BinVersions::WithExtendedHeader )
+ {
+ uint32_t fileOff = stream.tellRead();
+
+ stream.seekRead(fileOff + sizeof(BinaryHeader));
+ NV_BOOL_ERR_CHECK_RETURN(
+ sizeof(BinaryHeaderExt) == stream.peek(&ext, sizeof(BinaryHeaderExt)),
+ Serializer::ERROR_INVALID_FILE_FORMAT );
+
+ stream.seekRead(fileOff);
+ }
+
+ if( doDecanonize )
+ hdr.decanonize();
+
+ return Serializer::ERROR_NONE;
+}
+
+// Extract platform ABI from file header
+Serializer::ErrorType BinSerializer::getPlatformInfo(
+ BinaryHeader &hdr,
+ BinaryHeaderExt *ext,
+ PlatformABI &abi ) const
+{
+ //Difference between these versions is not important for non-inplace serializer
+ if( hdr.version == BinVersions::Initial || hdr.version == BinVersions::AllRefsCounted )
+ hdr.version = BinVersions::WithAlignment;
+
+ NV_ERR_CHECK_RETURN( verifyFileHeader(hdr, ext, hdr.fileLength) );
+
+ SerializePlatform platform;
+ NV_ERR_CHECK_WARN_RETURN(hdr.getPlatform(platform), "Invalid platform");
+
+ NV_ERR_CHECK_WARN_RETURN( PlatformABI::GetPredefinedABI(platform, abi), "Unknown platform" );
+
+ return Serializer::ERROR_NONE;
+}
+
+Serializer::ErrorType BinSerializer::peekInplaceAlignment(physx::PxFileBuf& stream, uint32_t& align)
+{
+ BinaryHeader hdr;
+ BinaryHeaderExt ext;
+ NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext, false) );
+ align = Canonize(hdr.alignment);
+ return Serializer::ERROR_NONE;
+}
+
+// Verify that object matches its header
+Serializer::ErrorType BinSerializer::verifyObjectHeader(const ObjHeader &hdr, const Interface *obj, Traits *traits) const
+{
+ DEBUG_ASSERT(obj);
+ NV_BOOL_ERR_CHECK_WARN_RETURN(
+ obj->version() == hdr.version,
+ Serializer::ERROR_UNKNOWN,
+ "Invalid object: version does not match object header" );
+
+ PX_UNUSED(traits);
+
+ uint32_t bits = UINT32_MAX;
+ const uint32_t *checksum = obj->checksum(bits);
+
+ if( !DoIgnoreChecksum(*obj) || hdr.version != obj->version() )
+ {
+ if( bits != 32 * hdr.checksumSize )
+ NV_PARAM_TRAITS_WARNING(
+ traits,
+ "Schema checksum is different for object of class %s and version %u, asset may be corrupted",
+ hdr.className, (unsigned)hdr.version
+ );
+ else
+ {
+ for(uint32_t i = 0; i < hdr.checksumSize; ++i)
+ if( checksum[i] != hdr.checksum[i] )
+ {
+ NV_PARAM_TRAITS_WARNING(
+ traits,
+ "Schema checksum is different for object of class %s and version %u, asset may be corrupted",
+ hdr.className, (unsigned)hdr.version
+ );
+ break;
+ }
+ }
+ }
+
+ return Serializer::ERROR_NONE;
+}
+
+#if 0
+//TODO: this is just for tests, remove it after metadata works
+static void DumpDefinition(const Definition *def, const char *className, uint32_t version, uint32_t off = 0)
+{
+ char *tab = (char *)::malloc(off + 1);
+ memset(tab, ' ', off);
+ tab[off] = 0;
+
+ if( className )
+ printf("%sClass %s:%d\n", tab, className, version);
+
+ printf("%sDefinition at 0x%p:\n", tab, def);
+ printf("%s name = %s\n", tab, def->name());
+ printf("%s type = %s\n", tab, typeToStr(def->type()));
+ printf("%s align = %d\n", tab, def->alignment());
+ printf("%s pad = %d\n", tab, def->padding());
+
+ printf("%s %d hints:\n", tab, def->numHints());
+ for(uint32_t i = 0; i < def->numHints(); ++i)
+ {
+ const Hint *hint = def->hint(i);
+
+ printf("%s %s => ", tab, hint->name());
+ switch( hint->type() )
+ {
+ case TYPE_U64:
+ printf("%llu", hint->asUInt());
+ break;
+ case TYPE_F64:
+ printf("%f", hint->asFloat());
+ break;
+ case TYPE_STRING:
+ printf("\"%s\"", hint->asString());
+ break;
+ default:
+ DEBUG_ALWAYS_ASSERT();
+ }
+ printf("\n");
+ }
+
+ printf("%s %d enums: ", tab, def->numEnumVals());
+ for(uint32_t i = 0; i < def->numEnumVals(); ++i)
+ printf("\"%s\", ", def->enumVal(i));
+ printf("\n");
+
+ printf("%s %d refVariants: ", tab, def->numRefVariants());
+ for(uint32_t i = 0; i < def->numRefVariants(); ++i)
+ printf("\"%s\", ", def->refVariantVal(i));
+ printf("\n");
+
+ printf("%s %d children:\n", tab, def->numChildren());
+ for(uint32_t i = 0; i < def->numChildren(); ++i)
+ {
+ printf("%sChild %d:\n", tab, i);
+ DumpDefinition(def->child(i), 0, 0, off + 1);
+ }
+
+ ::free(tab);
+
+ fflush(stdout);
+}
+#endif
+
+Serializer::ErrorType BinSerializer::peekNumObjects(physx::PxFileBuf &stream, uint32_t &numObjects)
+{
+ BinaryHeader hdr;
+ BinaryHeaderExt ext;
+ NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext, false) );
+
+ return peekNumObjectsInplace((const void *)&hdr, sizeof(hdr), numObjects);
+}
+
+Serializer::ErrorType BinSerializer::peekNumObjectsInplace(const void *data, uint32_t dataLen, uint32_t &numObjects)
+{
+ NV_BOOL_ERR_CHECK_RETURN( dataLen >= sizeof(BinaryHeader), Serializer::ERROR_INVALID_FILE_FORMAT );
+ numObjects = static_cast<uint32_t>(Canonize( ((const BinaryHeader *)data)->numObjects));
+ return Serializer::ERROR_NONE;
+}
+
+Serializer::ErrorType BinSerializer::peekClassNames(physx::PxFileBuf &stream, char **classNames, uint32_t &numClassNames)
+{
+ BinaryHeader hdr;
+ BinaryHeaderExt ext;
+ NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext) );
+
+ PlatformABI targetParams;
+ NV_ERR_CHECK_RETURN(getPlatformInfo(
+ hdr,
+ hdr.version >= BinVersions::WithExtendedHeader ? &ext : 0,
+ targetParams
+ ));
+
+ PlatformInputStream objectTable(stream, targetParams, mTraits);
+ objectTable.skipBytes(hdr.dataOffset);
+
+ numClassNames = physx::PxMin(numClassNames, (uint32_t)hdr.numObjects);
+ for(uint32_t i = 0; i < numClassNames; ++i)
+ {
+ uint32_t tmp;
+ NV_ERR_CHECK_RETURN( objectTable.readPtr(tmp) ); // Pointer to object data
+
+ uint32_t classNameOff;
+ NV_ERR_CHECK_RETURN( objectTable.readPtr(classNameOff) ); // Pointer to className
+
+ const char *className;
+ NV_ERR_CHECK_RETURN( objectTable.readString(classNameOff, className) );
+ classNames[i] = mTraits->strdup(className); //User will call Traits::strfree
+ mTraits->free((void *)className);
+
+ NV_ERR_CHECK_RETURN( objectTable.readPtr(tmp) ); // Pointer to name
+ NV_ERR_CHECK_RETURN( objectTable.readPtr(tmp) ); // Pointer to filename
+ }
+
+ return Serializer::ERROR_NONE;
+}
+
+Serializer::ErrorType BinSerializer::readMetadataInfo(const BinaryHeader &hdr, PlatformInputStream &s, DefinitionImpl *def)
+{
+ PX_PLACEMENT_NEW(def, DefinitionImpl)(*mTraits, false);
+
+ s.beginStruct(s.getTargetABI().getMetaInfoAlignment());
+
+ //type
+ uint32_t type;
+ NV_ERR_CHECK_RETURN( s.read(type) );
+ NV_BOOL_ERR_CHECK_WARN_RETURN( type < TYPE_LAST, Serializer::ERROR_INVALID_DATA_TYPE, "Unknown data type: %d", (int)type);
+
+ //arraySize
+ int32_t arraySize;
+ NV_ERR_CHECK_RETURN( s.read(arraySize) );
+
+ //shortName
+ uint32_t nameOff;
+ NV_ERR_CHECK_RETURN( s.readPtr(nameOff) );
+
+ const char *name;
+ NV_ERR_CHECK_RETURN( s.readString(nameOff, name) ); //NOTE: we do not release name because DefinitionImpl does not copy it
+
+ //structName
+ uint32_t structNameOff;
+ NV_ERR_CHECK_RETURN( s.readPtr(structNameOff) );
+
+ const char *structName;
+ NV_ERR_CHECK_RETURN( s.readString(structNameOff, structName) ); //NOTE: we do not release name because DefinitionImpl does not copy it
+
+ // We do not have metadata for older formats without alignment
+ NV_BOOL_ERR_CHECK_WARN_RETURN( hdr.version >= BinVersions::WithAlignment, Serializer::ERROR_INVALID_FILE_VERSION, "Unable to deserialize metadata: file format does not support it" );
+
+ //alignment
+ uint32_t alignment;
+ NV_ERR_CHECK_RETURN( s.read(alignment) );
+
+ //padding
+ uint32_t padding;
+ NV_ERR_CHECK_RETURN( s.read(padding) );
+
+ def->init(name, (DataType)type, structName);
+ def->setArraySize(arraySize);
+ if( alignment ) def->setAlignment(alignment);
+ if( padding ) def->setPadding(padding);
+
+ //numChildren
+ uint32_t numChildren;
+ NV_ERR_CHECK_RETURN( s.read(numChildren) );
+
+ //children
+ for(uint32_t i = 0; i < numChildren; ++i)
+ {
+ DefinitionImpl *childDef = (DefinitionImpl *)mTraits->alloc(sizeof(DefinitionImpl));
+
+ uint32_t off;
+ NV_ERR_CHECK_RETURN( s.readPtr(off) );
+
+ NV_ERR_CHECK_RETURN( s.pushPos(off) );
+ NV_ERR_CHECK_RETURN( readMetadataInfo(hdr, s, childDef) );
+ s.popPos();
+
+ def->addChild(childDef);
+ }
+
+ //numHints
+ uint32_t numHints;
+ NV_ERR_CHECK_RETURN( s.read(numHints) );
+
+ //hints
+ for(uint32_t i = 0; i < numHints; ++i)
+ {
+ HintImpl *hint = (HintImpl *)mTraits->alloc(sizeof(HintImpl));
+ PX_PLACEMENT_NEW(hint, HintImpl)();
+
+ s.beginStruct(s.getTargetABI().getHintAlignment());
+
+ //type
+ uint32_t hintType;
+ NV_ERR_CHECK_RETURN( s.read(hintType) );
+
+ //name
+ uint32_t hintNameOff;
+ NV_ERR_CHECK_RETURN( s.readPtr(hintNameOff) );
+
+ const char *hintName;
+ NV_ERR_CHECK_RETURN( s.readString(hintNameOff, hintName) );
+ Releaser releaseName((void *)hintName, mTraits);
+
+ //val
+ s.beginStruct(s.getTargetABI().getHintValueAlignment());
+ switch( hintType )
+ {
+ case TYPE_U64:
+ {
+ uint64_t val;
+ NV_ERR_CHECK_RETURN( s.read(val) );
+ hint->init(hintName, val, false);
+
+ break;
+ }
+ case TYPE_F64:
+ {
+ double val;
+ NV_ERR_CHECK_RETURN( s.read(val) );
+ hint->init(hintName, val, false);
+
+ break;
+ }
+ case TYPE_STRING:
+ {
+ uint32_t off;
+ NV_ERR_CHECK_RETURN( s.readPtr(off) );
+
+ const char *val;
+ NV_ERR_CHECK_RETURN( s.readString(off, val) );
+ Releaser releaseVal((void *)val, mTraits);
+
+ hint->init(hintName, val, false);
+
+ break;
+ }
+ default:
+ DEBUG_ALWAYS_ASSERT();
+ return Serializer::ERROR_INVALID_DATA_TYPE;
+ }
+ s.align(s.getTargetABI().getHintValueSize());
+ s.closeStruct();
+
+ s.closeStruct();
+
+ def->addHint(hint);
+ } //i
+
+ //numEnumVals
+ uint32_t numEnumVals;
+ NV_ERR_CHECK_RETURN( s.read(numEnumVals) );
+
+ //enumVals
+ for(uint32_t i = 0; i < numEnumVals; ++i)
+ {
+ uint32_t off;
+ NV_ERR_CHECK_RETURN( s.readPtr(off) );
+
+ const char *val;
+ NV_ERR_CHECK_RETURN( s.readString(off, val) );
+ Releaser releaseVal((void *)val, mTraits);
+
+ def->addEnumVal(val);
+ }
+
+ //numRefVariants
+ uint32_t numRefVariants;
+ NV_ERR_CHECK_RETURN( s.read(numRefVariants) );
+
+ //refVariants
+ for(uint32_t i = 0; i < numRefVariants; ++i)
+ {
+ uint32_t off;
+ NV_ERR_CHECK_RETURN( s.readPtr(off) );
+
+ const char *val;
+ NV_ERR_CHECK_RETURN( s.readString(off, val) );
+ Releaser releaseVal((void *)val, mTraits);
+
+ def->addRefVariantVal(val);
+ }
+
+ s.closeStruct();
+
+ return Serializer::ERROR_NONE;
+}
+
+Serializer::ErrorType BinSerializer::deserializeMetadata(physx::PxFileBuf &stream, DeserializedMetadata &desData)
+{
+ BinaryHeader hdr;
+ BinaryHeaderExt ext;
+ NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext) );
+ NV_ERR_CHECK_RETURN(verifyFileHeader(
+ hdr,
+ hdr.version >= BinVersions::WithExtendedHeader ? &ext : 0,
+ hdr.fileLength
+ ));
+
+ PlatformABI targetParams;
+ NV_ERR_CHECK_RETURN(getPlatformInfo(
+ hdr,
+ hdr.version >= BinVersions::WithExtendedHeader ? &ext : 0,
+ targetParams
+ ));
+
+ PlatformInputStream s(stream, targetParams, mTraits);
+ s.skipBytes(hdr.metadataOffset);
+
+ uint32_t numMetadata = hdr.numMetadata;
+
+ desData.init(mTraits, numMetadata);
+
+ for(uint32_t i = 0; i < numMetadata; ++i)
+ {
+ uint32_t classNameOff;
+ NV_ERR_CHECK_RETURN( s.readPtr(classNameOff) );
+
+ const char *className;
+ NV_ERR_CHECK_RETURN( s.readString(classNameOff, className) );
+
+ uint32_t version;
+ NV_ERR_CHECK_RETURN( s.read(version) );
+
+ uint32_t entryOff;
+ NV_ERR_CHECK_RETURN( s.readPtr(entryOff) );
+
+ s.pushPos(entryOff);
+
+ DefinitionImpl *def = (DefinitionImpl *)mTraits->alloc(sizeof(DefinitionImpl));
+ NV_ERR_CHECK_WARN_RETURN( readMetadataInfo(hdr, s, def), "Failed to read metadata info" );
+
+// DumpDefinition(def, className, version);
+
+ desData[i].def = def;
+ desData[i].version = version;
+ desData[i].className = className;
+
+ s.popPos();
+ }
+
+ return Serializer::ERROR_NONE;
+}
+
+Serializer::ErrorType BinSerializer::internalDeserialize(physx::PxFileBuf &stream, Serializer::DeserializedData &res, bool & /*doesNeedUpdate*/)
+{
+ NV_BOOL_ERR_CHECK_WARN_RETURN(
+ PlatformABI::VerifyCurrentPlatform(),
+ Serializer::ERROR_INVALID_PLATFORM,
+ "Current platform is not supported, aborting" );
+
+ NV_BOOL_ERR_CHECK_RETURN( BinaryHeader::CheckAlignment(), Serializer::ERROR_INVALID_PLATFORM );
+
+ BinaryHeader hdr;
+ BinaryHeaderExt ext;
+ NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext) );
+
+ PlatformABI abi;
+ NV_ERR_CHECK_RETURN(getPlatformInfo(
+ hdr,
+ hdr.version >= BinVersions::WithExtendedHeader ? &ext : 0,
+ abi
+ ));
+
+ uint32_t fileOff = stream.tellRead();
+
+ PlatformInputStream data(stream, abi, mTraits);
+ NV_ERR_CHECK_RETURN( data.skipBytes(hdr.dataOffset) );
+
+ res.init(mTraits, static_cast<uint32_t>(hdr.numObjects));
+ for(uint32_t i = 0; i < static_cast<uint32_t>(hdr.numObjects); ++i)
+ {
+ uint32_t objOff;
+ NV_ERR_CHECK_RETURN( data.readPtr(objOff) );
+
+ if( !objOff )
+ res[i] = 0;
+ else
+ {
+ NV_ERR_CHECK_RETURN( data.pushPos(objOff) );
+
+ Serializer::ErrorType error = readObject(res[i], data);
+ if( Serializer::ERROR_NONE != error )
+ {
+ for(uint32_t j = 0; j < i; ++j) //Last object was destroyed in readObject
+ res[j]->destroy();
+
+ res.init(0, 0);
+
+ return error;
+ }
+
+ data.popPos();
+ }
+
+ uint32_t tmp;
+ NV_ERR_CHECK_RETURN( data.readPtr(tmp) ); // className
+ NV_ERR_CHECK_RETURN( data.readPtr(tmp) ); // name
+ NV_ERR_CHECK_RETURN( data.readPtr(tmp) ); // filename
+ } //i
+
+ stream.seekRead(fileOff + hdr.fileLength); //Goto end of stream
+
+ return Serializer::ERROR_NONE;
+}
+
+static BinaryReloc *getRelocationTable(const BinaryHeader &hdr, char *start, uint32_t &nrelocs)
+{
+ char *ptrTable = start + hdr.relocOffset;
+ nrelocs = *reinterpret_cast<uint32_t *>(ptrTable);
+
+ ptrTable += PlatformABI::align(4, GetAlignment<BinaryReloc>::value);
+
+ return reinterpret_cast<BinaryReloc *>(ptrTable); //Alignment is ok
+}
+
+Serializer::ErrorType BinSerializer::internalDeserializeInplace(void *mdata, uint32_t dataLen, Serializer::DeserializedData &res, bool & doesNeedUpdate)
+{
+ doesNeedUpdate = false;
+
+ NV_BOOL_ERR_CHECK_WARN_RETURN(
+ PlatformABI::VerifyCurrentPlatform(),
+ Serializer::ERROR_INVALID_PLATFORM,
+ "Current platform is not supported, aborting" );
+
+ char *start = (char *)mdata;
+
+ //Header
+ BinaryHeader &hdr = *reinterpret_cast<BinaryHeader *>(start);
+ hdr.decanonize(); //Make platform-dependent
+
+ //Extended header
+ BinaryHeaderExt *ext = hdr.version >= BinVersions::WithExtendedHeader
+ ? reinterpret_cast<BinaryHeaderExt *>(start + sizeof(BinaryHeader))
+ : 0;
+ if( ext ) ext->decanonize();
+
+ //This particular updates can be done on the fly
+ //Probably there is no need to set isUpdated because updates can be done on the fly
+
+ if( hdr.version == BinVersions::Initial )
+ NV_ERR_CHECK_WARN_RETURN( updateInitial2AllCounted(hdr, start), "Failed to update binary asset from 1.0 to 1.1" );
+
+ if( hdr.version == BinVersions::AllRefsCounted )
+ NV_ERR_CHECK_WARN_RETURN( updateAllCounted2WithAlignment(hdr, start), "Failed to update binary asset from 1.1 to 1.2" );
+
+ NV_ERR_CHECK_RETURN( verifyFileHeader(hdr, ext, dataLen) );
+
+ NV_BOOL_ERR_CHECK_RETURN( IsAligned(mdata, hdr.alignment), Serializer::ERROR_UNALIGNED_MEMORY);
+
+ //Verify platform
+ SerializePlatform filePlatform;
+ NV_ERR_CHECK_WARN_RETURN( hdr.getPlatform(filePlatform), "Unknown platform" );
+ NV_BOOL_ERR_CHECK_WARN_RETURN(
+ GetCurrentPlatform() == filePlatform,
+ Serializer::ERROR_INVALID_PLATFORM,
+ "Failed to inplace deserialize: platforms do not match" );
+
+ //Fix pointers
+
+ uint32_t nrelocs;
+ BinaryReloc *relocs = getRelocationTable(hdr, start, nrelocs);
+
+ //Using refOffs-array causes a memory allocation hence it's bad.
+ //But we have to fix all pointers prior to calling finishNvParameterized().
+ //Basically we have 3 opportunities:
+ // - reorder relocs s.t. NvParameterized-objects go after all other relocs (strings, etc.)
+ // (but this limits our binary file format + it turns out to be tricky to implement)
+ // - walk through array once again
+ // (but this may have a significant time penalty)
+ // - reuse space in relocation table to store offsets of references
+ // (this sounds nice and easy enough!)
+ // - or maybe just process relocations in reverse order
+ // (this one should be the fastest but once again this limits our format)
+ //For now we just keep the dynamic array as it seems to be pretty fast.
+
+ physx::shdfnd::Array<uint32_t, Traits::Allocator> refOffs((Traits::Allocator(mTraits)));
+ refOffs.reserve(nrelocs / 10);
+
+ for(uint32_t i = 0; i < nrelocs; ++i)
+ {
+ BinaryReloc &reloc = relocs[i];
+
+ NV_BOOL_ERR_CHECK_RETURN(
+ reloc.type < static_cast<uint32_t>(RELOC_LAST),
+ Serializer::ERROR_INVALID_RELOC_TYPE );
+
+ switch( reloc.type )
+ {
+ case uint32_t(RELOC_ABS_RAW):
+ //Raw data, do nothing
+ break;
+ case uint32_t(RELOC_ABS_REF):
+ //Reference, init later
+ refOffs.pushBack(reloc.off);
+ break;
+ default:
+ DEBUG_ALWAYS_ASSERT();
+ return Serializer::ERROR_INVALID_INTERNAL_PTR;
+ }
+
+ char *&ptr = *reinterpret_cast<char **>(start + reloc.off);
+
+ size_t off = reinterpret_cast<size_t>(ptr); //size_t == uintptr_t
+ NV_BOOL_ERR_CHECK_RETURN( off < dataLen, Serializer::ERROR_INVALID_INTERNAL_PTR );
+
+ ptr = start + off;
+ }
+
+ uint32_t *refCount = reinterpret_cast<uint32_t*>(&hdr.numObjects);
+
+ //Init references (vtables and stuff)
+ for(uint32_t i = 0; i < refOffs.size(); ++i)
+ {
+ char *&p = *reinterpret_cast<char **>(start + refOffs[i]);
+
+ const ObjHeader &objHdr = *reinterpret_cast<const ObjHeader *>(p);
+
+ const char *className = objHdr.className;
+ NV_BOOL_ERR_CHECK_RETURN( className, Serializer::ERROR_INVALID_INTERNAL_PTR );
+
+ p += objHdr.dataOffset;
+
+ if( !objHdr.isIncluded )
+ {
+ Interface *obj = PX_PLACEMENT_NEW(p, NvParameters)(mTraits, start, reinterpret_cast<int32_t*>(refCount));
+ PX_UNUSED(obj);
+
+ //We do not want objHdr.verify() here
+ }
+ else
+ {
+ Interface *obj = mTraits->finishNvParameterized(className, objHdr.version, p, start, reinterpret_cast<int32_t*>(refCount));
+ NV_BOOL_ERR_CHECK_RETURN( obj, Serializer::ERROR_OBJECT_CREATION_FAILED );
+ NV_ERR_CHECK_RETURN( verifyObjectHeader(objHdr, obj, mTraits) );
+
+ if( objHdr.version != mTraits->getCurrentVersion(className) )
+ doesNeedUpdate = true;
+ } //if( !objHdr.isIncluded )
+ } //i
+
+ // Table of root references
+ ObjectTableEntry *objectTable = reinterpret_cast<ObjectTableEntry *>(start + hdr.dataOffset); //At start of data section
+
+ //Init results
+ res.init(mTraits, static_cast<uint32_t>(hdr.numObjects));
+ for(uint32_t i = 0; i < static_cast<uint32_t>(hdr.numObjects); ++i)
+ res[i] = objectTable[i].obj;
+
+ *refCount = refOffs.size(); //Release after all inplace references are destroyed
+
+ // Conversion will be done after deserialization to avoid releasing inplace memory if all objects are destroyed
+ //(otherwise we may have data corruption)
+
+ return Serializer::ERROR_NONE;
+}
+
+Serializer::ErrorType BinSerializer::updateAllCounted2WithAlignment(BinaryHeader &hdr, char * /*start*/)
+{
+ hdr.version = BinVersions::WithAlignment;
+ hdr.alignment = 8;
+ return Serializer::ERROR_NONE;
+}
+
+Serializer::ErrorType BinSerializer::updateInitial2AllCounted(BinaryHeader &hdr, char *start)
+{
+ // versionAllRefsCounted counts all references instead of just top-level references;
+ // to achieve this we simply set mDoDeallocateSelf to true in all references
+
+ uint32_t nrelocs;
+ BinaryReloc *relocs = getRelocationTable(hdr, start, nrelocs);
+
+ for(uint32_t i = 0; i < nrelocs; ++i)
+ {
+ BinaryReloc &reloc = relocs[i];
+
+ if( reloc.type != static_cast<uint32_t>(RELOC_ABS_REF) )
+ continue;
+
+ size_t targetOff = *reinterpret_cast<size_t *>(start + reloc.off); //size_t == uintptr_t
+
+ const ObjHeader &objHdr = *reinterpret_cast<const ObjHeader *>(start + targetOff);
+
+ targetOff += objHdr.dataOffset; //Points to start of NvParameters
+
+#if PX_PS4 == 1
+#pragma GCC diagnostic ignored "-Wunused-private-field"
+#endif
+ // MyNvParameters has the same layout as NvParameters
+ class MyNvParameters
+ {
+ void *vtable;
+ void *mParameterizedTraits;
+ void *mSerializationCb;
+ void *mCbUserData;
+ void *mBuffer;
+ void *mRefCount;
+ void *mName;
+ void *mClassName;
+ bool mDoDeallocateSelf;
+ bool mDoDeallocateName;
+ bool mDoDeallocateClassName;
+
+ public:
+ void setDoDeallocateSelf() { mDoDeallocateSelf = true; }
+ };
+#if PX_PS4 == 1
+#pragma GCC diagnostic warning "-Wunused-private-field"
+#endif
+ MyNvParameters *pAsNvParameters = reinterpret_cast<MyNvParameters *>(start + targetOff);
+ pAsNvParameters->setDoDeallocateSelf();
+ }
+
+ hdr.version = BinVersions::AllRefsCounted;
+
+ return Serializer::ERROR_NONE;
+}
+
+Serializer::ErrorType BinSerializer::readArraySlow(Handle &handle, PlatformInputStream &s)
+{
+ int32_t n;
+ NV_PARAM_ERR_CHECK_RETURN( handle.getArraySize(n), Serializer::ERROR_INVALID_ARRAY );
+
+ for(int32_t i = 0; i < n; ++i)
+ {
+ handle.set(i);
+ NV_ERR_CHECK_RETURN( readBinaryData(handle, s) );
+ handle.popIndex();
+ }
+
+ return Serializer::ERROR_NONE;
+}
+
+static bool IsSimpleStruct(const Definition *pd)
+{
+ // Empty structs are special
+ if( 0 == pd->numChildren() )
+ return false;
+
+ for(int32_t i = 0; i < pd->numChildren(); ++i)
+ {
+ if (pd->child(i)->type() == TYPE_STRING || pd->child(i)->type() == TYPE_ENUM || pd->child(i)->type() == TYPE_ARRAY ||
+ pd->child(i)->type() == TYPE_REF || pd->child(i)->type() == TYPE_STRUCT
+ )
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#ifndef WITHOUT_APEX_SERIALIZATION
+
+Serializer::ErrorType BinSerializer::internalSerialize(physx::PxFileBuf &stream, const Interface **objs, uint32_t nobjs, bool doMetadata)
+{
+ NV_BOOL_ERR_CHECK_WARN_RETURN(
+ PlatformABI::VerifyCurrentPlatform(),
+ Serializer::ERROR_INVALID_PLATFORM ,
+ "Current platform is not supported, aborting" );
+
+ NV_BOOL_ERR_CHECK_RETURN( BinaryHeader::CheckAlignment(), Serializer::ERROR_INVALID_PLATFORM );
+
+ PlatformABI targetParams;
+ NV_ERR_CHECK_WARN_RETURN( PlatformABI::GetPredefinedABI(mPlatform, targetParams), "Unknown platform" );
+ NV_BOOL_ERR_CHECK_WARN_RETURN(
+ targetParams.isNormal(),
+ Serializer::ERROR_INVALID_PLATFORM,
+ "Target platform is not supported, aborting" );
+
+ PlatformABI curParams;
+ NV_ERR_CHECK_WARN_RETURN( PlatformABI::GetPredefinedABI(GetCurrentPlatform(), curParams), "Unknown platform" );
+ NV_BOOL_ERR_CHECK_RETURN( curParams.isNormal(), Serializer::ERROR_INVALID_PLATFORM );
+
+ Dictionary dict(mTraits); //Dictionary is updated in other routines
+
+ // Compute object data
+
+ typedef physx::shdfnd::Array<PlatformOutputStream, Traits::Allocator> StreamArray;
+ StreamArray dataStreams((Traits::Allocator(mTraits)));
+ dataStreams.reserve(nobjs);
+ for(uint32_t i = 0; i < nobjs; ++i)
+ {
+ Handle handle(*objs[i], "");
+ NV_BOOL_ERR_CHECK_RETURN( handle.isValid(), Serializer::ERROR_UNKNOWN );
+
+ dataStreams.pushBack(PlatformOutputStream(targetParams, mTraits, dict));
+ dataStreams.back().setAlignment(16); // 16 for safety
+
+ NV_ERR_CHECK_WARN_RETURN( storeBinaryData(*objs[i], handle, dataStreams.back()), "Failed to serialize data for object %d", i );
+ }
+
+ // Compute metadata
+
+ PlatformOutputStream metadataStream(targetParams, mTraits, dict);
+ metadataStream.setAlignment(16); // 16 for safety
+ uint32_t numMetadata = 0;
+ if( doMetadata )
+ {
+ typedef physx::shdfnd::Pair<const char *, uint32_t> VersionedClass;
+ typedef physx::shdfnd::HashMap<VersionedClass, const Definition *, physx::shdfnd::Hash<VersionedClass>, Traits::Allocator> MapClass2Def;
+ MapClass2Def mapClass2Def((Traits::Allocator(mTraits)));
+
+ //We track all classes that were saved to avoid duplicate metadata info
+ class MyRefCallback: public ReferenceInterface
+ {
+ MapClass2Def &mapClass2Def;
+
+ //Silence warnings on unable to generate assignment operator
+ void operator =(MyRefCallback) {}
+ public:
+ MyRefCallback(MapClass2Def &mapClass2Def_): mapClass2Def(mapClass2Def_) {}
+
+ void referenceCallback(Handle &handle)
+ {
+ Interface *iface;
+ handle.getParamRef(iface);
+ if( iface )
+ mapClass2Def[ VersionedClass(iface->className(), iface->version()) ] = iface->rootParameterDefinition();
+ }
+ } cb(mapClass2Def);
+
+ for(uint32_t i = 0; i < nobjs; ++i)
+ {
+ if( !objs[i] )
+ continue;
+
+ mapClass2Def[ VersionedClass(objs[i]->className(), objs[i]->version()) ] = objs[i]->rootParameterDefinition();
+ getReferences(*objs[i], cb, false, true, true);
+ }
+
+ numMetadata = mapClass2Def.size();
+
+ for(MapClass2Def::Iterator i = mapClass2Def.getIterator(); !i.done(); ++i)
+ {
+ metadataStream.beginStruct(targetParams.getMetaEntryAlignment());
+
+ metadataStream.storeStringPtr(i->first.first); //className
+ metadataStream.storeSimple<uint32_t>(i->first.second); //classVersion
+
+ //info
+ Reloc &reloc = metadataStream.storePtr(RELOC_ABS_RAW, targetParams.getMetaInfoAlignment());
+ NV_ERR_CHECK_RETURN( storeMetadataInfo(i->second, *reloc.ptrData) );
+
+ metadataStream.closeStruct();
+ } //i
+ }
+
+ // Init header
+
+ BinaryHeader hdr;
+
+ hdr.magic = Magic;
+ hdr.type = BINARY_TYPE_PLAIN;
+ hdr.version = Version;
+ hdr.numObjects = static_cast<int32_t>(nobjs);
+ hdr.fileLength = 0;
+ hdr.dictOffset = 0;
+ hdr.dataOffset = 0;
+ hdr.relocOffset = 0;
+ hdr.metadataOffset = 0;
+
+ hdr.archType = static_cast<uint32_t>(mPlatform.archType);
+ hdr.compilerType = static_cast<uint32_t>(mPlatform.compilerType);
+ hdr.compilerVer = mPlatform.compilerVer;
+ hdr.osType = static_cast<uint32_t>(mPlatform.osType);
+ hdr.osVer = mPlatform.osVer;
+
+ hdr.numMetadata = numMetadata;
+ hdr.alignment = 0;
+
+ BinaryHeaderExt ext;
+ memset(&ext, 0, sizeof(ext));
+ memcpy(&ext.vcsSafetyFlags, VCS_SAFETY_FLAGS, 4);
+
+ // Resulting stream
+
+ PlatformOutputStream joinStream(targetParams, mTraits, dict);
+
+ // Merge header
+
+ joinStream.storeBytes(reinterpret_cast<const char *>(&hdr), sizeof(hdr));
+ joinStream.storeBytes(reinterpret_cast<const char *>(&ext), sizeof(ext));
+ joinStream.align(16);
+
+ // Merge dictionary
+
+ uint32_t dictOffset = joinStream.size();
+ joinStream.mergeDict();
+
+ // Merge data
+
+ uint32_t dataOffset = 0;
+ {
+ joinStream.align(joinStream.getTargetABI().aligns.pointer);
+ dataOffset = joinStream.size();
+
+ //Create object table
+ for(uint32_t i = 0; i < nobjs; ++i)
+ {
+ dataStreams[i].flatten();
+
+ Reloc &reloc = joinStream.storePtr(RELOC_ABS_REF, dataStreams[i].alignment());
+ reloc.ptrData->merge(dataStreams[i]);
+
+ //This was requested for faster peeking of contained assets
+ joinStream.storeStringPtr(objs[i]->className());
+ joinStream.storeStringPtr(objs[i]->name());
+
+ //UE3 was once using this
+ joinStream.storeNullPtr();
+ }
+
+ joinStream.flatten(); //Merge all data-related pointers
+ }
+
+ // Merge metadata
+
+ uint32_t metadataOffset = 0;
+ if( doMetadata )
+ {
+ metadataOffset = joinStream.merge(metadataStream);
+ joinStream.flatten(); //Merge all metadata-related pointers
+ }
+
+ // Merge relocation data
+
+ uint32_t relocOffset = joinStream.writeRelocs();
+
+ // Update offsets in header
+
+ void *data = joinStream.getData();
+
+ BinaryHeader &hdrFinal = *reinterpret_cast<BinaryHeader *>(data);
+ hdrFinal.fileLength = joinStream.size();
+ hdrFinal.dictOffset = dictOffset;
+ hdrFinal.dataOffset = dataOffset;
+ hdrFinal.metadataOffset = metadataOffset;
+ hdrFinal.relocOffset = relocOffset;
+ hdrFinal.alignment = joinStream.alignment();
+
+ BinaryHeaderExt &extFinal = *reinterpret_cast<BinaryHeaderExt *>((char *)data + sizeof(BinaryHeader));
+
+ //Make platform-independent
+ hdrFinal.canonize();
+ extFinal.canonize();
+
+ // Write data to stream
+
+ if( stream.tellWrite() % joinStream.alignment() )
+ {
+ NV_PARAM_TRAITS_WARNING(
+ mTraits,
+ "Input stream is unaligned, "
+ "you will not be able to inplace deserialize it "
+ "without copying to intermediate buffer"
+ );
+ }
+
+ NV_BOOL_ERR_CHECK_RETURN(
+ joinStream.size() == stream.write(data, joinStream.size()),
+ Serializer::ERROR_STREAM_ERROR );
+
+ return Serializer::ERROR_NONE;
+}
+
+Serializer::ErrorType BinSerializer::storeMetadataInfo(const Definition *def, PlatformOutputStream &s)
+{
+ s.beginStruct(s.getTargetABI().getMetaInfoAlignment());
+
+ //type
+ s.storeSimple((uint32_t)def->type());
+
+ //arraySize
+ s.storeSimple(TYPE_ARRAY == def->type() ? (int32_t)def->arraySize() : -1);
+
+ //shortName
+ s.storeStringPtr(def->name());
+
+ //structName
+ s.storeStringPtr(def->structName());
+
+ //alignment
+ s.storeSimple(def->alignment());
+
+ //padding
+ s.storeSimple(def->padding());
+
+ //numChildren
+ s.storeSimple(def->numChildren());
+
+ //children
+ for(int32_t i = 0; i < def->numChildren(); ++i)
+ {
+ Reloc &childrenReloc = s.storePtr(RELOC_ABS_RAW, s.getTargetABI().getMetaInfoAlignment());
+ NV_ERR_CHECK_RETURN( storeMetadataInfo(def->child(i), *childrenReloc.ptrData) );
+ }
+
+ //numHints
+ s.storeSimple(def->numHints());
+
+ //hints
+ for(int32_t i = 0; i < def->numHints(); ++i)
+ {
+ const Hint *hint = def->hint(i);
+
+ s.beginStruct(s.getTargetABI().getHintAlignment());
+
+ s.storeSimple((uint32_t)hint->type());
+ s.storeStringPtr(hint->name());
+
+ s.beginStruct(s.getTargetABI().getHintValueAlignment());
+ switch( hint->type() )
+ {
+ case TYPE_U64:
+ s.storeSimple(hint->asUInt());
+ break;
+ case TYPE_F64:
+ s.storeSimple(hint->asFloat());
+ break;
+ case TYPE_STRING:
+ s.storeStringPtr(hint->asString());
+ break;
+
+NV_PARAMETRIZED_LINAL_DATATYPE_LABELS
+NV_PARAMETRIZED_REF_DATATYPE_LABELS
+NV_PARAMETRIZED_ENUM_DATATYPE_LABELS
+NV_PARAMETRIZED_SERVICE_DATATYPE_LABELS
+NV_PARAMETRIZED_UNDEFINED_AND_LAST_DATATYPE_LABELS
+NV_PARAMETRIZED_AGGREGATE_DATATYPE_LABELS
+ case TYPE_F32:
+ case TYPE_U32: case TYPE_U16: case TYPE_U8:
+ case TYPE_I64: case TYPE_I32: case TYPE_I16: case TYPE_I8: case TYPE_BOOL:
+ default:
+ DEBUG_ALWAYS_ASSERT();
+ return Serializer::ERROR_INVALID_DATA_TYPE;
+ }
+ s.align(s.getTargetABI().getHintValueSize());
+ s.closeStruct();
+
+ s.closeStruct();
+ }
+
+ //numEnumVals
+ s.storeSimple(def->numEnumVals());
+
+ //enumVals
+ for(int32_t i = 0; i < def->numEnumVals(); ++i)
+ s.storeStringPtr(def->enumVal(i));
+
+ //numRefVariantVals
+ s.storeSimple(def->numRefVariants());
+
+ //refVariants
+ for(int32_t i = 0; i < def->numRefVariants(); ++i)
+ s.storeStringPtr(def->refVariantVal(i));
+
+ s.closeStruct();
+
+ return Serializer::ERROR_NONE;
+}
+
+//Store array of arbitrary type (slow version)
+Serializer::ErrorType BinSerializer::storeArraySlow(Handle &handle, PlatformOutputStream &s)
+{
+ int32_t size;
+ NV_PARAM_ERR_CHECK_RETURN( handle.getArraySize(size), Serializer::ERROR_INVALID_ARRAY );
+
+ const Interface &obj = *handle.getConstInterface();
+ for(int32_t i = 0; i < size; ++i)
+ {
+ handle.set(i);
+ NV_ERR_CHECK_RETURN( storeBinaryData(obj, handle, s) );
+ handle.popIndex();
+ }
+
+ return Serializer::ERROR_NONE;
+}
+
+//Print binary data for part of NvParameterized object addressed by handle
+Serializer::ErrorType BinSerializer::storeBinaryData(const Interface &obj, Handle &handle, PlatformOutputStream &res, bool isRootObject)
+{
+ bool isObject = !handle.numIndexes();
+
+ if( isObject )
+ res.storeObjHeader(obj);
+
+ const Definition *pd = handle.parameterDefinition();
+
+ bool doNotSerialize = 0 != pd->hint("DONOTSERIALIZE"),
+ isDynamicArray = pd->type() == TYPE_ARRAY && !pd->arraySizeIsFixed();
+
+ // Alignment in dynamic array means alignment of dynamic memory
+ // so we do not insert it here
+ if( pd->alignment() && !isDynamicArray )
+ res.align(pd->alignment());
+
+ //Dynamic arrays are special because we need some of their fields for correct inplace deserialization
+ if( doNotSerialize && !isDynamicArray )
+ {
+ //Simply skip bytes
+ res.align(res.getTargetAlignment(pd));
+ res.skipBytes(res.getTargetSize(pd));
+
+ return Serializer::ERROR_NONE;
+ }
+
+ switch( pd->type() )
+ {
+ case TYPE_ARRAY:
+ {
+ if( pd->arraySizeIsFixed() )
+ {
+ res.beginArray(pd);
+ storeArraySlow(handle, res);
+ res.closeArray();
+ }
+ else
+ {
+ res.beginStruct(pd); //Dynamic arrays are implemented as structs
+
+ bool isEmpty = false;
+ if( doNotSerialize )
+ isEmpty = true;
+ else
+ {
+ for(int32_t i = 0; i < pd->arrayDimension(); ++i)
+ {
+ int32_t size = 0;
+ NV_PARAM_ERR_CHECK_RETURN( handle.getArraySize(size, i), Serializer::ERROR_INVALID_ARRAY );
+
+ if( 0 == size )
+ {
+ isEmpty = true;
+ break;
+ }
+ }
+ }
+
+ const Definition *elemPd = pd;
+ for(int32_t i = 0; i < pd->arrayDimension(); ++i)
+ elemPd = elemPd->child(0);
+
+ //Pointer-to-data
+ Reloc *reloc = 0;
+ if( isEmpty )
+ res.storeNullPtr();
+ else
+ {
+ reloc = &res.storePtr(RELOC_ABS_RAW, elemPd);
+ if( pd->alignment() )
+ reloc->ptrData->setAlignment(physx::PxMax(reloc->ptrData->alignment(), pd->alignment()));
+ }
+
+ //isAllocated
+ res.storeSimple(false);
+
+ //elementSize
+ res.storeSimple<uint32_t>(res.getTargetSize(elemPd));
+
+ //arraySizes
+ const Definition *subArrayPd = pd;
+ res.beginArray(res.getTargetABI().getAlignment<int32_t>());
+ for(int32_t dim = 0; dim < pd->arrayDimension(); ++dim)
+ {
+ // Store size of static dimensions even if doNotSerialize is on
+ int32_t size = 0;
+ if( !doNotSerialize || subArrayPd->arraySizeIsFixed() )
+ NV_PARAM_ERR_CHECK_RETURN( handle.getArraySize(size, dim), Serializer::ERROR_INVALID_ARRAY );
+
+ res.storeSimple(size);
+
+ NV_BOOL_ERR_CHECK_RETURN( 1 == subArrayPd->numChildren(), Serializer::ERROR_UNKNOWN );
+ subArrayPd = subArrayPd->child(0);
+ }
+ res.closeArray();
+
+ //Data
+ if( !isEmpty )
+ {
+ reloc->ptrData->beginArray(elemPd);
+
+ int32_t size = -1;
+ NV_PARAM_ERR_CHECK_RETURN( handle.getArraySize(size), Serializer::ERROR_INVALID_ARRAY );
+
+ const Definition *child = pd->child(0);
+ switch( child->type() )
+ {
+# define NV_PARAMETERIZED_TYPES_NO_LEGACY_TYPES
+# define NV_PARAMETERIZED_TYPES_ONLY_SIMPLE_TYPES
+# define NV_PARAMETERIZED_TYPES_NO_STRING_TYPES
+# define NV_PARAMETERIZED_TYPE(type_name, enum_name, c_type) \
+ case TYPE_##enum_name: \
+ { \
+ reloc->ptrData->storeSimpleArray<c_type>(handle); \
+ break; \
+ }
+# include "nvparameterized/NvParameterized_types.h"
+
+ case TYPE_STRUCT:
+ if( IsSimpleStruct(child) )
+ {
+ //Fast path for simple structs
+ reloc->ptrData->storeSimpleStructArray(handle);
+ break;
+ }
+
+ //Else fall through to default, includes TYPE_MAT34 case
+NV_PARAMETRIZED_UNDEFINED_AND_LAST_DATATYPE_LABELS
+NV_PARAMETRIZED_LEGACY_DATATYPE_LABELS
+NV_PARAMETRIZED_STRING_DATATYPE_LABELS
+NV_PARAMETRIZED_REF_DATATYPE_LABELS
+NV_PARAMETRIZED_ENUM_DATATYPE_LABELS
+NV_PARAMETRIZED_SERVICE_DATATYPE_LABELS
+ case TYPE_ARRAY:
+ default:
+ storeArraySlow(handle, *reloc->ptrData);
+ break;
+ }
+
+ reloc->ptrData->closeArray();
+ }
+
+ res.closeStruct();
+ }
+ break;
+ }
+
+ case TYPE_STRUCT:
+ {
+ uint32_t oldSize = isObject ? res.beginObject(obj, isRootObject, pd) : res.beginStruct(pd);
+
+ for(int32_t i = 0; i < pd->numChildren(); ++i)
+ {
+ handle.set(i);
+ NV_ERR_CHECK_RETURN( storeBinaryData(obj, handle, res) );
+ handle.popIndex();
+ }
+
+ //Empty structs are at least 1 char long
+ if( res.size() == oldSize )
+ res.storeSimple((uint8_t)0);
+
+ if( isObject )
+ res.closeObject();
+ else
+ res.closeStruct();
+
+ break;
+ }
+
+ case TYPE_STRING:
+ {
+ const char *s = 0;
+ handle.getParamString(s);
+
+ res.beginString();
+
+ //buf
+ res.storeStringPtr(s);
+
+ //isAllocated
+ res.storeSimple(false);
+
+ res.closeString();
+
+ break;
+ }
+
+ case TYPE_ENUM:
+ {
+ const char *s = 0;
+ handle.getParamEnum(s);
+
+ res.storeStringPtr(s);
+
+ break;
+ }
+
+ case TYPE_REF:
+ {
+ Interface *refObj = 0;
+ handle.getParamRef(refObj);
+
+ if( !refObj )
+ res.storeNullPtr();
+ else if( pd->isIncludedRef() )
+ {
+ Handle refHandle(*refObj, "");
+ NV_BOOL_ERR_CHECK_RETURN( refHandle.isValid(), Serializer::ERROR_UNKNOWN );
+
+ Reloc &reloc = res.storePtr(RELOC_ABS_REF, 16); //16 for safety
+ NV_ERR_CHECK_RETURN( storeBinaryData(*refObj, refHandle, *reloc.ptrData, false) );
+ }
+ else //Named reference
+ {
+ Reloc &reloc = res.storePtr(RELOC_ABS_REF, 16); //16 for safety
+ reloc.ptrData->storeObjHeader(*refObj, false);
+ reloc.ptrData->beginObject(*refObj, false, 0);
+ reloc.ptrData->closeObject(); //Named references are instances of NvParameters => no additional fields
+ }
+
+ break;
+ }
+
+ case TYPE_POINTER:
+ {
+ res.storeNullPtr();
+ break;
+ }
+
+
+# define NV_PARAMETERIZED_TYPES_NO_LEGACY_TYPES
+# define NV_PARAMETERIZED_TYPES_ONLY_SIMPLE_TYPES
+# define NV_PARAMETERIZED_TYPES_NO_STRING_TYPES
+# define NV_PARAMETERIZED_TYPE(type_name, enum_name, c_type) \
+ case TYPE_##enum_name: \
+ { \
+ c_type val; \
+ NV_PARAM_ERR_CHECK_RETURN( handle.getParam##type_name(val), Serializer::ERROR_INVALID_VALUE ); \
+ res.storeSimple<c_type>(val); \
+ break; \
+ }
+# include "nvparameterized/NvParameterized_types.h"
+
+ case TYPE_MAT34:
+ {
+ float val[12];
+ NV_PARAM_ERR_CHECK_RETURN( handle.getParamMat34Legacy(val), Serializer::ERROR_INVALID_VALUE );
+ res.storeSimple(val, 12);
+ break;
+ }
+
+NV_PARAMETRIZED_UNDEFINED_AND_LAST_DATATYPE_LABELS
+ default:
+ DEBUG_ASSERT(0 && "Unknown type");
+ return Serializer::ERROR_INVALID_DATA_TYPE;
+ }
+
+ return Serializer::ERROR_NONE;
+}
+
+#endif
+
+//Read NvParameterized object data
+Serializer::ErrorType BinSerializer::readObject(Interface *&obj, PlatformInputStream &data)
+{
+ ObjHeader objHdr;
+ NV_ERR_CHECK_WARN_RETURN( data.readObjHeader(objHdr), "Failed to deserialize object header" );
+ Releaser releaseClassName((void *)objHdr.className, mTraits),
+ releaseName((void *)objHdr.name, mTraits),
+ releaseChecksum((void *)objHdr.checksum, mTraits);
+
+ if( !objHdr.isIncluded )
+ {
+ void *buf = mTraits->alloc(sizeof(NvParameters));
+ NV_BOOL_ERR_CHECK_RETURN( buf, Serializer::ERROR_MEMORY_ALLOCATION_FAILURE );
+
+ obj = PX_PLACEMENT_NEW(buf, NvParameters)(mTraits);
+ obj->setClassName(objHdr.className);
+
+ if( objHdr.name )
+ obj->setName(objHdr.name);
+
+ //We do not want objHdr.verify() here
+ }
+ else
+ {
+ NV_BOOL_ERR_CHECK_RETURN( objHdr.className, Serializer::ERROR_OBJECT_CREATION_FAILED );
+
+ obj = mTraits->createNvParameterized(objHdr.className, objHdr.version);
+ NV_BOOL_ERR_CHECK_RETURN( obj, Serializer::ERROR_OBJECT_CREATION_FAILED );
+
+ if( objHdr.name )
+ obj->setName(objHdr.name);
+
+ NV_ERR_CHECK_RETURN( verifyObjectHeader(objHdr, obj, mTraits) );
+
+ Handle handle(*obj, "");
+ NV_BOOL_ERR_CHECK_RETURN( handle.isValid(), Serializer::ERROR_UNKNOWN );
+
+ NV_ERR_CHECK_RETURN( data.pushPos(objHdr.dataOffset) );
+ NV_ERR_CHECK_RETURN( readBinaryData(handle, data) );
+ data.popPos();
+ }
+
+ return Serializer::ERROR_NONE;
+}
+
+//Read binary data of NvParameterized object addressed by handle
+Serializer::ErrorType BinSerializer::readBinaryData(Handle &handle, PlatformInputStream &data)
+{
+ const Definition *pd = handle.parameterDefinition();
+
+ bool isDynamicArray = TYPE_ARRAY == pd->type() && !pd->arraySizeIsFixed();
+
+ // See comment in storeBinaryData
+ if( pd->alignment() && !isDynamicArray )
+ data.align(pd->alignment());
+
+ if( pd->hint("DONOTSERIALIZE") )
+ {
+ //Simply skip DONOTSERIALIZE
+ data.align(data.getTargetAlignment(pd));
+ NV_ERR_CHECK_RETURN( data.skipBytes(data.getTargetSize(pd)) );
+ return Serializer::ERROR_NONE;
+ }
+
+ switch( pd->type() )
+ {
+ case TYPE_ARRAY:
+ {
+ if( pd->arraySizeIsFixed() )
+ {
+ data.beginArray(pd);
+ for(int32_t i = 0; i < pd->arraySize(); ++i)
+ {
+ handle.set(i);
+ NV_ERR_CHECK_RETURN( readBinaryData(handle, data) );
+ handle.popIndex();
+ }
+ data.closeArray();
+ }
+ else
+ {
+ data.beginStruct(pd); //Dynamic arrays are implemented as structs
+
+ uint32_t elemOff;
+ NV_ERR_CHECK_RETURN( data.readPtr(elemOff) );
+
+ bool isAllocated;
+ NV_ERR_CHECK_RETURN( data.read(isAllocated) );
+
+ int32_t elementSize;
+ NV_ERR_CHECK_RETURN( data.read(elementSize) ); //elementSize
+
+ data.beginStruct(data.getTargetABI().aligns.i32); //Start array of sizes
+
+ int32_t arraySize;
+ NV_ERR_CHECK_RETURN( data.read(arraySize) ); //We need only the first size
+
+ const Definition *subArrayPd = pd->child(0);
+ for(int32_t dim = 1; dim < pd->arrayDimension(); ++dim)
+ {
+ int32_t size;
+ NV_ERR_CHECK_RETURN( data.read(size) );
+
+ // We do not support nested dynamic arrays
+ if( subArrayPd->arraySizeIsFixed() )
+ NV_BOOL_ERR_CHECK_RETURN( size == subArrayPd->arraySize(), Serializer::ERROR_INVALID_ARRAY );
+
+ subArrayPd = subArrayPd->child(0);
+ }
+ data.closeStruct(); //End array of sizes
+
+ NV_PARAM_ERR_CHECK_RETURN( handle.resizeArray(arraySize), Serializer::ERROR_INVALID_ARRAY );
+
+ if( elemOff )
+ {
+ // Check alignment
+ uint32_t align = pd->alignment();
+ if( align && elemOff % align ) {
+ char longName[256];
+ handle.getLongName(longName, sizeof(longName));
+ NV_PARAM_TRAITS_WARNING(
+ mTraits,
+ "%s: array is unaligned, "
+ "you will not be able to inplace deserialize it "
+ "without copying to intermediate buffer.",
+ longName
+ );
+ }
+
+ NV_ERR_CHECK_RETURN( data.pushPos(elemOff) );
+
+ switch( pd->child(0)->type() )
+ {
+# define NV_PARAMETERIZED_TYPES_NO_LEGACY_TYPES
+# define NV_PARAMETERIZED_TYPES_ONLY_SIMPLE_TYPES
+# define NV_PARAMETERIZED_TYPES_NO_STRING_TYPES
+# define NV_PARAMETERIZED_TYPE(type_name, enum_name, c_type) \
+ case TYPE_##enum_name: \
+ { \
+ NV_ERR_CHECK_RETURN( data.readSimpleArray<c_type>(handle) ); \
+ break; \
+ }
+# include "nvparameterized/NvParameterized_types.h"
+
+ case TYPE_STRUCT:
+ {
+ const Definition *child = pd->child(0);
+ if( IsSimpleStruct(child) )
+ {
+ //Fast path for simple structs
+ NV_ERR_CHECK_RETURN( data.readSimpleStructArray(handle) );
+ break;
+ }
+
+ //Else fall through to default, including TYPE_MAT34 case
+ }
+
+NV_PARAMETRIZED_UNDEFINED_AND_LAST_DATATYPE_LABELS
+NV_PARAMETRIZED_LEGACY_DATATYPE_LABELS
+NV_PARAMETRIZED_STRING_DATATYPE_LABELS
+NV_PARAMETRIZED_REF_DATATYPE_LABELS
+NV_PARAMETRIZED_ENUM_DATATYPE_LABELS
+NV_PARAMETRIZED_SERVICE_DATATYPE_LABELS
+case TYPE_ARRAY:
+ default:
+ NV_ERR_CHECK_RETURN( readArraySlow(handle, data) );
+ break;
+ }
+
+ data.popPos();
+ }
+
+ data.closeStruct();
+ }
+ break;
+ }
+
+ case TYPE_STRUCT:
+ {
+ uint32_t oldPos = data.getPos();
+
+ data.beginStruct(pd);
+ for(int32_t i = 0; i < pd->numChildren(); ++i)
+ {
+ handle.set(i);
+ NV_ERR_CHECK_RETURN( readBinaryData(handle, data) );
+ handle.popIndex();
+ }
+
+ //Empty structs are at least 1 char long
+ if( data.getPos() == oldPos )
+ {
+ uint8_t tmp;
+ NV_ERR_CHECK_RETURN( data.read(tmp) );
+ }
+
+ data.closeStruct();
+
+ break;
+ }
+
+ case TYPE_STRING:
+ {
+ data.beginString();
+
+ uint32_t off;
+ NV_ERR_CHECK_RETURN( data.readPtr(off) );
+
+ const char *s;
+ NV_ERR_CHECK_RETURN( data.readString(off, s) );
+
+ NV_PARAM_ERR_CHECK_RETURN( handle.setParamString(s), Serializer::ERROR_INVALID_VALUE );
+ mTraits->free((char *)s);
+
+ bool isAllocated;
+ NV_ERR_CHECK_RETURN( data.read(isAllocated) );
+
+ data.closeString();
+
+ break;
+ }
+
+ case TYPE_ENUM:
+ {
+ uint32_t off;
+ NV_ERR_CHECK_RETURN( data.readPtr(off) );
+
+ const char *s;
+ NV_ERR_CHECK_RETURN( data.readString(off, s) );
+
+ NV_BOOL_ERR_CHECK_RETURN( s, Serializer::ERROR_INVALID_VALUE );
+ NV_PARAM_ERR_CHECK_RETURN( handle.setParamEnum(s), Serializer::ERROR_INVALID_VALUE );
+
+ mTraits->free((char *)s);
+
+ break;
+ }
+
+ case TYPE_REF:
+ {
+ uint32_t objPos;
+ NV_ERR_CHECK_RETURN( data.readPtr(objPos) );
+
+ Interface *refObj = 0;
+
+ if( objPos )
+ {
+ NV_ERR_CHECK_RETURN( data.pushPos(objPos) );
+ NV_ERR_CHECK_RETURN( readObject(refObj, data) );
+ data.popPos();
+ }
+
+ if( refObj && (-1 == handle.parameterDefinition()->refVariantValIndex(refObj->className())) )
+ {
+ char longName[256];
+ handle.getLongName(longName, sizeof(longName));
+ NV_PARAM_TRAITS_WARNING(
+ mTraits,
+ "%s: setting reference of invalid class %s",
+ longName,
+ refObj->className()
+ );
+ }
+
+ NV_PARAM_ERR_CHECK_RETURN( handle.setParamRef(refObj), Serializer::ERROR_INVALID_REFERENCE );
+
+ break;
+ }
+
+ case TYPE_POINTER:
+ {
+ void *tmp;
+ NV_ERR_CHECK_RETURN( data.read(tmp) );
+ break;
+ }
+
+
+# define NV_PARAMETERIZED_TYPES_NO_LEGACY_TYPES
+# define NV_PARAMETERIZED_TYPES_ONLY_SIMPLE_TYPES
+# define NV_PARAMETERIZED_TYPES_NO_STRING_TYPES
+# define NV_PARAMETERIZED_TYPE(type_name, enum_name, c_type) \
+ case TYPE_##enum_name: \
+ { \
+ c_type val; \
+ NV_ERR_CHECK_RETURN(data.read(val)); \
+ NV_PARAM_ERR_CHECK_RETURN( handle.setParam##type_name(val), Serializer::ERROR_INVALID_VALUE ); \
+ break; \
+ }
+# include "nvparameterized/NvParameterized_types.h"
+
+ case TYPE_MAT34:
+ {
+ float val[12];
+ for (int k = 0; k < 12; ++k)
+ {
+ NV_ERR_CHECK_RETURN(data.read(val[k]));
+ }
+ NV_PARAM_ERR_CHECK_RETURN( handle.setParamMat34Legacy(val), Serializer::ERROR_INVALID_VALUE );
+ break;
+ }
+
+NV_PARAMETRIZED_UNDEFINED_AND_LAST_DATATYPE_LABELS
+ default:
+ DEBUG_ASSERT(0 && "Unknown type");
+ return Serializer::ERROR_INVALID_DATA_TYPE;
+ }
+
+ return Serializer::ERROR_NONE;
+}
+
+bool isBinaryFormat(physx::PxFileBuf &stream)
+{
+ uint32_t magic;
+ stream.peek(&magic, 4);
+ return Canonize(magic) == BinSerializer::Magic;
+}
+
+Serializer::ErrorType peekBinaryPlatform(physx::PxFileBuf &stream, SerializePlatform &platform)
+{
+ BinaryHeader hdr;
+ BinaryHeaderExt ext;
+ NV_ERR_CHECK_RETURN( peekFileHeader(stream, hdr, ext) );
+ NV_ERR_CHECK_RETURN( hdr.getPlatform(platform) );
+ return Serializer::ERROR_NONE;
+}
+
+} // namespace NvParameterized
|