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); }
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)); } } } }
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 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); } }
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); }
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); }
public IDX(Stream stream) { this.sections = SectionIO.ReadAll(stream); }
public void Write(Stream stream) { SectionIO.WriteAll(stream, this.sections); }
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); } }