/// <summary> /// Parse the file table. /// </summary> /// <returns>Number of files found.</returns> public override int ParseFileTable() { // Set correct position for data section long offset = this.tableOffset; int[] tableItemStart = new int[this.numFiles]; for (int i = 0; i < this.numFiles; i++) { tableItemStart[i] = StreamUtility.ReadIntFromStream(this.container, offset, false); offset += 4; } long listOffset = offset; this.fileTable = new List <FileItem>(); for (int i = 0; i < this.numFiles; i++) { offset = listOffset + tableItemStart[i]; FileItem item = new FileItem(this.container); item.FileOffset = StreamUtility.ReadUIntFromStream(this.container, offset, false) + this.dataOffset; item.FileSize = StreamUtility.ReadUIntFromStream(this.container, offset + 4, false); item.FileName = StreamUtility.ReadStringFromStream(this.container, offset + 8, -1, 0x00); item.FileName = item.FileName.Replace('\\', '+'); this.fileTable.Add(item); } return(fileTable.Count); }
/// <summary> /// Parse the file table. /// </summary> /// <returns>Number of files found.</returns> public override int ParseFileTable() { long offset = this.tableOffset; int tableLength = this.numFiles * this.tableItemSize; long fileOffset = this.tableOffset + tableLength; this.fileTable = new List <FileItem>(); for (int i = 0; i < this.numFiles; i++) { FileItem item = new FileItem(this.container); item.FileSize = StreamUtility.ReadUIntFromStream(this.container, offset); item.FileName = StreamUtility.ReadStringFromStream(this.container, offset + 4, -1); item.FileOffset = fileOffset; offset += this.tableItemSize; fileOffset += item.FileSize; fileTable.Add(item); } return(fileTable.Count); }
public static CriPack_UTF ByteUnpack(byte[] stream) { if (stream == null || stream.Length < 4) { return(null); } if (stream[0] != 0x40 || // @ stream[1] != 0x55 || // U stream[2] != 0x54 || // T stream[3] != 0x46) // F { stream = CriPack_UTF.Decrypt(stream); } using (MemoryStream buffer = new MemoryStream(stream)) { CriPack_UTF utf = new CriPack_UTF(); long offset = 4; utf.payloadSize = StreamUtility.ReadUIntFromStream(buffer, offset); offset += 4; utf.dataBankOffset = StreamUtility.ReadUIntFromStream(buffer, offset) + 8; offset += 4; utf.stringBankOffset = StreamUtility.ReadUIntFromStream(buffer, offset) + 8; offset += 4; utf.endOfPayloadOffset = StreamUtility.ReadUIntFromStream(buffer, offset) + 8; offset += 4; // Optional check if (utf.endOfPayloadOffset != (utf.payloadSize + 8)) { MessageBox.Show("End of UTF Payload (" + String.Format("0x{0:X4}", utf.endOfPayloadOffset) + ") " + "does not match UTF Payload Size (" + String.Format("0x{0:X4}", utf.payloadSize + 8) + ")", "Warning", MessageBoxButtons.OK); } int nameOffset = StreamUtility.ReadIntFromStream(buffer, offset); offset += 4; uint temp = StreamUtility.ReadUIntFromStream(buffer, offset); offset += 4; int numProperties = (int)((temp >> 16) & 0xff); utf.itemDataLength = (int)(temp & 0xff); utf.numItem = StreamUtility.ReadIntFromStream(buffer, offset); offset += 4; // Optional check if ((utf.itemDataLength * utf.numItem) != (utf.stringBankOffset - utf.dataBankOffset)) { MessageBox.Show( String.Format("Calculated data bank size (0x{0:X4}) does not match specified size (0x{1:X4})", utf.stringBankOffset - utf.dataBankOffset, utf.itemDataLength * utf.numItem), "Warning", MessageBoxButtons.OK); } { // Extract string bank int address = (int)utf.stringBankOffset; utf.stringBank = new Dictionary <int, string>(); while (address < utf.endOfPayloadOffset) { string value = StreamUtility.ReadStringFromStream(buffer, address, 0); utf.stringBank.Add((address - (int)utf.stringBankOffset), value); address += value.Length + 1; } } // Get name of this UTF utf.name = utf.GetStringFromBank(nameOffset); // Extract items utf.properties = new CriPack_UTFProperty[utf.numItem][]; for (int i = 0; i < utf.numItem; i++) { // Extract properties utf.properties[i] = new CriPack_UTFProperty[numProperties]; long itemOffset = offset; int dataBankCursor = (int)utf.dataBankOffset + utf.itemDataLength * i; for (int p = 0; p < numProperties; p++) { // Read flag byte[] bytes = StreamUtility.ReadBytesFromStream(buffer, itemOffset, 1); itemOffset += 1; byte flag = bytes[0]; // Determine storage and type CriPack_UTFProperty property = new CriPack_UTFProperty(); property.storage = (CriPack_DataStorage)(flag & (byte)CriPack_DataStorage.MASK); property.type = (CriPack_DataType)(flag & (byte)CriPack_DataType.MASK); if (property.storage == CriPack_DataStorage.UNDEFINED) { throw new NotSupportedException(String.Format("Unrecognized storage location: 0x{0:X4}", (byte)property.storage)); } // Extract name of the property { int address = StreamUtility.ReadIntFromStream(buffer, itemOffset); itemOffset += 4; property.name = utf.GetStringFromBank(address); } // Extract value if (property.storage == CriPack_DataStorage.NONE) { // No value associated } else if (property.storage == CriPack_DataStorage.STRING) { // String value int address = StreamUtility.ReadIntFromStream(buffer, itemOffset); itemOffset += 4; property.value = utf.GetStringFromBank(address); } else if (property.storage == CriPack_DataStorage.DATA) { int address; // Data value specified by 'type' switch (property.type) { case CriPack_DataType.UNSIGNED_BYTE: case CriPack_DataType.SIGNED_BYTE: bytes = StreamUtility.ReadBytesFromStream(buffer, dataBankCursor, 1); dataBankCursor += 1; property.value = bytes[0]; break; case CriPack_DataType.UNSIGNED_SHORT: bytes = StreamUtility.ReadBytesFromStream(buffer, dataBankCursor, 2); dataBankCursor += 2; Array.Reverse(bytes); // Change endian property.value = BitConverter.ToUInt16(bytes, 0); break; case CriPack_DataType.SIGNED_SHORT: bytes = StreamUtility.ReadBytesFromStream(buffer, dataBankCursor, 2); dataBankCursor += 2; Array.Reverse(bytes); // Change endian property.value = BitConverter.ToInt16(bytes, 0); break; case CriPack_DataType.UNSIGNED_INT: property.value = StreamUtility.ReadUIntFromStream(buffer, dataBankCursor); dataBankCursor += 4; break; case CriPack_DataType.SIGNED_INT: property.value = StreamUtility.ReadIntFromStream(buffer, dataBankCursor); dataBankCursor += 4; break; case CriPack_DataType.UNSIGNED_LONG: bytes = StreamUtility.ReadBytesFromStream(buffer, dataBankCursor, 8); dataBankCursor += 8; Array.Reverse(bytes); // Change endian property.value = BitConverter.ToUInt64(bytes, 0); break; case CriPack_DataType.SIGNED_LONG: bytes = StreamUtility.ReadBytesFromStream(buffer, dataBankCursor, 8); dataBankCursor += 8; Array.Reverse(bytes); // Change endian property.value = BitConverter.ToInt64(bytes, 0); break; case CriPack_DataType.FLOAT: bytes = StreamUtility.ReadBytesFromStream(buffer, dataBankCursor, 4); dataBankCursor += 4; Array.Reverse(bytes); // Change endian property.value = BitConverter.ToSingle(bytes, 0); break; case CriPack_DataType.DOUBLE: bytes = StreamUtility.ReadBytesFromStream(buffer, dataBankCursor, 8); dataBankCursor += 8; Array.Reverse(bytes); // Change endian property.value = BitConverter.ToDouble(bytes, 0); break; case CriPack_DataType.STRING: address = StreamUtility.ReadIntFromStream(buffer, dataBankCursor); dataBankCursor += 4; property.value = utf.GetStringFromBank(address); break; case CriPack_DataType.DATA: address = StreamUtility.ReadIntFromStream(buffer, dataBankCursor); dataBankCursor += 4; int size = StreamUtility.ReadIntFromStream(buffer, dataBankCursor); dataBankCursor += 4; // Assume this is another table bytes = StreamUtility.ReadBytesFromStream(buffer, address, size); property.value = CriPack_UTF.ByteUnpack(bytes); break; default: property.value = null; break; } } utf.properties[i][p] = property; } } return(utf); } }
/// <summary> /// Parse the file table. /// </summary> /// <returns>Number of files found.</returns> public override int ParseFileTable() { long offset = 8; uint fid = 0; this.fileTable = new List <FileItem>(); string fileNameBase; { // Get file name base int fileNameStart = this.container.Name.LastIndexOf('\\') + 1; int fileNameEnd = this.container.Name.LastIndexOf('.'); if (fileNameEnd == -1) { fileNameEnd = this.container.Name.Length; } fileNameBase = this.container.Name.Substring(fileNameStart, fileNameEnd - fileNameStart); } while (true) { AfsFileItem item = new AfsFileItem(); item.fileId = fid; item.startOffset = StreamUtility.ReadUIntFromStream(this.container, offset, false); offset += 4; item.length = StreamUtility.ReadUIntFromStream(this.container, offset, false); offset += 4; if (item.isValid()) { FileItem fileItem = ConvertAfsToGeneral(item, fileNameBase + "-" + Convert.ToSingle(item.fileId)); uint fileIdentifier = StreamUtility.ReadUIntFromStream(this.container, fileItem.FileOffset); string fileExt = StreamUtility.GetFileExtension(fileIdentifier); fileItem.FileName += "." + fileExt; fileTable.Add(fileItem); } else { break; } fid++; } if (fileTable.Count == this.numFiles + 1) { // The last one is the file property table. FileItem fileItem = fileTable[fileTable.Count - 1]; offset = fileItem.FileOffset; // Retrieve file names for (int i = 0; i < this.numFiles; i++) { fileTable[i].FileName = StreamUtility.ReadStringFromStream(this.container, offset, -1); offset += 0x30; } // Remove the file property table fileTable.RemoveAt(fileTable.Count - 1); } if (fileTable.Count != this.numFiles) { throw new FormatException(this.container.Name + ": The real number of files doesn't match the header value!" + System.Environment.NewLine + "The header indicated: " + Convert.ToString(this.numFiles) + System.Environment.NewLine + "The real number of files: " + Convert.ToString(fileTable.Count)); } return(fileTable.Count); }