/// <summary> /// Decodes the ARZ file. /// </summary> /// <param name="inReader">input BinaryReader</param> /// <param name="baseOffset">Offset in the file.</param> /// <param name="arzFile">ArzFile instance which we are operating.</param> public void Decode(BinaryReader inReader, int baseOffset, ArzFile arzFile) { // Record Entry Format // 0x0000 int32 stringEntryID (dbr filename) // 0x0004 int32 string length // 0x0008 string (record type) // 0x00?? int32 offset // 0x00?? int32 length in bytes // 0x00?? int32 timestamp? // 0x00?? int32 timestamp? this.idStringIndex = inReader.ReadInt32(); this.RecordType = TQData.ReadCString(inReader); this.offset = inReader.ReadInt32() + baseOffset; // Compressed size // We throw it away and just advance the offset in the file. inReader.ReadInt32(); // Crap1 - timestamp? // We throw it away and just advance the offset in the file. inReader.ReadInt32(); // Crap2 - timestamp? // We throw it away and just advance the offset in the file. inReader.ReadInt32(); // Get the ID string this.ID = arzFile.Getstring(this.idStringIndex); }
/// <summary> /// Decompresses the ARZ file into an array of bytes. /// </summary> /// <param name="arzFile">ArzFile which we are decompressing.</param> /// <returns>Returns a byte array containing the raw data.</returns> private byte[] DecompressBytes(ArzFile arzFile) { if (arzFile == null) { throw new ArgumentNullException("arzFile", "arzFile is null."); } // Read in the compressed data and decompress it, storing the results in a memorystream using (FileStream arzStream = new FileStream(arzFile.fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { arzStream.Seek(this.offset, SeekOrigin.Begin); // Ignore the zlib compression method. arzStream.ReadByte(); // Ignore the zlib compression flags. arzStream.ReadByte(); // Create a deflate stream. using (DeflateStream deflate = new DeflateStream(arzStream, CompressionMode.Decompress)) { // Create a memorystream to hold the decompressed data using (MemoryStream outStream = new MemoryStream()) { // Now decompress byte[] buffer = new byte[1024]; int len; while ((len = deflate.Read(buffer, 0, 1024)) > 0) { outStream.Write(buffer, 0, len); } // Return the decompressed data return(outStream.ToArray()); } } } }
/// <summary> /// Decompresses an individual record. /// </summary> /// <param name="arzFile">ARZ file which we are decompressing.</param> /// <returns>decompressed DBRecord.</returns> public DBRecordCollection Decompress(ArzFile arzFile) { // record variables have this format: // 0x00 int16 specifies data type: // 0x0000 = int - data will be an int32 // 0x0001 = float - data will be a Single // 0x0002 = string - data will be an int32 that is index into string table // 0x0003 = bool - data will be an int32 // 0x02 int16 specifies number of values (usually 1, but sometimes more (for arrays) // 0x04 int32 key string ID (the id into the string table for this variable name // 0x08 data value byte[] data = this.DecompressBytes(arzFile); int numberOfDWords = data.Length / 4; if (data.Length % 4 != 0) { // Turn on debugging so we can log the exception. if (!TQDebug.DebugEnabled) { TQDebug.DebugEnabled = true; } TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Error in ARZFile - {0}", arzFile.fileName)); TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Error while parsing arz record {0}, data Length = {1} which is not a multiple of 4", this.ID, (int)data.Length)); throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Error while parsing arz record {0}, data Length = {1} which is not a multiple of 4", this.ID, (int)data.Length)); } DBRecordCollection record = new DBRecordCollection(this.ID, this.RecordType); // Create a memory stream to read the binary data using (BinaryReader inReader = new BinaryReader(new MemoryStream(data, false))) { int i = 0; while (i < numberOfDWords) { short dataType = inReader.ReadInt16(); short valCount = inReader.ReadInt16(); int variableID = inReader.ReadInt32(); string variableName = arzFile.Getstring(variableID); if (variableName == null) { // Turn on debugging so we can log the exception. if (!TQDebug.DebugEnabled) { TQDebug.DebugEnabled = true; } TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Error in ARZFile - {0}", arzFile.fileName)); TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Error while parsing arz record {0}, variable is NULL", this.ID)); throw new ArgumentNullException(string.Format(CultureInfo.InvariantCulture, "Error while parsing arz record {0}, variable is NULL", this.ID)); } if (dataType < 0 || dataType > 3) { // Turn on debugging so we can log the exception. if (!TQDebug.DebugEnabled) { TQDebug.DebugEnabled = true; } TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Error in ARZFile - {0}", arzFile.fileName)); TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Error while parsing arz record {0}, variable {1}, bad dataType {2}", this.ID, variableName, dataType)); throw new ArgumentOutOfRangeException(string.Format(CultureInfo.InvariantCulture, "Error while parsing arz record {0}, variable {1}, bad dataType {2}", this.ID, variableName, dataType)); } Variable v = new Variable(variableName, (VariableDataType)dataType, valCount); if (valCount < 1) { // Turn on debugging so we can log the exception. if (!TQDebug.DebugEnabled) { TQDebug.DebugEnabled = true; } TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Error in ARZFile - {0}", arzFile.fileName)); TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Error while parsing arz record {0}, variable {1}, bad valCount {2}", this.ID, variableName, valCount)); throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Error while parsing arz record {0}, variable {1}, bad valCount {2}", this.ID, variableName, valCount)); } // increment our dword count i += 2 + valCount; for (int j = 0; j < valCount; ++j) { switch (v.DataType) { case VariableDataType.Integer: case VariableDataType.Boolean: { int val = inReader.ReadInt32(); v[j] = val; break; } case VariableDataType.Float: { float val = inReader.ReadSingle(); v[j] = val; break; } case VariableDataType.StringVar: { int id = inReader.ReadInt32(); string val = arzFile.Getstring(id); if (val == null) { val = string.Empty; } else { val = val.Trim(); } v[j] = val; break; } default: { int val = inReader.ReadInt32(); v[j] = val; break; } } } record.Set(v); } } return(record); }