Exemple #1
0
        private Directory BuildContentTree(Stream stream, GENESTRT nameTable, PACKTOC toc, PACKTOC.DirectoryEntry dirEnt)
        {
            Directory dir = new Directory(nameTable.Strings[(int)dirEnt.NameIndex]);

            for (uint i = dirEnt.FirstEntryIndex; i < dirEnt.FirstEntryIndex + dirEnt.NumEntries; i++)
            {
                PACKTOC.Entry entry = toc.Entries[(int)i];
                string        name  = nameTable.Strings[(int)entry.NameIndex];

                if (entry is PACKTOC.UncompressedFileEntry uFileEntry)
                {
                    byte[] rawData = new byte[uFileEntry.Size];
                    stream.Seek((long)uFileEntry.Offset, SeekOrigin.Begin);
                    stream.Read(rawData);

                    dir.Children.Add(new File(name, rawData, false, uFileEntry.Size));
                }
                else if (entry is PACKTOC.DirectoryEntry directoryEntry)
                {
                    dir.Children.Add(this.BuildContentTree(stream, nameTable, toc, directoryEntry));
                }
                else if (entry is PACKTOC.CompressedFileEntry cFileEntry)
                {
                    byte[] rawData = new byte[cFileEntry.CompressedSize];
                    stream.Seek((long)cFileEntry.Offset, SeekOrigin.Begin);
                    stream.Read(rawData);

                    dir.Children.Add(new File(name, rawData, true, cFileEntry.UncompressedSize));
                }
            }

            return(dir);
        }
Exemple #2
0
        private static Metric ConvertToParsedMetric(GOPGMET.Metric metric, GENESTRT strt)
        {
            if (metric is GOPGMET.StringMetric str)
            {
                StringMetric parsed = new StringMetric();
                parsed.Name = strt.Strings[str.NameIndex];
                foreach (ushort index in str.ValueIndices)
                {
                    parsed.Values.Add(strt.Strings[index]);
                }

                return(parsed);
            }
            else if (metric is GOPGMET.ReferenceMetric reference)
            {
                ReferenceMetric parsed = new ReferenceMetric();
                parsed.Name = strt.Strings[reference.NameIndex];
                foreach (GOPGMET.Metric referenced in reference.ReferencedMetrics)
                {
                    parsed.ReferencedMetrics.Add(ConvertToParsedMetric(referenced, strt));
                }

                return(parsed);
            }
            else
            {
                throw new Exception("Unknown raw metric type \"" + metric.GetType() + "\".");
            }
        }
Exemple #3
0
        private static GOPGMET.Metric ConvertToRawMetric(Metric metric, GENESTRT strt)
        {
            if (metric is StringMetric str)
            {
                GOPGMET.StringMetric raw = new GOPGMET.StringMetric();
                raw.NameIndex = (ushort)strt.AddString(str.Name);
                foreach (string value in str.Values)
                {
                    raw.ValueIndices.Add((ushort)strt.AddString(value));
                }

                return(raw);
            }
            else if (metric is ReferenceMetric reference)
            {
                GOPGMET.ReferenceMetric raw = new GOPGMET.ReferenceMetric();
                raw.NameIndex = (ushort)strt.AddString(reference.Name);
                foreach (Metric referenced in reference.ReferencedMetrics)
                {
                    raw.ReferencedMetrics.Add(ConvertToRawMetric(referenced, strt));
                }

                return(raw);
            }
            else
            {
                throw new Exception("Unknown parsed metric type \"" + metric.GetType() + "\".");
            }
        }
Exemple #4
0
        private FileSet ReadFileSet(Stream stream, string name)
        {
            FileSet fileSet = new FileSet(name);

            using (BinaryReader reader = new BinaryReader(stream)) {
                SectionSet fileSetSections = SectionIO.ReadAll(reader);

                PACKFSHD fileSetHeader    = fileSetSections.Get <PACKFSHD>();
                GENESTRT fileSetNameTable = fileSetSections.Get <GENESTRT>();

                foreach (PACKFSHD.FileEntry fEntry in fileSetHeader.Files)
                {
                    string fName   = fileSetNameTable.Strings[(int)fEntry.NameIndex];
                    byte[] rawData = new byte[fEntry.CompressedSize];
                    stream.Seek((long)fEntry.Offset, SeekOrigin.Begin);
                    stream.Read(rawData);

                    if (fEntry.Unknown != 0x2)
                    {
                        throw new Exception("Unsupported value of unknown file set file entry field: " + fEntry.Unknown);
                    }

                    fileSet.Files.Add(new File(fName, rawData, true, fEntry.UncompressedSize));
                }
            }

            return(fileSet);
        }
Exemple #5
0
        public APK(Stream stream)
        {
            using (BinaryReader reader = new BinaryReader(stream)) {
                SectionSet sections = SectionIO.ReadAll(reader);

                // TODO: Figure out what hash is calculated from and validate hash.
                PACKHEDR hedr      = sections.Get <PACKHEDR>();
                GENESTRT nameTable = sections.Get <GENESTRT>();
                this.Name = nameTable.Strings[(int)hedr.NameIndex];

                PACKTOC toc = sections.Get <PACKTOC>();
                this.RootDirectory = this.BuildContentTree(stream, nameTable, toc, (PACKTOC.DirectoryEntry)toc.Entries[0]);

                PACKFSLS fileSetList = sections.Get <PACKFSLS>();
                foreach (PACKFSLS.FileSetEntry entry in fileSetList.FileSets)
                {
                    stream.Seek((long)entry.Offset, SeekOrigin.Begin);
                    byte[] fileSetData = reader.ReadBytes((int)entry.Size);
                    string fileSetName = nameTable.Strings[(int)entry.NameIndex];

                    if (!Enumerable.SequenceEqual(new MD5CryptoServiceProvider().ComputeHash(fileSetData), entry.Hash))
                    {
                        throw new Exception("Hash mismatch in file set \"" + fileSetName + "\".");
                    }

                    using (MemoryStream fileSetStream = new MemoryStream(fileSetData)) {
                        this.FileSets.Add(this.ReadFileSet(fileSetStream, fileSetName));
                    }
                }
            }
        }
Exemple #6
0
        public IDX(params string[] apkFiles)
        {
            this.sections = new SectionSet();
            this.sections.Add(new ENDILTLE());

            List <SectionSet> apks = new List <SectionSet>();

            foreach (string apkFile in apkFiles)
            {
                using (FileStream stream = File.OpenRead(apkFile)) {
                    apks.Add(SectionIO.ReadAll(stream));
                }
            }

            PACKTOC  combinedToc  = new PACKTOC();
            PACKFSLS combinedFsls = new PACKFSLS();
            GENESTRT combinedStrt = new GENESTRT();

            foreach (SectionSet set in apks)
            {
                PACKHEDR hedr = set.Get <PACKHEDR>();
                GENESTRT strt = set.Get <GENESTRT>();

                hedr.NameIndex = combinedStrt.AddString(strt.Strings[(int)hedr.NameIndex]);
                this.sections.Add(hedr);
            }

            uint packageIndex = 0;

            foreach (SectionSet set in apks)
            {
                PACKTOC  toc  = set.Get <PACKTOC>();
                PACKFSLS fsls = set.Get <PACKFSLS>();
                GENESTRT strt = set.Get <GENESTRT>();

                foreach (PACKTOC.Entry entry in toc.Entries)
                {
                    entry.NameIndex    = combinedStrt.AddString(strt.Strings[(int)entry.NameIndex]);
                    entry.PackageIndex = packageIndex;

                    combinedToc.Entries.Add(entry);
                }

                foreach (PACKFSLS.FileSetEntry entry in fsls.FileSets)
                {
                    entry.NameIndex    = combinedStrt.AddString(strt.Strings[(int)entry.NameIndex]);
                    entry.PackageIndex = packageIndex;

                    combinedFsls.FileSets.Add(entry);
                }

                packageIndex++;
            }

            this.sections.Add(combinedToc);
            this.sections.Add(combinedFsls);
            this.sections.Add(combinedStrt);
            this.sections.Add(new GENEEOF());
        }
        private static GENESTRT GetGENESTRT(EndianBinaryReader br, long headerOffset, long headerSize)
        {
            GENESTRT genetmp = new GENESTRT();
            long     tmp     = br.BaseStream.Position;
            long     tmp2    = headerOffset + headerSize;

            br.BaseStream.Position = tmp2;
            while (br.BaseStream.Position != br.BaseStream.Length)
            {
                if (br.ReadByte() == '\0')
                {
                }
                else
                {
                    br.BaseStream.Position -= 1;
                    char tmpchar = (char)br.ReadByte();
                    if (tmpchar == 'G')
                    {
                        tmpchar = (char)br.ReadByte();
                        if (tmpchar == 'E')
                        {
                            br.BaseStream.Position -= 2;
                            if (Encoding.ASCII.GetString(br.ReadBytes(8)) == "GENESTRT")
                            {
                                genetmp.offset = br.BaseStream.Position - 8;
                                break;
                            }
                        }
                    }
                }
            }
            br.ReadInt32();
            br.ReadInt32();
            long headend = br.BaseStream.Position;

            genetmp.stringcnt = br.ReadInt32();
            br.ReadInt32();
            long genehsize = br.ReadInt32();

            br.ReadInt32();
            genetmp.nameofflist = new long[genetmp.stringcnt];
            for (int i = 0; i < genetmp.stringcnt; i++)
            {
                genetmp.nameofflist[i] = br.ReadInt32();
            }
            br.BaseStream.Position = headend + genehsize;
            genetmp.names_off      = br.BaseStream.Position;
            genetmp.stringlist     = new string[genetmp.stringcnt];
            for (int j = 0; j < genetmp.stringcnt; j++)
            {
                genetmp.stringlist[j] = ReadStringZ(br);
            }
            br.BaseStream.Position = tmp;
            return(genetmp);
        }
Exemple #8
0
        private void WriteFileSet(Stream stream, FileSet fileSet)
        {
            PACKFSHD fileSetHeader    = new PACKFSHD();
            GENESTRT fileSetNameTable = new GENESTRT();

            fileSetHeader.Unknown    = 0x10000;
            fileSetHeader.DataOffset = 0; // Filled in later.

            foreach (File file in fileSet.Files)
            {
                PACKFSHD.FileEntry fileEntry = new PACKFSHD.FileEntry();
                fileEntry.NameIndex        = fileSetNameTable.AddString(file.Name);
                fileEntry.Unknown          = 0x2;
                fileEntry.Offset           = 0; // Filled in later.
                fileEntry.UncompressedSize = file.UncompressedSize;
                fileEntry.CompressedSize   = (uint)file.RawData.Length;

                fileSetHeader.Files.Add(fileEntry);
            }

            SectionSet fileSetSections = new SectionSet();

            fileSetSections.Add(new ENDILTLE());
            fileSetSections.Add(fileSetHeader);
            fileSetSections.Add(fileSetNameTable);
            fileSetSections.Add(new GENEEOF());

            ulong headersSize;

            using (MemoryStream sizeTestStream = new MemoryStream()) {
                SectionIO.WriteAll(sizeTestStream, fileSetSections);
                headersSize = (ulong)sizeTestStream.Length;
            }

            ulong currOffset = NumberUtil.Align(headersSize, 0x10);

            fileSetHeader.DataOffset = (uint)currOffset - 0x10;  // Offset excludes ENDILTLE.
            foreach (PACKFSHD.FileEntry fileEntry in fileSetHeader.Files)
            {
                fileEntry.Offset = currOffset;
                currOffset       = NumberUtil.Align(currOffset + fileEntry.CompressedSize, 0x10);
            }

            SectionIO.WriteAll(stream, fileSetSections);

            foreach (File file in fileSet.Files)
            {
                stream.Write(file.RawData);
                stream.PadTo(0x10);
            }
        }
Exemple #9
0
        public GOP(Stream stream)
        {
            SectionSet sections = SectionIO.ReadAll(stream);

            GOPGMET  met  = sections.Get <GOPGMET>();
            GOPGREC  rec  = sections.Get <GOPGREC>();
            GENESTRT strt = sections.Get <GENESTRT>();
            GOPGDAT  dat  = sections.Get <GOPGDAT>();

            foreach (GOPGREC.ElementInfo elementInfo in rec.Elements)
            {
                Element element = new Element();
                element.Name    = strt.Strings[elementInfo.NameIndex];
                element.Type    = elementInfo.Type;
                element.Unknown = elementInfo.Unknown;

                this.Elements.Add(element);
            }

            this.Records = new string[dat.Records.Count, rec.Elements.Count + 1];

            int recordIndex = 0;

            foreach (GOPGDAT.Record record in dat.Records)
            {
                this.Records[recordIndex, 0] = record.Index.ToString();
                using (MemoryStream dataStream = new MemoryStream(record.Data)) {
                    using (BinaryReader dataReader = new BinaryReader(dataStream)) {
                        for (int i = 0; i < rec.Elements.Count; i++)
                        {
                            GOPGREC.ElementInfo elementInfo = rec.Elements[i];
                            dataStream.Seek(elementInfo.Offset, SeekOrigin.Begin);
                            this.Records[recordIndex, i + 1] = ReadElement(dataReader, elementInfo, strt);
                        }
                    }
                }

                recordIndex++;
            }

            this.RootMetric = ConvertToParsedMetric(met.Root, strt);
        }
Exemple #10
0
        public void Write(Stream stream)
        {
            SectionSet sections = new SectionSet();

            GOPGFIN fin = new GOPGFIN();

            fin.Unknown1 = 0x2;
            fin.Unknown2 = 0x1;
            sections.Add(fin);

            GOPGMET  met  = new GOPGMET();
            GOPGREC  rec  = new GOPGREC();
            GENESTRT strt = new GENESTRT();
            GOPGDAT  dat  = new GOPGDAT();

            strt.AddString("");

            uint currElementPos = 0;

            foreach (Element element in this.Elements)
            {
                uint padTo = ELEMENT_PAD_TO[element.Type];
                currElementPos = (currElementPos + (padTo - 1)) & ~(padTo - 1);

                GOPGREC.ElementInfo info = new GOPGREC.ElementInfo();
                info.Type      = element.Type;
                info.Offset    = currElementPos;
                info.NameIndex = (ushort)strt.AddString(element.Name);
                info.Unknown   = element.Unknown;

                rec.Elements.Add(info);
                currElementPos += ELEMENT_LENGTH[element.Type];
            }

            for (int recordIndex = 0; recordIndex < this.Records.GetLength(0); recordIndex++)
            {
                using (MemoryStream dataStream = new MemoryStream()) {
                    using (BinaryWriter dataWriter = new BinaryWriter(dataStream)) {
                        for (int elementIndex = 0; elementIndex < this.Elements.Count; elementIndex++)
                        {
                            string element = this.Records[recordIndex, elementIndex + 1];
                            GOPGREC.ElementInfo elementInfo = rec.Elements[elementIndex];

                            dataWriter.PadTo((int)ELEMENT_PAD_TO[elementInfo.Type]);
                            WriteElement(dataWriter, elementInfo, strt, element);
                        }

                        dataWriter.PadTo(0x4);
                    }

                    GOPGDAT.Record record = new GOPGDAT.Record();
                    record.Index = uint.Parse(this.Records[recordIndex, 0]);
                    record.Data  = dataStream.ToArray();

                    dat.Records.Add(record);
                }
            }

            met.Root = ConvertToRawMetric(this.RootMetric, strt);

            sections.Add(met);
            sections.Add(rec);
            sections.Add(strt);
            sections.Add(dat);
            sections.Add(new GENEEOF());

            SectionIO.WriteAll(stream, sections);
        }
Exemple #11
0
        private static void WriteElement(BinaryWriter writer, GOPGREC.ElementInfo elementInfo, GENESTRT stringTable, string value)
        {
            switch (elementInfo.Type)
            {
            case GOPGREC.ElementType.ENUM:
                writer.Write(uint.Parse(value));
                break;

            case GOPGREC.ElementType.INT8:
                writer.Write(sbyte.Parse(value));
                break;

            case GOPGREC.ElementType.INT16:
                writer.Write(short.Parse(value));
                break;

            case GOPGREC.ElementType.INT32:
                writer.Write(int.Parse(value));
                break;

            case GOPGREC.ElementType.UINT8:
                writer.Write(byte.Parse(value));
                break;

            case GOPGREC.ElementType.UINT16:
                writer.Write(ushort.Parse(value));
                break;

            case GOPGREC.ElementType.UINT32:
                writer.Write(uint.Parse(value));
                break;

            case GOPGREC.ElementType.FLOAT32:
                writer.Write(float.Parse(value));
                break;

            case GOPGREC.ElementType.BOOL:
                writer.Write(bool.Parse(value));
                break;

            case GOPGREC.ElementType.RECID:
            case GOPGREC.ElementType.STRING:
                writer.Write(stringTable.AddString(value));
                break;

            case GOPGREC.ElementType.RGBA:
                foreach (string component in StringVectorToComponents(value, 4))
                {
                    writer.Write(byte.Parse(component));
                }

                break;

            case GOPGREC.ElementType.FRGB:
            case GOPGREC.ElementType.VECTOR3:
                foreach (string component in StringVectorToComponents(value, 3))
                {
                    writer.Write(float.Parse(component));
                }

                break;

            case GOPGREC.ElementType.FRGBA:
                foreach (string component in StringVectorToComponents(value, 4))
                {
                    writer.Write(float.Parse(component));
                }

                break;

            case GOPGREC.ElementType.IVECTOR4:
                foreach (string component in StringVectorToComponents(value, 4))
                {
                    writer.Write(int.Parse(component));
                }

                break;

            default:
                throw new Exception("Element \"" + stringTable.Strings[(int)elementInfo.NameIndex] + "\" has unknown type " + (int)elementInfo.Type + ".");
            }
        }
Exemple #12
0
        private static string ReadElement(BinaryReader reader, GOPGREC.ElementInfo elementInfo, GENESTRT stringTable)
        {
            switch (elementInfo.Type)
            {
            case GOPGREC.ElementType.ENUM:
                return(reader.ReadUInt32().ToString());

            case GOPGREC.ElementType.INT8:
                return(reader.ReadSByte().ToString());

            case GOPGREC.ElementType.INT16:
                return(reader.ReadInt16().ToString());

            case GOPGREC.ElementType.INT32:
                return(reader.ReadInt32().ToString());

            case GOPGREC.ElementType.UINT8:
                return(reader.ReadByte().ToString());

            case GOPGREC.ElementType.UINT16:
                return(reader.ReadUInt16().ToString());

            case GOPGREC.ElementType.UINT32:
                return(reader.ReadUInt32().ToString());

            case GOPGREC.ElementType.FLOAT32:
                return(reader.ReadSingle().ToString());

            case GOPGREC.ElementType.BOOL:
                return(reader.ReadBoolean().ToString());

            case GOPGREC.ElementType.RECID:
            case GOPGREC.ElementType.STRING:
                return(stringTable.Strings[reader.ReadInt32()]);

            case GOPGREC.ElementType.RGBA:
                return("(" + reader.ReadByte() + "," + reader.ReadByte() + "," + reader.ReadByte() + "," + reader.ReadByte() + ")");

            case GOPGREC.ElementType.FRGB:
            case GOPGREC.ElementType.VECTOR3:
                return("(" + reader.ReadSingle() + "," + reader.ReadSingle() + "," + reader.ReadSingle() + ")");

            case GOPGREC.ElementType.FRGBA:
                return("(" + reader.ReadSingle() + "," + reader.ReadSingle() + "," + reader.ReadSingle() + "," + reader.ReadSingle() + ")");

            case GOPGREC.ElementType.IVECTOR4:
                return("(" + reader.ReadInt32() + "," + reader.ReadInt32() + "," + reader.ReadInt32() + "," + reader.ReadInt32() + ")");

            default:
                throw new Exception("Element \"" + stringTable.Strings[(int)elementInfo.NameIndex] + "\" has unknown type " + (int)elementInfo.Type + ".");
            }
        }
Exemple #13
0
        private void WriteFiles(Stream stream, PACKTOC toc, GENESTRT nameTable)
        {
            List <Node> nodes = this.FlattenTree(this.RootDirectory);

            for (uint i = 0; i < nodes.Count; i++)
            {
                Node node = nodes[(int)i];

                if (node is Directory dir)
                {
                    PACKTOC.DirectoryEntry entry = new PACKTOC.DirectoryEntry();
                    entry.NameIndex       = nameTable.AddString(node.Name);
                    entry.PackageIndex    = 0;
                    entry.FirstEntryIndex = 0;
                    entry.NumEntries      = 0;

                    for (uint j = i + 1; j < nodes.Count; j++)
                    {
                        Node node2 = nodes[(int)j];
                        if (dir.Children.Contains(node2))
                        {
                            if (entry.FirstEntryIndex == 0)
                            {
                                entry.FirstEntryIndex = j;
                            }

                            entry.NumEntries++;
                        }
                    }

                    toc.Entries.Add(entry);
                }
                else if (node is File file)
                {
                    if (file.Compressed)
                    {
                        PACKTOC.CompressedFileEntry entry = new PACKTOC.CompressedFileEntry();
                        entry.NameIndex        = nameTable.AddString(node.Name);
                        entry.PackageIndex     = 0;
                        entry.Offset           = 0; // Filled in later.
                        entry.UncompressedSize = file.UncompressedSize;
                        entry.CompressedSize   = (ulong)file.RawData.Length;

                        toc.Entries.Add(entry);
                    }
                    else
                    {
                        PACKTOC.UncompressedFileEntry entry = new PACKTOC.UncompressedFileEntry();
                        entry.NameIndex    = nameTable.AddString(node.Name);
                        entry.PackageIndex = 0;
                        entry.Offset       = 0; // Filled in later.
                        entry.Size         = (ulong)file.RawData.Length;

                        toc.Entries.Add(entry);
                    }

                    stream.Write(file.RawData);
                    stream.PadTo(0x200);
                }
            }
        }
Exemple #14
0
        public void Write(Stream stream)
        {
            GENESTRT nameTable = new GENESTRT();

            nameTable.Strings.Add(this.Name);

            PACKHEDR packhedr = new PACKHEDR();

            packhedr.Unknown1   = 0x10000;
            packhedr.NameIndex  = 0;
            packhedr.DataOffset = 0;            // Filled in later.
            packhedr.Unknown3   = 1;
            packhedr.Hash       = new byte[16]; // TODO

            PACKTOC toc = new PACKTOC();

            byte[] fileData;
            using (MemoryStream fileStream = new MemoryStream()) {
                this.WriteFiles(fileStream, toc, nameTable);
                fileData = fileStream.ToArray();
            }

            PACKFSLS      fsls         = new PACKFSLS();
            List <byte[]> fileSetDatas = new List <byte[]>();
            uint          nameIndex    = (uint)nameTable.Strings.Count;

            foreach (FileSet fileSet in this.FileSets)
            {
                byte[] fileSetData;
                using (MemoryStream fileSetStream = new MemoryStream()) {
                    this.WriteFileSet(fileSetStream, fileSet);
                    fileSetData = fileSetStream.ToArray();
                }

                PACKFSLS.FileSetEntry entry = new PACKFSLS.FileSetEntry();
                entry.NameIndex    = nameTable.AddString(fileSet.Name);
                entry.PackageIndex = 0;
                entry.Offset       = 0; // Filled in later.
                entry.Size         = (ulong)fileSetData.Length;
                entry.Hash         = new MD5CryptoServiceProvider().ComputeHash(fileSetData);

                fsls.FileSets.Add(entry);
                fileSetDatas.Add(fileSetData);
            }

            SectionSet set = new SectionSet();

            set.Add(new ENDILTLE());
            set.Add(packhedr);
            set.Add(toc);
            set.Add(fsls);
            set.Add(nameTable);
            set.Add(new GENEEOF());

            ulong headersSize;

            using (MemoryStream sizeTestStream = new MemoryStream()) {
                SectionIO.WriteAll(sizeTestStream, set);
                headersSize = (ulong)sizeTestStream.Length;
            }

            ulong currOffset = NumberUtil.Align(headersSize, 0x800);

            packhedr.DataOffset = (uint)currOffset;
            foreach (PACKTOC.Entry entry in toc.Entries)
            {
                if (entry is PACKTOC.UncompressedFileEntry uFileEntry)
                {
                    uFileEntry.Offset = currOffset;
                    currOffset        = NumberUtil.Align(currOffset + uFileEntry.Size, 0x200);
                }
                else if (entry is PACKTOC.CompressedFileEntry cFileEntry)
                {
                    cFileEntry.Offset = currOffset;
                    currOffset        = NumberUtil.Align(currOffset + cFileEntry.CompressedSize, 0x200);
                }
            }

            currOffset = NumberUtil.Align(currOffset, 0x800);
            foreach (PACKFSLS.FileSetEntry fileSetEntry in fsls.FileSets)
            {
                fileSetEntry.Offset = currOffset;
                currOffset          = NumberUtil.Align(currOffset + fileSetEntry.Size, 0x800);
            }

            SectionIO.WriteAll(stream, set);
            stream.PadTo(0x800);

            stream.Write(fileData);

            foreach (byte[] fileSetData in fileSetDatas)
            {
                stream.PadTo(0x800);
                stream.Write(fileSetData);
            }
        }
        private static int Main(string[] args)
        {
            OpenFileDialog fd = new OpenFileDialog();

            fd.Filter = "AKB 1/48 Guam apk files|*.apk";

            if (fd.ShowDialog() == DialogResult.OK)
            {
                FolderBrowserDialog fbd = new FolderBrowserDialog();
                fbd.SelectedPath = "C:\\";
                if (fbd.ShowDialog() == DialogResult.OK)
                {
                    FileStream filestream   = new FileStream("out.txt", FileMode.Create);
                    var        streamwriter = new StreamWriter(filestream);
                    streamwriter.AutoFlush = true;
                    Console.SetOut(streamwriter);
                    Console.SetError(streamwriter);
                    using (EndianBinaryReader reader = new EndianBinaryReader(EndianBitConverter.Little, File.Open(fd.FileName, FileMode.Open)))
                    {
                        reader.ReadBytes(16);
                        if (Encoding.ASCII.GetString(reader.ReadBytes(8)) != "PACKHEDR")
                        {
                            return(-1);
                        }
                        PACKHEDR pkhdr = new PACKHEDR();
                        pkhdr.headerSize  = reader.ReadInt64();
                        pkhdr.dummy       = reader.ReadInt32();
                        pkhdr.zero        = reader.ReadInt32();
                        pkhdr.dummySize   = reader.ReadInt32();
                        pkhdr.dummy2      = reader.ReadInt32();
                        pkhdr.dummystring = Encoding.ASCII.GetString(reader.ReadBytes(16));
                        if (Encoding.ASCII.GetString(reader.ReadBytes(8)) != "PACKTOC ")
                        {
                            return(-1);
                        }
                        PACKTOC pktoc = new PACKTOC();
                        pktoc.size      = reader.ReadInt64();
                        pktoc.offset    = reader.BaseStream.Position;
                        pktoc.entrySize = reader.ReadInt32();
                        pktoc.files     = reader.ReadInt32();
                        pktoc.folders   = reader.ReadInt32();
                        pktoc.zero      = reader.ReadInt32();
                        GENESTRT gene1 = GetGENESTRT(reader, pktoc.offset, pktoc.size);
                        //FOLDERS fldrs = new FOLDERS(pktoc.folders);
                        for (int k = 0; k < pktoc.folders; k++)
                        {
                            /*
                             * fldrs.dummystring.Add(reader.ReadBytes(pktoc.entrySize));
                             * fldrs.nameIdx.Add(fldrs.dummystring[k].ElementAt(4));
                             * fldrs.fileNum.Add(fldrs.dummystring[k].ElementAt(16));
                             * fldrs.subFiles.Add(fldrs.dummystring[k].ElementAt(20));
                             * fldrs.foldernames[k] = gene1.stringlist[fldrs.nameIdx[k]];
                             */
                            reader.ReadBytes(pktoc.entrySize);
                        }
                        for (int l = pktoc.folders; l < pktoc.files; l++)
                        {
                            long tocpos = reader.BaseStream.Position;
                            reader.ReadInt32(); //always 0x200 (512)
                            int idx = reader.ReadInt32();
                            reader.ReadInt32(); //always 0
                            reader.ReadInt32(); //always 0
                            long offset = reader.ReadInt64();
                            long size   = reader.ReadInt64();
                            long zsize  = reader.ReadInt64();
                            Console.WriteLine("TOC offset: {4}  file: {0}  offset: {1}  size: {2}  zsize: {3}", gene1.stringlist[idx], offset, size, zsize, tocpos);
                            if (size != 0)
                            {
                                string fname = gene1.stringlist[idx];
                                if (zsize == 0)
                                {
                                    long tmpstreampos = reader.BaseStream.Position;
                                    reader.BaseStream.Position = offset;
                                    //Console.WriteLine("File: {0} is not compressed. Writing to {1}", fname, fbd.SelectedPath + "\\" + fname);
                                    using (FileStream nfstrm = new FileStream(fbd.SelectedPath + "\\" + fname, FileMode.Create))
                                    {
                                        nfstrm.Write(reader.ReadBytes((int)size), 0, (int)size);
                                        reader.BaseStream.Position = tmpstreampos;
                                    }
                                }
                                else
                                {
                                    long tempstrmpos = reader.BaseStream.Position;
                                    reader.BaseStream.Position = offset + 2;
                                    //Console.WriteLine("File: {0} is compressed. Writing to {1}", fname, fbd.SelectedPath + "\\" + fname);
                                    MemoryStream tmpmemstrm = new MemoryStream(reader.ReadBytes((int)zsize));
                                    using (FileStream cpfs = new FileStream(fbd.SelectedPath + "\\" + fname, FileMode.Create))
                                    {
                                        using (DeflateStream dfstrm = new DeflateStream(tmpmemstrm, CompressionMode.Decompress))
                                        {
                                            dfstrm.CopyTo(cpfs);
                                        }
                                    }
                                    reader.BaseStream.Position = tempstrmpos;
                                }
                            }
                        }
                        reader.BaseStream.Position = pktoc.offset + pktoc.size;
                        if (Encoding.ASCII.GetString(reader.ReadBytes(8)) != "PACKFSLS")
                        {
                            return(-1);
                        }
                        PACKFSLS pkfls = new PACKFSLS();
                        pkfls.headerSize   = reader.ReadInt64();
                        pkfls.headerOffset = reader.BaseStream.Position;
                        pkfls.archives     = reader.ReadInt32();
                        pkfls.dummy        = reader.ReadInt32();
                        pkfls.dummy2       = reader.ReadInt32();
                        pkfls.zero         = reader.ReadInt32();
                        for (int archive = 0; archive < pkfls.archives; archive++)
                        {
                            int tmpidx = reader.ReadInt32();
                            reader.ReadInt32();
                            long archiveoffset = reader.ReadInt64();
                            long archivesize   = reader.ReadInt64();
                            reader.ReadBytes(16);
                            string aname  = gene1.stringlist[tmpidx];
                            long   tmppos = reader.BaseStream.Position;
                            extractArchives(reader, archiveoffset, aname, fbd.SelectedPath);
                            reader.BaseStream.Position = tmppos;
                        }
                    }
                    filestream.Close();
                }
            }
            return(1);
        }
        private static void extractArchives(EndianBinaryReader bread, long offset, string archname, string path)
        {
            bread.BaseStream.Position = offset;
            bread.ReadBytes(8);
            bread.ReadBytes(8);
            long tmppos = bread.BaseStream.Position;

            bread.ReadBytes(8);
            long header_size   = bread.ReadInt64();
            long header_offset = bread.BaseStream.Position;

            bread.ReadInt32();
            int entry_size   = bread.ReadInt32();
            int files        = bread.ReadInt32();
            int entries_size = bread.ReadInt32();

            bread.ReadBytes(16);
            GENESTRT arcgene = GetGENESTRT(bread, header_offset, header_size);

            for (int i = 0; i < files; i++)
            {
                int    name_idx = bread.ReadInt32();
                int    zip      = bread.ReadInt32();
                long   f_offset = bread.ReadInt64();
                long   f_size   = bread.ReadInt64();
                long   f_zsize  = bread.ReadInt64();
                string f_name   = archname + "/" + arcgene.stringlist[name_idx];
                f_offset += offset;
                FileInfo fileInfo = new FileInfo(path + "/" + f_name);

                if (!fileInfo.Exists)
                {
                    Directory.CreateDirectory(fileInfo.Directory.FullName);
                }
                if (f_zsize == 0)
                {
                    long tmpstreampos = bread.BaseStream.Position;
                    bread.BaseStream.Position = f_offset;
                    Console.WriteLine("File: {0} is not compressed. Writing to {1}", f_name, path + "\\" + f_name);
                    using (FileStream nfstrm = new FileStream(path + "/" + f_name, FileMode.Create))
                    {
                        nfstrm.Write(bread.ReadBytes((int)f_size), 0, (int)f_size);
                        bread.BaseStream.Position = tmpstreampos;
                    }
                }
                else
                {
                    long tempstrmpos = bread.BaseStream.Position;
                    bread.BaseStream.Position = f_offset + 2;
                    Console.WriteLine("File: {0} is compressed. Writing to {1}", f_name, path + "\\" + f_name);
                    MemoryStream tmpmemstrm = new MemoryStream(bread.ReadBytes((int)f_zsize));
                    using (FileStream cpfs = new FileStream(path + "\\" + f_name, FileMode.Create))
                    {
                        using (DeflateStream dfstrm = new DeflateStream(tmpmemstrm, CompressionMode.Decompress))
                        {
                            dfstrm.CopyTo(cpfs);
                        }
                    }
                    bread.BaseStream.Position = tempstrmpos;
                }
            }
        }