public void ParseTable(UTF_File table, string tableName, Version version, bool throwExIfNewColumn)
        {
            if (Name != tableName)
            {
                throw new InvalidOperationException("AcbFormatHelperTable.ParseTable: table name does not match!");
            }

            //Check if they exist
            foreach (var utfColumn in table.Columns)
            {
                if (utfColumn.Name == "MusicPackageType" && utfColumn.TypeFlag == TypeFlag.Int32)
                {
                    continue;                                                                               //Is MusicPackage, a column added by ACE. Skip this.
                }
                var column = GetColumn(utfColumn.Name, utfColumn.TypeFlag, throwExIfNewColumn, table.Columns.IndexOf(utfColumn));
                column.SetExists(version);
            }

            //Check if they dont exist
            foreach (var column in Columns)
            {
                var utfColumn = table.GetColumn(column.Name);

                if (utfColumn != null)
                {
                    if (utfColumn.TypeFlag == column.ValueType)
                    {
                        continue;
                    }
                }

                //Doesn't exist
                column.SetDoesNotExist(version);
            }
        }
Exemple #2
0
        public AWB_CPK(AFS2_File afs2File, UTF_File cpkHeader)
        {
            CPK_Header = cpkHeader;

            foreach (var entry in afs2File.Entries.OrderBy(x => x.AwbId))
            {
                Entries.Add(new CPK_Entry(entry.AwbId, entry.bytes));
            }
        }
        public UTF_File CreateTable(Version version, string name)
        {
            UTF_File table = new UTF_File(name);

            foreach (var column in Columns)
            {
                if (column.DoesExist(version))
                {
                    table.Columns.Add(new UTF_Column(column.Name, column.ValueType));
                }
            }

            return(table);
        }
        public void ParseFiles(string[] filePaths)
        {
            foreach (var file in filePaths)
            {
#if !DEBUG
                try
                {
#endif
                if (Path.GetExtension(file).ToLower() == ".acb")
                {
                    Console.WriteLine($"Parsing \"{file}\"...");
                    byte[]   bytes   = File.ReadAllBytes(file);
                    UTF_File utfFile = UTF_File.LoadUtfTable(bytes, bytes.Length);
                    AcbFormatHelperMain.ParseFile(utfFile, false);
                }
#if !DEBUG
            }
            catch
            {
                Console.WriteLine($"\"{file}\" failed, skipping...");
            }
#endif
            }
        }
 public void ParseFile(UTF_File utfFile)
 {
     AcbFormatHelperMain.ParseFile(utfFile, true);
 }
        public void ParseFile(UTF_File acbFile, bool throwExIfNewColumn)
        {
            Version version = BigEndianConverter.UIntToVersion(acbFile.GetValue <uint>("Version", TypeFlag.UInt32, 0), true);

            AddVersion(version.ToString());

            //Parse tables
            foreach (var column in acbFile.Columns)
            {
#if !DEBUG
                if (ExcludedTables.Contains(column.Name))
                {
                    continue;
                }
#endif

                var tableColumn = (column.Rows[0].UtfTable != null) ? column.Rows[0].UtfTable : column.UtfTable;

                if (tableColumn != null)
                {
                    var table = GetTable(column.Name, throwExIfNewColumn);
                    table.SetExists(version);
                    table.ParseTable(tableColumn, column.Name, version, throwExIfNewColumn);
                }
            }

            //Check if they dont exist
            foreach (var table in Tables)
            {
#if !DEBUG
                if (ExcludedTables.Contains(table.Name))
                {
                    continue;
                }
#endif

                var utfColumn = acbFile.GetColumn(table.Name);

                if (utfColumn != null)
                {
                    byte[]   columnData  = (utfColumn.StorageFlag == StorageFlag.PerRow) ? utfColumn.Rows[0].Bytes : utfColumn.Bytes;
                    UTF_File columnTable = (utfColumn.StorageFlag == StorageFlag.PerRow) ? utfColumn.Rows[0].UtfTable : utfColumn.UtfTable;

                    if (columnTable == null && columnData == null)
                    {
                        continue;                                            //Table does not exist, but there is also no other data... skip
                    }
                    if (columnTable != null)
                    {
                        continue;                      //Table exists
                    }
                    //Handle StreamAwbHash table. This can be a UtfTable or a Byte array depending on ACB version, or if a stream AWB is present (can be null 16 bytes if there is no external AWB, even on newer versions with UtfTable)
                    if (columnTable == null && columnData != null && table.Name == "StreamAwbHash")
                    {
                        bool valid = true;

                        foreach (var _byte in columnData)
                        {
                            if (_byte != 0)
                            {
                                valid = false;
                            }
                        }

                        if (valid)
                        {
                            continue;
                        }
                    }
                }

                //Doesn't exist
                table.SetDoesNotExist(version);
            }


            //Parse all header columns
            Header.ParseTable(acbFile, "Header", version, throwExIfNewColumn);

            //Sort columns
            Sort();
        }
Exemple #7
0
        public static AWB_CPK Load(byte[] bytes, int offset, int length)
        {
            AWB_CPK cpk = new AWB_CPK();

            using (MemoryStream stream = new MemoryStream(bytes, offset, length))
            {
                //CPK Header
                if (stream.ReadInt32() != CPK_SIGNATURE)
                {
                    throw new InvalidDataException("CPK Signature not found.");
                }

                cpk.CPK_Unk1 = stream.ReadInt32();
                ulong cpkTableSize = stream.ReadUInt32();
                stream.Seek(4, SeekOrigin.Current);

                cpk.CPK_Header = UTF_File.LoadUtfTable(stream.ReadBytes((int)cpkTableSize), (int)cpkTableSize);

                //ITOC Header
                if (cpk.CPK_Header.ColumnHasValue("ItocOffset"))
                {
                    long itocOffset = (long)cpk.CPK_Header.GetValue <ulong>("ItocOffset", TypeFlag.UInt64, 0);
                    if (itocOffset > 0)
                    {
                        stream.Seek(itocOffset, SeekOrigin.Begin);

                        if (stream.ReadInt32() != ITOC_SIGNATURE)
                        {
                            throw new InvalidDataException("ITOC Signature not found.");
                        }

                        cpk.ITOC_Unk1 = stream.ReadInt32();
                        ulong itocTableSize = stream.ReadUInt32();
                        stream.Seek(4, SeekOrigin.Current);

                        cpk.ITOC = UTF_File.LoadUtfTable(stream.ReadBytes((int)itocTableSize), (int)itocTableSize);

                        if (cpk.ITOC.TableName != "CpkItocInfo")
                        {
                            throw new InvalidDataException($"Unexpected ITOC: {cpk.ITOC.TableName}. Cannot continue.");
                        }
                    }
                }

                //TOC
                if (cpk.CPK_Header.ColumnHasValue("TocOffset"))
                {
                    if (cpk.CPK_Header.GetValue <ulong>("TocOffset", TypeFlag.UInt64, 0) != 0)
                    {
                        throw new InvalidDataException($"This cpk has a TOC table, cannot continue.");
                    }
                }

                //ETOC
                if (cpk.CPK_Header.ColumnHasValue("EtocOffset"))
                {
                    if (cpk.CPK_Header.GetValue <ulong>("EtocOffset", TypeFlag.UInt64, 0) != 0)
                    {
                        throw new InvalidDataException($"This cpk has a ETOC table, cannot continue.");
                    }
                }

                //Validate header
                if (!cpk.CPK_Header.ColumnHasValue("Files"))
                {
                    throw new InvalidDataException("\"Files\" column not found or missing value.");
                }

                if (!cpk.CPK_Header.ColumnHasValue("Align"))
                {
                    throw new InvalidDataException("\"Align\" column not found or missing value.");
                }

                if (!cpk.CPK_Header.ColumnHasValue("ContentOffset"))
                {
                    throw new InvalidDataException("\"ContentOffset\" column not found or missing value.");
                }

                uint   numFiles      = cpk.CPK_Header.GetValue <uint>("Files", TypeFlag.UInt32, 0);
                ulong  contentOffset = cpk.CPK_Header.GetValue <ulong>("ContentOffset", TypeFlag.UInt64, 0);
                ushort align         = cpk.CPK_Header.GetValue <ushort>("Align", TypeFlag.UInt16, 0);
                ulong  currentOffset = contentOffset;

                //Validate ITOC
                if (!cpk.ITOC.ColumnHasValue("FilesL") || !cpk.ITOC.ColumnHasValue("FilesH"))
                {
                    throw new InvalidDataException($"\"FilesL\" or \"FilesH\" column not found or missing value.");
                }

                int      numH  = (int)cpk.ITOC.GetValue <uint>("FilesH", TypeFlag.UInt32, 0);
                int      numL  = (int)cpk.ITOC.GetValue <uint>("FilesL", TypeFlag.UInt32, 0);
                UTF_File dataH = cpk.ITOC.GetColumnTable("DataH", true);
                UTF_File dataL = cpk.ITOC.GetColumnTable("DataL", true);

                if (numH + numL != numFiles)
                {
                    throw new InvalidDataException($"FilesH + FilesL does not equal Files. Cannot continue.");
                }

                //Load files
                for (ushort id = 0; id < numFiles; id++)
                {
                    uint fileSize    = 0;
                    uint extractSize = 0;
                    bool found       = false;

                    //DataL seems to be for files of less than 65535 bytes.
                    for (int i = 0; i < numL; i++)
                    {
                        if (dataL.GetValue <ushort>("ID", TypeFlag.UInt16, i) != id)
                        {
                            continue;
                        }

                        fileSize    = dataL.GetValue <ushort>("FileSize", TypeFlag.UInt16, i);
                        extractSize = dataL.GetValue <ushort>("ExtractSize", TypeFlag.UInt16, i);
                        found       = true;
                        break;
                    }

                    if (!found)
                    {
                        for (int i = 0; i < numH; i++)
                        {
                            if (dataH.GetValue <ushort>("ID", TypeFlag.UInt16, i) != id)
                            {
                                continue;
                            }

                            fileSize    = dataH.GetValue <uint>("FileSize", TypeFlag.UInt32, i);
                            extractSize = dataH.GetValue <uint>("ExtractSize", TypeFlag.UInt32, i);
                            found       = true;
                            break;
                        }
                    }

                    if (found)
                    {
                        if (fileSize == 0)
                        {
                            continue;                //null entry
                        }
                        stream.Seek((long)currentOffset, SeekOrigin.Begin);

                        byte[] data = stream.ReadBytes((int)fileSize);

                        if (data.Length > 8)
                        {
                            string isComp = Encoding.ASCII.GetString(data.GetRange(0, 8));

                            if (isComp == "CRILAYLA")
                            {
                                int size = (int)((extractSize > fileSize) ? extractSize : fileSize);
                                data = _cpk.DecompressCRILAYLA(data, size);
                            }
                        }

                        cpk.Entries.Add(new CPK_Entry(id, data));

                        //Increment offset
                        currentOffset += fileSize;

                        if ((currentOffset % align) != 0)
                        {
                            currentOffset += (align - (currentOffset % align));
                        }
                    }
                    else
                    {
                        throw new Exception($"Could not find the file for ID {id} in either \"DataL\" or \"DataH\".");
                    }
                }
            }


            return(cpk);
        }
Exemple #8
0
        public byte[] Write()
        {
            PadWithNullEntries();
            ushort align = CPK_Header.GetValue <ushort>("Align", TypeFlag.UInt16, 0);

            List <byte> bytes        = new List <byte>();
            List <byte> contentBytes = new List <byte>();

            //Update header
            ulong contentOffset = 0x800;
            ulong contentSize   = GetContentSize();

            CPK_Header.SetValue("Files", (uint)Entries.Count, TypeFlag.UInt32, 0);
            CPK_Header.SetValue("ContentOffset", contentOffset, TypeFlag.UInt64, 0);
            CPK_Header.SetValue("ContentSize", contentSize, TypeFlag.UInt64, 0);
            CPK_Header.SetValue("ItocOffset", contentOffset + contentSize, TypeFlag.UInt64, 0);

            //ITOC
            int numH = 0;
            int numL = 0;

            //Create DataL/DataH tables
            UTF_File dataH = new UTF_File("CpkItocH");
            UTF_File dataL = new UTF_File("CpkItocL");

            dataL.Columns.Add(new UTF_Column("ID", TypeFlag.UInt16, StorageFlag.PerRow));
            dataL.Columns.Add(new UTF_Column("FileSize", TypeFlag.UInt16, StorageFlag.PerRow));
            dataL.Columns.Add(new UTF_Column("ExtractSize", TypeFlag.UInt16, StorageFlag.PerRow));
            dataH.Columns.Add(new UTF_Column("ID", TypeFlag.UInt16, StorageFlag.PerRow));
            dataH.Columns.Add(new UTF_Column("FileSize", TypeFlag.UInt32, StorageFlag.PerRow));
            dataH.Columns.Add(new UTF_Column("ExtractSize", TypeFlag.UInt32, StorageFlag.PerRow));

            foreach (var entry in Entries)
            {
                if (entry.Data.Length > ushort.MaxValue)
                {
                    dataH.AddValue("FileSize", TypeFlag.UInt32, numH, entry.Data.Length.ToString());
                    dataH.AddValue("ExtractSize", TypeFlag.UInt32, numH, entry.Data.Length.ToString());
                    dataH.AddValue("ID", TypeFlag.UInt16, numH, entry.ID.ToString());
                    numH++;
                }
                else
                {
                    dataL.AddValue("FileSize", TypeFlag.UInt16, numL, entry.Data.Length.ToString());
                    dataL.AddValue("ExtractSize", TypeFlag.UInt16, numL, entry.Data.Length.ToString());
                    dataL.AddValue("ID", TypeFlag.UInt16, numL, entry.ID.ToString());
                    numL++;
                }

                //Write data
                if (entry.Data.Length > 0)
                {
                    contentBytes.AddRange(entry.Data);

                    if ((contentBytes.Count % align) != 0)
                    {
                        contentBytes.AddRange(new byte[(align - (contentBytes.Count % align))]);
                    }
                }
            }

            //Create ITOC table
            ITOC           = new UTF_File();
            ITOC.TableName = "CpkItocInfo";
            ITOC.Columns.Add(new UTF_Column("FilesL", TypeFlag.UInt32, StorageFlag.PerRow));
            ITOC.Columns.Add(new UTF_Column("FilesH", TypeFlag.UInt32, StorageFlag.PerRow));
            ITOC.Columns.Add(new UTF_Column("DataL", TypeFlag.Data, StorageFlag.PerRow));
            ITOC.Columns.Add(new UTF_Column("DataH", TypeFlag.Data, StorageFlag.PerRow));

            ITOC.AddValue("FilesL", TypeFlag.UInt32, 0, numL.ToString());
            ITOC.AddValue("FilesH", TypeFlag.UInt32, 0, numH.ToString());
            ITOC.AddData("DataL", 0, dataL.Write());
            ITOC.AddData("DataH", 0, dataH.Write());

            //Create file
            byte[] itocBytes = ITOC.Write();
            CPK_Header.SetValue("ItocSize", itocBytes.Length, TypeFlag.UInt64, 0);
            byte[] headerBytes = CPK_Header.Write();

            bytes.AddRange(BitConverter.GetBytes(CPK_SIGNATURE));
            bytes.AddRange(BitConverter.GetBytes(CPK_Unk1));
            bytes.AddRange(BitConverter.GetBytes((ulong)headerBytes.Length));
            bytes.AddRange(headerBytes);
            bytes.AddRange(new byte[2040 - bytes.Count]);
            bytes.AddRange(BitConverter.GetBytes((ulong)CRI_SIGNATURE));

            if (bytes.Count != 0x800)
            {
                throw new InvalidDataException("CPK header is wrong size.");
            }

            bytes.AddRange(contentBytes);
            bytes.AddRange(BitConverter.GetBytes(ITOC_SIGNATURE));
            bytes.AddRange(BitConverter.GetBytes(ITOC_Unk1));
            bytes.AddRange(BitConverter.GetBytes((ulong)itocBytes.Length));
            bytes.AddRange(itocBytes);

            return(bytes.ToArray());
        }