/// <summary> /// Reads a file block and returns it. /// If the block is SDNA, initializes and returns an instance of <pre>StructureDNA</pre>. /// </summary> /// <param name="file">A blend file with the reader at the start of a file block.</param> /// <param name="pointerSize">The pointer size of the current file.</param> /// <returns>A parsed FileBlock.</returns> public static FileBlock ReadBlock(BinaryReader file, int pointerSize) { if (pointerSize != 4 && pointerSize != 8) { throw new ArgumentException("Impossible for pointerSize to be " + pointerSize); } string code; int size, sdna, count; byte[] data; ulong address; // read block header code = new string(file.ReadChars(4)); size = file.ReadInt32(); address = pointerSize == 4 ? file.ReadUInt32() : file.ReadUInt64(); sdna = file.ReadInt32(); count = file.ReadInt32(); data = file.ReadBytes(size); FileBlock block = code == "DNA1" ? new StructureDNA(code, size, sdna, count, data) : new FileBlock(code, size, sdna, count, data); // blocks are aligned at four bytes while (file.BaseStream.Position % 4 != 0 && file.BaseStream.Position < file.BaseStream.Length) // don't want to read off the file by accident { file.ReadByte(); } // I'm not 100% sure why this is done here. block.OldMemoryAddress = address; return(block); }
/// <summary> /// Parses a file block. If the file block is SDNA or another block with block.count == 0, it will return null. /// </summary> /// <param name="block">The block to parse.</param> /// <param name="blocksParsed">Number of blocks parsed so far.</param> /// <param name="file">Source file for the structures.</param> /// <returns>An array of PopulatedStructures, or { null } if no structures are defined.</returns> public static Structure[] ParseFileBlock(FileBlock block, int blocksParsed, BlenderFile file) { if (block.Count == 0 || block.Code == "DNA1") { return(null); } StructureDNA sdna = file.StructureDNA; if (block.Data.Length != sdna.StructureList[block.SDNAIndex].StructureTypeSize * block.Count) { // generally, these are things like raw data; packed files, preview images, and arrays of pointers that are themselves pointed to. // I have no idea what TEST and REND do. file.RawBlockMessages.Add(blocksParsed + " " + block.OldMemoryAddress.ToString("X" + (file.PointerSize * 2)) + " " + block.Code + " " + block.SDNAIndex + " " + sdna.StructureList[block.SDNAIndex].StructureTypeSize * block.Count + " " + block.Data.Length); return(null); } Structure[] output = new Structure[block.Count]; if (block.Count > 1) { for (int i = 0; i < block.Count; i++) { byte[] data = new byte[block.Size / block.Count]; for (int j = 0; j < block.Size / block.Count; j++) { data[j] = block.Data[i * (block.Size / block.Count) + j]; } output[i] = new Structure(data, sdna.StructureList[block.SDNAIndex], file); output[i].Size = sdna.StructureList[block.SDNAIndex].StructureTypeSize; output[i].TypeName = sdna.StructureList[block.SDNAIndex].StructureTypeName; output[i].ContainingBlock = block; } } else { output[0] = new Structure(block.Data, sdna.StructureList[block.SDNAIndex], file); output[0].Size = sdna.StructureList[block.SDNAIndex].StructureTypeSize; output[0].TypeName = sdna.StructureList[block.SDNAIndex].StructureTypeName; output[0].ContainingBlock = block; } return(output); }
/// <summary> /// Reads the file blocks from the file. Returns the block with the code <pre>DNA1</pre>, which is the file's /// structure DNA. /// </summary> /// <param name="fileReader">Reference to file reader for current file.</param> /// <returns>File's Structure DNA.</returns> private StructureDNA readBlocks(BinaryReader fileReader) { StructureDNA dna = null; do { FileBlock b = FileBlock.ReadBlock(fileReader, PointerSize); if (b.Code == "DNA1") { dna = (StructureDNA)b; } fileBlocks.Add(b); } while(fileReader.BaseStream.Position < fileReader.BaseStream.Length); if (dna == null) { throw new InvalidDataException("This file contains no structure DNA! What are you trying to pull?!"); } return(dna); }