public FileInjector(CpkContainer cpk, string outpath, long injectionOffset) { if (DisableInjection) { return; } Cpk = cpk; if (outpath != null) { Directory.CreateDirectory(Path.GetDirectoryName(outpath)); OutputStream = new FileStream(outpath, FileMode.Create); } else { OutputStream = new HyoutaUtils.Streams.MemoryStream64(); } CurrentInjectionOffset = injectionOffset; using (Stream instream = cpk.DuplicateStream()) { instream.Position = 0; StreamUtils.CopyStream(instream, OutputStream, instream.Length); } EnsureAligned(); RemappedSubcpks = new Dictionary <string, SubcpkData>(); }
public FileInjectorV0V2(CpkContainer cpkv2, CpkContainer cpkv0, string outpathv2, string outpathv0, long injectionOffset) { Injector0 = cpkv0 == null ? null : new FileInjector(cpkv0, outpathv0, injectionOffset); Injector2 = cpkv2 == null ? null : new FileInjector(cpkv2, outpathv2, injectionOffset); }
private SubcpkData GetOrCreateSubcpkData(string subcpkPath) { SubcpkData data; if (RemappedSubcpks.TryGetValue(subcpkPath, out data)) { return(data); } int subcpkidx = Cpk.GetChildIndexFromName(subcpkPath).Value; var subcpkoffs = Cpk.QueryChildInfoByIndex(subcpkidx, "FileOffset"); var subcpkstream = Cpk.GetChildByIndex(subcpkidx).AsFile.DataStream; var subcpk = new CpkContainer(subcpkstream.Duplicate()); long subcpkOffsetInMainCpk = (long)subcpkoffs.value_u64 + Math.Min(Cpk.content_offset, Cpk.toc_offset); // header goes from start of file to content_offset in all of these long headerInjectedOffset = CurrentInjectionOffset; long headerSize = subcpk.content_offset; OutputStream.Position = headerInjectedOffset; subcpkstream.Position = 0; StreamUtils.CopyStream(subcpkstream, OutputStream, headerSize); EnsureAligned(); // and ToC is from toc_offset until the end of file long tocInjectedOffset = CurrentInjectionOffset; long tocSize = subcpkstream.Length - subcpk.toc_offset; OutputStream.Position = tocInjectedOffset; subcpkstream.Position = subcpk.toc_offset; StreamUtils.CopyStream(subcpkstream, OutputStream, tocSize); EnsureAligned(); // fetch relevant metadata for all files and repoint the offsets List <SubcpkFileInfo> files = new List <SubcpkFileInfo>((int)subcpk.toc_entries); long shift = subcpkOffsetInMainCpk - headerInjectedOffset; for (int i = 0; i < subcpk.toc_entries; ++i) { var name = subcpk.GetChildNameFromIndex(i); var fsize = subcpk.QueryChildInfoByIndex(i, "FileSize"); var esize = subcpk.QueryChildInfoByIndex(i, "ExtractSize"); var foffs = subcpk.QueryChildInfoByIndex(i, "FileOffset"); long fsizepos = tocInjectedOffset + (fsize.data_position - subcpk.toc_offset); long esizepos = tocInjectedOffset + (esize.data_position - subcpk.toc_offset); long foffspos = tocInjectedOffset + (foffs.data_position - subcpk.toc_offset); OutputStream.Position = foffspos; long newFileoffs = (long)foffs.value_u64 + shift; OutputStream.WriteUInt64(((ulong)newFileoffs).ToEndian(EndianUtils.Endianness.BigEndian)); files.Add(new SubcpkFileInfo() { name = name, fsizepos = fsizepos, esizepos = esizepos, foffspos = foffspos }); } // repoint offsets to be correct List <string> offsetnames = new List <string>() { "ContentOffset", "TocOffset", "EtocOffset", "ItocOffset", "GtocOffset" }; foreach (string offsetname in offsetnames) { var result = subcpk.QueryInfo(offsetname); long value = (long)result.value_u64; long position = result.data_position; if (offsetname == "ContentOffset") { // hack to force ContentOffset and TocOffset to be the same value = subcpk.toc_offset; } if (value != 0) { long newOffset = (value - subcpk.toc_offset) + (tocInjectedOffset - headerInjectedOffset); OutputStream.Position = headerInjectedOffset + position; OutputStream.WriteUInt64(((ulong)newOffset).ToEndian(EndianUtils.Endianness.BigEndian)); } } // repoint file offset in main cpk to copied headers long newOffsetOfSubcpkInMaincpk = headerInjectedOffset - Math.Min(Cpk.content_offset, Cpk.toc_offset); OutputStream.Position = subcpkoffs.data_position; OutputStream.WriteUInt64(((ulong)newOffsetOfSubcpkInMaincpk).ToEndian(EndianUtils.Endianness.BigEndian)); // remember and return OutputStream.Position = CurrentInjectionOffset; data = new SubcpkData() { Cpk = subcpk, SubcpkOffset = headerInjectedOffset, ContentTocOffset = tocInjectedOffset - headerInjectedOffset, Files = files }; RemappedSubcpks.Add(subcpkPath, data); return(data); }