Beispiel #1
0
 /// <summary>
 /// Assign properties from TOC.
 /// </summary>
 /// <param name="properties">Property bank in TOC.</param>
 public void AssignTocProperties(CriPack_UTFProperty[] properties, long tocOffset)
 {
     this.DirName     = (string)CriPack_UTF.GetPropertyValue(properties, "DirName");
     this.FileName    = (string)CriPack_UTF.GetPropertyValue(properties, "FileName");
     this.FileSize    = (uint)CriPack_UTF.GetPropertyValue(properties, "FileSize");
     this.ExtractSize = (uint)CriPack_UTF.GetPropertyValue(properties, "ExtractSize");
     this.FileOffset  = tocOffset + (long)(ulong)CriPack_UTF.GetPropertyValue(properties, "FileOffset");
     this.FileId      = (uint)CriPack_UTF.GetPropertyValue(properties, "ID");
     this.UserString  = (string)CriPack_UTF.GetPropertyValue(properties, "UserString");
     this.CRC         = (uint)CriPack_UTF.GetPropertyValue(properties, "CRC");
 }
        /// <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);
        }
Beispiel #3
0
        /// <summary>
        /// Assign properties from E-TOC.
        /// </summary>
        /// <param name="properties">Property bank in E-TOC.</param>
        public void AssignEtocProperties(CriPack_UTFProperty[] properties)
        {
            this.localDir = (string)CriPack_UTF.GetPropertyValue(properties, "LocalDir");
            ulong timestamp = (ulong)CriPack_UTF.GetPropertyValue(properties, "UpdateDateTime");
            // Convert time
            int timeYear   = (int)((timestamp >> 48) & 0xffff);
            int timeMonth  = (int)((timestamp >> 40) & 0xff);
            int timeDay    = (int)((timestamp >> 32) & 0xff);
            int timeHour   = (int)((timestamp >> 24) & 0xff);
            int timeMinute = (int)((timestamp >> 16) & 0xff);
            int timeSecond = (int)((timestamp >> 8) & 0xff);

            this.fileDate = new DateTime(timeYear, timeMonth, timeDay, timeHour, timeMinute, timeSecond);
        }
        /// <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");
        }
        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 object GetPropertyValue(int index, string name)
 {
     return(CriPack_UTF.GetPropertyValue(this.properties[index], name));
 }