aboutsummaryrefslogtreecommitdiff
path: root/sdk/extensions/import/apexmodules/NvParameterized/src/BinSerializer.cpp
diff options
context:
space:
mode:
authorBryan Galdrikian <[email protected]>2018-05-31 11:36:08 -0700
committerBryan Galdrikian <[email protected]>2018-05-31 11:36:08 -0700
commit7115f60b91b5717d90f643fd692010905c7004db (patch)
treeeffd68c6978751c517d54c2f2bb5bb6e7dc93e18 /sdk/extensions/import/apexmodules/NvParameterized/src/BinSerializer.cpp
parentUpdating BlastTool zip (diff)
downloadblast-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.cpp3656
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