aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/NvParameterized/src/BinSerializer.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/NvParameterized/src/BinSerializer.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'APEX_1.4/NvParameterized/src/BinSerializer.cpp')
-rw-r--r--APEX_1.4/NvParameterized/src/BinSerializer.cpp1828
1 files changed, 1828 insertions, 0 deletions
diff --git a/APEX_1.4/NvParameterized/src/BinSerializer.cpp b/APEX_1.4/NvParameterized/src/BinSerializer.cpp
new file mode 100644
index 00000000..623c0203
--- /dev/null
+++ b/APEX_1.4/NvParameterized/src/BinSerializer.cpp
@@ -0,0 +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