Exemplo n.º 1
0
        // initialize from existing CPK
        public CpkBuilder(DuplicatableStream stream, Endianness endian = Endianness.BigEndian)
        {
            // should start with CPK and some unknown header bytes
            long cpkHeaderOffset = stream.Position;
            uint cpkMagic        = stream.ReadUInt32(Endianness.LittleEndian);

            if (cpkMagic != 0x204B5043)
            {
                throw new Exception("wrong CPK magic");
            }

            UnknownCpkHeaderBytes = stream.ReadBytes(12);

            // main UTF table should follow
            MainUtfTable = new UtfBuilder(stream, endian);
            if (MainUtfTable.Rows.Count != 1)
            {
                throw new Exception("wrong rowcount in main UTF table");
            }

            UnknownPostCpkHeaderBytes = stream.ReadBytes(4);
            while (stream.ReadByte() == 0)
            {
                ;
            }
            stream.Position = stream.Position - 1;
            CopyrightText   = stream.ReadBytes(stream.Position.Align(0x800, cpkHeaderOffset) - stream.Position);           // or something

            ulong tocOffset = (ulong)MainUtfTable.Rows[0].Cells[MainUtfTable.FindColumnIndex("TocOffset")].Data;

            //ulong tocSize = (ulong)MainUtfTable.Rows[0].Cells[MainUtfTable.FindColumnIndex("TocSize")].Data;
            if (tocOffset != 0)
            {
                stream.Position = cpkHeaderOffset + (long)tocOffset;
                uint magic = stream.ReadUInt32(Endianness.LittleEndian);
                if (magic != 0x20434F54)
                {
                    throw new Exception("wrong TOC magic");
                }
                UnknownTocHeaderBytes = stream.ReadBytes(12);
                TocUtfTable           = new UtfBuilder(stream, endian);
            }

            ulong itocOffset = (ulong)MainUtfTable.Rows[0].Cells[MainUtfTable.FindColumnIndex("ItocOffset")].Data;

            //ulong itocSize = (ulong)MainUtfTable.Rows[0].Cells[MainUtfTable.FindColumnIndex("ItocSize")].Data;
            if (itocOffset != 0)
            {
                stream.Position = cpkHeaderOffset + (long)itocOffset;
                uint magic = stream.ReadUInt32(Endianness.LittleEndian);
                if (magic != 0x434F5449)
                {
                    throw new Exception("wrong ITOC magic");
                }
                UnknownItocHeaderBytes = stream.ReadBytes(12);
                ItocUtfTable           = new UtfBuilder(stream, endian);
            }

            ulong etocOffset = (ulong)MainUtfTable.Rows[0].Cells[MainUtfTable.FindColumnIndex("EtocOffset")].Data;

            //ulong etocSize = (ulong)MainUtfTable.Rows[0].Cells[MainUtfTable.FindColumnIndex("EtocSize")].Data;
            if (etocOffset != 0)
            {
                stream.Position = cpkHeaderOffset + (long)etocOffset;
                uint magic = stream.ReadUInt32(Endianness.LittleEndian);
                if (magic != 0x434F5445)
                {
                    throw new Exception("wrong ETOC magic");
                }
                UnknownEtocHeaderBytes = stream.ReadBytes(12);
                EtocUtfTable           = new UtfBuilder(stream, endian);
            }

            ulong gtocOffset = (ulong)MainUtfTable.Rows[0].Cells[MainUtfTable.FindColumnIndex("GtocOffset")].Data;

            //ulong gtocSize = (ulong)MainUtfTable.Rows[0].Cells[MainUtfTable.FindColumnIndex("GtocSize")].Data;
            if (gtocOffset != 0)
            {
                // haven't actually seen this, but would make sense...
                stream.Position = cpkHeaderOffset + (long)gtocOffset;
                uint magic = stream.ReadUInt32(Endianness.LittleEndian);
                if (magic != 0x434F5447)
                {
                    throw new Exception("wrong GTOC magic");
                }
                UnknownGtocHeaderBytes = stream.ReadBytes(12);
                GtocUtfTable           = new UtfBuilder(stream, endian);
            }

            ulong contentOffset = (ulong)MainUtfTable.Rows[0].Cells[MainUtfTable.FindColumnIndex("ContentOffset")].Data;
            //ulong contentSize = (ulong)MainUtfTable.Rows[0].Cells[MainUtfTable.FindColumnIndex("ContentSize")].Data;
            uint fileCount = (uint)MainUtfTable.Rows[0].Cells[MainUtfTable.FindColumnIndex("Files")].Data;

            if (TocUtfTable == null || TocUtfTable.Rows.Count != fileCount)
            {
                throw new Exception("invalid TOC?");
            }

            Files = new List <CpkFile>((int)fileCount);
            int  columnDirName     = TocUtfTable.FindColumnIndex("DirName");
            int  columnFileName    = TocUtfTable.FindColumnIndex("FileName");
            int  columnFileSize    = TocUtfTable.FindColumnIndex("FileSize");
            int  columnExtractSize = TocUtfTable.FindColumnIndex("ExtractSize");
            int  columnFileOffset  = TocUtfTable.FindColumnIndex("FileOffset");
            int  columnFileIndexId = TocUtfTable.FindColumnIndex("ID");
            long baseFileOffset    = cpkHeaderOffset + ((contentOffset < tocOffset) ? (long)contentOffset : (long)tocOffset);

            for (int i = 0; i < (int)fileCount; ++i)
            {
                var f = new CpkFile();
                f.Directory = (string)TocUtfTable.Rows[i].Cells[columnDirName].Data;
                f.Name      = (string)TocUtfTable.Rows[i].Cells[columnFileName].Data;
                uint fileSize = (uint)TocUtfTable.Rows[i].Cells[columnFileSize].Data;
                f.DecompressedSize = (uint)TocUtfTable.Rows[i].Cells[columnExtractSize].Data;
                ulong fileOffset = (ulong)TocUtfTable.Rows[i].Cells[columnFileOffset].Data;
                f.FileStream = new HyoutaUtils.Streams.PartialStream(stream, baseFileOffset + (long)fileOffset, fileSize);
                f.ID         = (uint)TocUtfTable.Rows[i].Cells[columnFileIndexId].Data;
                Files.Add(f);
            }

            return;
        }