/// <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> /// Construct a AXCS file. /// </summary> /// <param name="file">File stream.</param> public AxcsContainer(FileStream file) : base(file) { long offset = 0; // Confirm 'AXCS' identifier uint identifier = StreamUtility.ReadUIntFromStream(this.container, offset); offset += 4; if (identifier != 0x53435841) // If file identifier is not AXCS { throw new FormatException(container.Name + ": File is not AXCS format!"); } // Get the next value this.dataOffset = StreamUtility.ReadIntFromStream(this.container, offset, false); offset += 4; // Get number of files this.numFiles = StreamUtility.ReadUIntFromStream(this.container, offset, false); offset += 4; // Get file table position this.tableOffset = offset; this.containerType = "AXCS archive container"; }
/// <summary> /// Parse the file table. /// </summary> /// <returns>Number of files found.</returns> public override int ParseFileTable() { this.fileTable = new List <FileItem>(); // Extract TOC { uint identifier = StreamUtility.ReadUIntFromStream(this.container, this.tableOffset); if (identifier != 0x544f4320) // TOC { throw new FormatException(container.Name + ": Checking TOC identified failed!"); } // Get UTF length int tocLength = StreamUtility.ReadIntFromStream(this.container, this.tableOffset + 0x8, false); byte[] tocBytes = StreamUtility.ReadBytesFromStream(this.container, this.tableOffset + 0x10, tocLength); this.toc = CriPack_UTF.ByteUnpack(tocBytes); } // Extract E-TOC (Extended TOC) try { long etocOffset = (long)(ulong)this.header.GetPropertyValue(0, "EtocOffset"); uint identifier = StreamUtility.ReadUIntFromStream(this.container, etocOffset); if (identifier != 0x45544f43) // ETOC { throw new FormatException(container.Name + ": Checking E-TOC identified failed!"); } // Get UTF length int etocLength = StreamUtility.ReadIntFromStream(this.container, etocOffset + 0x8, false); byte[] etocBytes = StreamUtility.ReadBytesFromStream(this.container, etocOffset + 0x10, etocLength); this.etoc = CriPack_UTF.ByteUnpack(etocBytes); } catch (KeyNotFoundException e) { } // No E-TOC for (int i = 0; i < toc.properties.Length; i++) { CriPackFileItem item = new CriPackFileItem(this.container); item.AssignTocProperties(toc.properties[i], this.tableOffset); if (this.etoc != null) { item.AssignEtocProperties(etoc.properties[i]); } fileTable.Add(item); } return(fileTable.Count); }
/// <summary> /// Construct a CriPack file. /// </summary> /// <param name="file">File stream.</param> public CriPack_Container(FileStream file) : base(file) { long offset = 0; // Confirm 'CriPack' identifier uint identifier = StreamUtility.ReadUIntFromStream(this.container, offset); offset += 4; if (identifier != 0x43504b20) // If file identifier is not CriPack { throw new FormatException(container.Name + ": File is not CriPack format!"); } // Get UTF length offset += 4; int headerLength = StreamUtility.ReadIntFromStream(this.container, offset, false); offset += 4; // Zero padding, ignore offset += 4; this.containerType = "CRI Pack Container"; //byte[] utfHeader = StreamUtility.ReadBytesFromStream(this.container, offset, (int)this.utfLength); //MessageBox.Show("CRC32 of UTF: " + String.Format("0x{0:X4}", Crc32.Compute(0xedb88320, 0xffffffff, utfHeader)), "Info", MessageBoxButtons.OK); //MessageBox.Show("CRC32 of UTF: " + String.Format("0x{0:X4}", Crc32.Compute(0x04C11DB7, 0xffffffff, utfHeader)), "Info", MessageBoxButtons.OK); //utfHeader = StreamUtility.ReadBytesFromStream(this.container, offset + 8, (int)this.utfLength - 8); //MessageBox.Show("CRC32 of UTF: " + String.Format("0x{0:X4}", Crc32.Compute(0xedb88320, 0xffffffff, utfHeader)), "Info", MessageBoxButtons.OK); //MessageBox.Show("CRC32 of UTF: " + String.Format("0x{0:X4}", Crc32.Compute(0x04C11DB7, 0xffffffff, utfHeader)), "Info", MessageBoxButtons.OK); //utfHeader = StreamUtility.ReadBytesFromStream(this.container, offset - 8, (int)this.utfLength + 8); //MessageBox.Show("CRC32 of UTF: " + String.Format("0x{0:X4}", Crc32.Compute(0xedb88320, 0xffffffff, utfHeader)), "Info", MessageBoxButtons.OK); //MessageBox.Show("CRC32 of UTF: " + String.Format("0x{0:X4}", Crc32.Compute(0x04C11DB7, 0xffffffff, utfHeader)), "Info", MessageBoxButtons.OK); //utfHeader = StreamUtility.ReadBytesFromStream(this.container, offset - 16, (int)this.utfLength + 16); //MessageBox.Show("CRC32 of UTF: " + String.Format("0x{0:X4}", Crc32.Compute(0xedb88320, 0xffffffff, utfHeader)), "Info", MessageBoxButtons.OK); //MessageBox.Show("CRC32 of UTF: " + String.Format("0x{0:X4}", Crc32.Compute(0x04C11DB7, 0xffffffff, utfHeader)), "Info", MessageBoxButtons.OK); //utfHeader = StreamUtility.ReadBytesFromStream(this.container, offset + 4, (int)this.utfLength - 4); //MessageBox.Show("CRC32 of UTF: " + String.Format("0x{0:X4}", Crc32.Compute(0xedb88320, 0xffffffff, utfHeader)), "Info", MessageBoxButtons.OK); //MessageBox.Show("CRC32 of UTF: " + String.Format("0x{0:X4}", Crc32.Compute(0x04C11DB7, 0xffffffff, utfHeader)), "Info", MessageBoxButtons.OK); byte[] headerBytes = StreamUtility.ReadBytesFromStream(this.container, offset, headerLength); this.header = CriPack_UTF.ByteUnpack(headerBytes); this.tableOffset = (long)(ulong)this.header.GetPropertyValue(0, "TocOffset"); }
/// <summary> /// Construct a Cwab file. /// </summary> /// <param name="file">File stream.</param> public CwabContainer(FileStream file) : base(file) { long offset = 0; // Confirm 'CWAB' identifier uint identifier = StreamUtility.ReadUIntFromStream(this.container, offset); offset += 4; if (identifier != 0x43574142) // If file identifier is not CWAB { throw new FormatException(container.Name + ": File is not CWAB format!"); } // Get number of files this.numFiles = StreamUtility.ReadIntFromStream(this.container, offset); offset += 4; // Set file table position this.tableOffset = offset; this.containerType = "CWAB Animation Package"; }
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); } }
public long DecompressToFile(FileStream toFile) { long offset = this.fileOffset; // Check identifier ulong identifier = StreamUtility.ReadULongFromStream(this.file, offset); if (identifier != 0 && identifier != 0x4352494c41594c41) { throw new FormatException("File is not compressed by CRILAYLA!"); } int decompSize = StreamUtility.ReadIntFromStream(this.file, offset + 0x8); long decompHeaderOffset = StreamUtility.ReadUIntFromStream(this.file, offset + 0xC) + offset + 0x10; if (decompHeaderOffset + 0x100 != offset + this.fileSize) { throw new FormatException("Size mismatch!"); } // Extract real header StreamUtility.CopyBlock(this.file, toFile, decompHeaderOffset, 0x100); //const long input_end = offset + input_size - 0x100 - 1; //long input_offset = input_end; //const long output_end = 0x100 + uncompressed_size - 1; //uint8_t bit_pool = 0; //int bits_left = 0; //long bytes_output = 0; //while ( bytes_output < uncompressed_size ) //{ // if (GET_NEXT_BITS(1)) // { // long backreference_offset = // output_end-bytes_output+GET_NEXT_BITS(13)+3; // long backreference_length = 3; // // decode variable length coding for length // enum { vle_levels = 4 }; // int vle_lens[vle_levels] = { 2, 3, 5, 8 }; // int vle_level; // for (vle_level = 0; vle_level < vle_levels; vle_level++) // { // int this_level = GET_NEXT_BITS(vle_lens[vle_level]); // backreference_length += this_level; // if (this_level != ((1 << vle_lens[vle_level])-1)) break; // } // if (vle_level == vle_levels) // { // int this_level; // do // { // this_level = GET_NEXT_BITS(8); // backreference_length += this_level; // } while (this_level == 255); // } // //printf("0x%08lx backreference to 0x%lx, length 0x%lx\n", output_end-bytes_output, backreference_offset, backreference_length); // for (int i=0;i<backreference_length;i++) // { // output_buffer[output_end-bytes_output] = output_buffer[backreference_offset--]; // bytes_output++; // } // } // else // { // // verbatim byte // output_buffer[output_end-bytes_output] = GET_NEXT_BITS(8); // //printf("0x%08lx verbatim byte\n", output_end-bytes_output); // bytes_output++; // } //} //put_bytes_seek(0, outfile, output_buffer, 0x100 + uncompressed_size); //free(output_buffer); return(0x100 + decompSize); }