| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- #include "stdafx.h"
- #include "ContentReader.h"
- ContentReader::ContentReader(FILE* file, TypeReaderManager* typeReaderManager)
- : BinaryReader(file),
- typeReaderManager(typeReaderManager)
- {
- }
- // Parses the entire contents of an XNB file.
- void ContentReader::ReadXnb()
- {
- // Read the XNB header.
- uint32_t endPosition = ReadHeader();
- ReadTypeManifest();
- uint32_t sharedResourceCount = Read7BitEncodedInt();
- // Read the primary asset data.
- Log.WriteLine("Asset:");
- ReadObject();
- // Read any shared resource instances.
- for (uint32_t i = 0 ; i < sharedResourceCount; i++)
- {
- Log.WriteLine("Shared resource %d:", i);
-
- ReadObject();
- }
- // Make sure we read the amount of data that the file header said we should.
- if (FilePosition() != endPosition)
- {
- throw exception("End position does not match XNB header: unexpected amount of data was read.");
- }
- }
- // Reads the XNB file header (version number, size, etc.).
- uint32_t ContentReader::ReadHeader()
- {
- uint32_t startPosition = FilePosition();
- // Magic number.
- uint8_t magic1 = ReadByte();
- uint8_t magic2 = ReadByte();
- uint8_t magic3 = ReadByte();
- if (magic1 != 'X' ||
- magic2 != 'N' ||
- magic3 != 'B')
- {
- throw exception("Not an XNB file.");
- }
- // Target platform.
- uint8_t targetPlatform = ReadByte();
- switch (targetPlatform)
- {
- case 'w': Log.WriteLine("Target platform: Windows"); break;
- case 'm': Log.WriteLine("Target platform: Windows Phone"); break;
- case 'x': Log.WriteLine("Target platform: Xbox 360"); break;
- default: Log.WriteLine("Unknown target platform %d", targetPlatform); break;
- }
- // Format version.
- uint8_t formatVersion = ReadByte();
- if (formatVersion != 5)
- {
- Log.WriteLine("Warning: not an XNA Game Studio version 4.0 XNB file. Parsing may fail unexpectedly.");
- }
- // Flags.
- uint8_t flags = ReadByte();
- if (flags & 1)
- {
- Log.WriteLine("Graphics profile: HiDef");
- }
- else
- {
- Log.WriteLine("Graphics profile: Reach");
- }
- bool isCompressed = (flags & 0x80) != 0;
- // File size.
- uint32_t sizeOnDisk = ReadUInt32();
- if (startPosition + sizeOnDisk > FileSize())
- {
- throw exception("XNB file has been truncated.");
- }
- if (isCompressed)
- {
- uint32_t decompressedSize = ReadUInt32();
- uint32_t compressedSize = startPosition + sizeOnDisk - FilePosition();
- Log.WriteLine("%d bytes of asset data are compressed into %d", decompressedSize, compressedSize);
- throw exception("Don't support reading the contents of compressed XNB files.");
- }
- return startPosition + sizeOnDisk;
- }
- // Reads the manifest of what types are contained in this XNB file.
- void ContentReader::ReadTypeManifest()
- {
- Log.WriteLine("Type readers:");
- Log.Indent();
- // How many type readers does this .xnb use?
- uint32_t typeReaderCount = Read7BitEncodedInt();
- typeReaders.clear();
- for (uint32_t i = 0; i < typeReaderCount; i++)
- {
- // Read the type reader metadata.
- wstring readerName = ReadString();
- int32_t readerVersion = ReadInt32();
- Log.WriteLine("%S (version %d)", readerName.c_str(), readerVersion);
- // Look up and store this type reader implementation class.
- TypeReader* reader = typeReaderManager->GetByReaderName(readerName);
- typeReaders.push_back(reader);
- }
- // Initialize the readers in a separate pass after they are all registered, in case there are
- // circular dependencies between them (eg. an array of classes which themselves contain arrays).
- for each (TypeReader* reader in typeReaders)
- {
- reader->Initialize(typeReaderManager);
- }
- Log.Unindent();
- }
- // Reads a single polymorphic object from the current location.
- void ContentReader::ReadObject()
- {
- Log.Indent();
- // What type of object is this?
- TypeReader* typeReader = ReadTypeId();
-
- if (typeReader)
- {
- Log.WriteLine("Type: %S", typeReader->TargetType().c_str());
- // Call into the appropriate TypeReader to parse the object data.
- typeReader->Read(this);
- }
- else
- {
- Log.WriteLine("null");
- }
- Log.Unindent();
- }
- // Reads either a raw value or polymorphic object, depending on whether the specified typeReader represents a value type.
- void ContentReader::ReadValueOrObject(TypeReader* typeReader)
- {
- if (typeReader->IsValueType())
- {
- // Read a value type.
- Log.Indent();
- typeReader->Read(this);
- Log.Unindent();
- }
- else
- {
- // Read a reference type.
- ReadObject();
- }
- }
- // Reads the typeId from the start of a polymorphic object, and looks up the appropriate TypeReader implementation.
- TypeReader* ContentReader::ReadTypeId()
- {
- uint32_t typeId = Read7BitEncodedInt();
- if (typeId > 0)
- {
- // Look up the reader for this type of object.
- typeId--;
- if (typeId >= typeReaders.size())
- {
- throw exception("Invalid XNB file: typeId is out of range.");
- }
- return typeReaders[typeId];
- }
- else
- {
- // A zero typeId indicates a null object.
- return nullptr;
- }
- }
- // Reads a typeId, and validates that it is the expected type.
- void ContentReader::ValidateTypeId(wstring const& expectedType)
- {
- TypeReader* reader = ReadTypeId();
- if (!reader || reader->TargetType() != expectedType)
- {
- throw exception("Invalid XNB file: got an unexpected typeId.");
- }
- }
- // Reads a shared resource ID, which indexes into the table of shared object instances that come after the primary asset.
- void ContentReader::ReadSharedResource()
- {
- uint32_t resourceId = Read7BitEncodedInt();
- if (resourceId)
- {
- Log.WriteLine("shared resource #%u", resourceId - 1);
- }
- else
- {
- Log.WriteLine("null");
- }
- }
|