public void PreviewFile(string path) { string ext = Path.GetExtension(path).ToLower(); TOCFile toc; switch (ext) { case ".toc": toc = new TOCFile(path); if (toc != null && toc.lines != null) Helpers.FillTreeFast(treeView2, toc.lines); break; case ".sb": string tocpath = Helpers.GetFileNameWithOutExtension(path) + ".toc"; if (File.Exists(tocpath)) { toc = new TOCFile(tocpath); if (toc != null && toc.lines != null && toc.lines.Count != 0) foreach (BJSON.Field f in toc.lines[0].fields) if (f.fieldname == "cas" && (bool)f.data) { SBFile sb = new SBFile(path); if (sb != null && sb.lines != null) Helpers.FillTreeFast(treeView2, sb.lines); return; } } break; } }
public void LoadFile(string path) { this.Text = "SB Tool - " + path; toc = new TOCFile(Helpers.GetFileNameWithOutExtension(path) + ".toc"); if (toc.iscas) { toolStrip1.Visible = true; splitContainer2.BringToFront(); sb = new SBFile(path); RefreshTree(); } else { toolStrip1.Visible = false; tabControl1.BringToFront(); RefreshBinary(); } }
public void LoadFile(string path) { initfs = new TOCFile(path); list = new List<FileEntry>(); foreach (BJSON.Entry e in initfs.lines) if (e.fields != null && e.fields.Count != 0) { BJSON.Field file = e.fields[0]; List<BJSON.Field> data = (List<BJSON.Field>)file.data; FileEntry entry = new FileEntry(); foreach (BJSON.Field f in data) switch (f.fieldname) { case "name": entry.name = (string)f.data; break; case "payload": entry.data = (byte[])f.data; break; } list.Add(entry); } RefreshList(); }
private void RefreshPreview() { try { int n = listBox2.SelectedIndex; if (n == -1) return; status.Text = "Getting header infos from db..."; Application.DoEvents(); DBAccess.RESInformation ti = ttprevlist[n]; DBAccess.BundleInformation buni = DBAccess.GetBundleInformationById(ti.bundlepath)[0]; DBAccess.TOCInformation toci = DBAccess.GetTocInformationByIndex(buni.tocIndex); byte[] resdata = new byte[0]; if (toci.incas) { status.Text = "Getting header data from sha1..."; Application.DoEvents(); resdata = SHA1Access.GetDataBySha1(Helpers.HexStringToByteArray(ti.sha1)); } else { status.Text = "Getting header data from binary bundle..."; Application.DoEvents(); TOCFile toc = new TOCFile(toci.path); byte[] bundledata = toc.ExportBundleDataByPath(buni.bundlepath); BinaryBundle b = new BinaryBundle(new MemoryStream(bundledata)); foreach (BinaryBundle.ResEntry res in b.ResList) if (res._name == ti.resname) { resdata = res._data; break; } } hb2.ByteProvider = new DynamicByteProvider(resdata); status.Text = "Ready"; } catch (Exception ex) { status.Text = "General error, after state '" + status.Text + "' : " + ex.Message; } }
public static void AddBundle(int tocid, bool incas, Bundle b, TOCFile.TOCBundleInfoStruct info, SQLiteConnection con) { Debug.LogLn(" EBX:" + b.ebx.Count + " RES:" + b.res.Count + " CHUNK:" + b.chunk.Count, true); SQLCommand("INSERT INTO bundles (tocfile, frostid, offset, size, base, delta) VALUES (" + tocid + ",'" + info.id + "'," + info.offset + ", " + info.size + ", '" + info.isbase + "', '" + info.isdelta + "' )", con); int bundleid = (int)GetLastRowId(con); TOCInformation toci = GetTocInformationByIndex(tocid); var transaction = con.BeginTransaction(); int counter = 0; if (b.ebx != null) foreach (Bundle.ebxtype ebx in b.ebx) try { if (ebx.name != null && ebx.originalSize != null && ebx.size != null) { EBXInformation inf = new EBXInformation(); inf.basesha1 = Helpers.ByteArrayToHexString(ebx.baseSha1); inf.bundlepath = b.path; inf.casPatchType = ebx.casPatchType; inf.deltasha1 = Helpers.ByteArrayToHexString(ebx.deltaSha1); inf.ebxname = ebx.name; inf.incas = incas; inf.isbase = info.isbase; inf.isdelta = info.isdelta; if (toci.type == TYPE_BASEGAME) inf.isbasegamefile = true; if (toci.type == TYPE_UPDATE) inf.isDLC = true; if (toci.type == TYPE_PATCH) inf.isPatch = true; inf.offset = info.offset; inf.sha1 = Helpers.ByteArrayToHexString(ebx.Sha1); inf.size = info.size; inf.tocfilepath = toci.path; byte[] data = new byte[0]; if (inf.incas) data = SHA1Access.GetDataBySha1(ebx.Sha1, 0x38); else { BinaryBundle bb = null; foreach (AddEBXHelpStruct h in aehelp) if (h.tocpath == inf.tocfilepath && h.bpath == inf.bundlepath) { bb = h.b; break; } if (bb == null) { TOCFile toc = new TOCFile(inf.tocfilepath); byte[] bundledata = toc.ExportBundleDataByPath(inf.bundlepath); bb = new BinaryBundle(new MemoryStream(bundledata)); AddEBXHelpStruct h = new AddEBXHelpStruct(); h.tocpath = inf.tocfilepath; h.bpath = inf.bundlepath; h.b = bb; if (aehelp.Count > 10) aehelp.RemoveAt(0); } foreach (BinaryBundle.EbxEntry ebx2 in bb.EbxList) if (inf.ebxname == ebx2._name) data = ebx2._data; } inf.guid = Helpers.ByteArrayToHexString(data, 0x28, 0x10); AddEBXLUTFile(inf, con); if ((counter++) % 100 == 0) { transaction.Commit(); transaction = con.BeginTransaction(); } } } catch (Exception ex) { throw ex; } transaction.Commit(); transaction = con.BeginTransaction(); if (b.res != null) foreach (Bundle.restype res in b.res) try { if (res.name != null) AddRESFile(res.name, res.SHA1, res.rtype, bundleid, con); } catch (Exception ex) { throw ex; } transaction.Commit(); transaction = con.BeginTransaction(); if (b.chunk != null) foreach (Bundle.chunktype chunk in b.chunk) try { AddChunk(chunk.id, chunk.SHA1, bundleid, con); } catch (Exception ex) { throw ex; } transaction.Commit(); }
private static void ScanTOCsForBundles() { Debug.LogLn("Saving bundles into db..."); SQLiteConnection con = GetConnection(); con.Open(); SQLiteDataReader reader = getAll("tocfiles", con); StringBuilder sb = new StringBuilder(); List<string> files = new List<string>(); List<int> fileids = new List<int>(); while (reader.Read()) { fileids.Add(reader.GetInt32(0)); files.Add(reader.GetString(1)); } int counter = 0; Stopwatch sp = new Stopwatch(); sp.Start(); foreach (string file in files) { counter++; Debug.LogLn("Opening " + file + " ..."); TOCFile tocfile = new TOCFile(file); int counter2 = 0; foreach (TOCFile.TOCBundleInfoStruct info in tocfile.bundles) { counter2++; Bundle b; string pathsb = Helpers.GetFileNameWithOutExtension(file) + ".sb"; FileStream fs = new FileStream(pathsb, FileMode.Open, FileAccess.Read); fs.Seek(0, SeekOrigin.End); long filesize = fs.Position; if (info.offset > filesize) { fs.Close(); continue; } fs.Seek(info.offset, 0); byte[] buff = new byte[info.size]; fs.Read(buff, 0, info.size); if (tocfile.iscas) { if (buff[0] != 0x82) continue; List<BJSON.Entry> list = new List<BJSON.Entry>(); BJSON.ReadEntries(new MemoryStream(buff), list); b = Bundle.Create(list[0]); } else { uint magic = BitConverter.ToUInt32(buff, 4); if (magic != 0xd58e799d) continue; b = Bundle.Create(buff, true); } string log = " adding bundle: " + (counter2) + "/" + tocfile.bundles.Count + " "; if (info.isbase) log += "ISBASEG "; if (info.isdelta) log += "ISDELTA "; log += "ID: " + info.id; Debug.Log(log, true); AddBundle(fileids[counter - 1], tocfile.iscas, b, info, con); } counter2 = 0; var transaction = con.BeginTransaction(); foreach (TOCFile.TOCChunkInfoStruct info in tocfile.chunks) { AddGlobalChunk(fileids[counter - 1], info.id, info.sha1, info.offset, info.size, con); Debug.LogLn(" adding chunk: " + (counter2) + "/" + tocfile.chunks.Count + " " + Helpers.ByteArrayToHexString(info.id), counter2 % 1000 == 0); if (counter2 % 1000 == 0) { transaction.Commit(); transaction = con.BeginTransaction(); } counter2++; } transaction.Commit(); long elapsed = sp.ElapsedMilliseconds; long ETA = ((elapsed / counter) * files.Count); TimeSpan ETAt = TimeSpan.FromMilliseconds(ETA); Debug.LogLn((counter) + "/" + files.Count + " files done." + " - Elapsed: " + sp.Elapsed.ToString() + " ETA: " + ETAt.ToString()); } con.Close(); }
public static void AddEBXLUTFile(EBXInformation ebx, SQLiteConnection con) { string ftype = "b"; if (ebx.isDLC) ftype = "u"; if (ebx.isPatch) ftype = "p"; string guid = ""; byte[] data = new byte[0]; if (ebx.incas) data = SHA1Access.GetDataBySha1(Helpers.HexStringToByteArray(ebx.sha1)); else { BinaryBundle b = null; foreach(AddEBXHelpStruct h in aehelp) if (h.tocpath == ebx.tocfilepath && h.bpath == ebx.bundlepath) { b = h.b; break; } if (b == null) { TOCFile toc = new TOCFile(ebx.tocfilepath); byte[] bundledata = toc.ExportBundleDataByPath(ebx.bundlepath); b = new BinaryBundle(new MemoryStream(bundledata)); AddEBXHelpStruct h = new AddEBXHelpStruct(); h.tocpath = ebx.tocfilepath; h.bpath = ebx.bundlepath; h.b = b; if (aehelp.Count > 10) aehelp.RemoveAt(0); } foreach (BinaryBundle.EbxEntry ebx2 in b.EbxList) if (ebx.ebxname == ebx2._name) data = ebx2._data; } guid = Helpers.ByteArrayToHexString(data, 0x28, 0x10); SQLCommand("INSERT INTO ebxlut (path,sha1,basesha1,deltasha1,casptype,guid,bundlepath,offset,size,isbase,isdelta,tocpath,incas,filetype) VALUES ('" + ebx.ebxname.Replace("'","''") + "','" + ebx.sha1 + "','" + ebx.basesha1 + "','" + ebx.deltasha1 + "'," + ebx.casPatchType + ",'" + guid + "','" + ebx.bundlepath + "'," + ebx.offset + "," + ebx.size + ",'" + ebx.isbase + "','" + ebx.isdelta + "','" + ebx.tocfilepath + "','" + ebx.incas + "','" + ftype + "')", con); }
public static void AddTOCFile(string path, string type, SQLiteConnection con) { string md5 = Helpers.ByteArrayToHexString(Helpers.ComputeHash(path)); Debug.LogLn(" MD5: " + md5 + " Filename: " + Path.GetFileName(path)); TOCFile toc = new TOCFile(path); bool incas = false; foreach (BJSON.Field f1 in toc.lines[0].fields) if (f1.fieldname == "cas") incas = (bool)f1.data; SQLCommand("INSERT INTO tocfiles (path, md5, incas, type) VALUES ('" + path + "', '" + md5 + "','" + incas + "','" + type + "')", con); }
public void UpdateTOC(TOCFile toc) { string path = toc.MyPath; path = path.ToLower().Replace(".toc",".sb"); if (!toc.iscas) return; SBFile sb = new SBFile(path); BJSON.Entry root = sb.lines[0]; BJSON.Field bundles = root.FindField("bundles"); BJSON.Entry tocroot = toc.lines[0]; BJSON.Field tocbundles = tocroot.FindField("bundles"); foreach (BJSON.Entry bun in (List<BJSON.Entry>)bundles.data) { BJSON.Field f = bun.FindField("path"); string bunpath = (string)f.data; foreach (BJSON.Entry tocbun in (List<BJSON.Entry>)tocbundles.data) { BJSON.Field f2 = tocbun.FindField("id"); string bunpath2 = (string)f2.data; if (bunpath == bunpath2) { BJSON.Field offset = tocbun.FindField("offset"); offset.data = BitConverter.GetBytes(bun.offset); MemoryStream m = new MemoryStream(); BJSON.WriteEntry(m, bun); string p = Path.GetDirectoryName(path); File.WriteAllBytes(p + "\\" + Path.GetFileName(bunpath) + ".bin", m.ToArray()); BJSON.Field size = tocbun.FindField("size"); size.data = BitConverter.GetBytes((uint)m.Length); } } } toc.Save(); DbgPrint(" TOC file offsets updated."); }
private void openSingleToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog d = new OpenFileDialog(); d.Filter = "*.toc|*.toc"; if (d.ShowDialog() == System.Windows.Forms.DialogResult.OK) { toc = new TOCFile(d.FileName); RefreshTree(); this.Text = "TOC Tool - " + d.FileName; } }
private void RefreshPreview() { try { int n = listBox2.SelectedIndex; if (n == -1) return; statustextures.Text = "Getting header infos from db..."; Application.DoEvents(); hb3.ByteProvider = new DynamicByteProvider(new byte[0]); hb3.BringToFront(); if (!Directory.Exists("tmp")) Directory.CreateDirectory("tmp"); if (File.Exists("tmp\\tmp.dds")) File.Delete("tmp\\tmp.dds"); DBAccess.TextureInformation ti = ttprevlist[n]; DBAccess.BundleInformation buni = DBAccess.GetBundleInformationByIndex(ti.bundleIndex); DBAccess.TOCInformation toci = DBAccess.GetTocInformationByIndex(buni.tocIndex); byte[] resdata = new byte[0]; if (toci.incas) { statustextures.Text = "Getting header data from sha1..."; Application.DoEvents(); resdata = SHA1Access.GetDataBySha1(ti.sha1); } else { statustextures.Text = "Getting header data from binary bundle..."; Application.DoEvents(); TOCFile toc = new TOCFile(toci.path); byte[] bundledata = toc.ExportBundleDataByPath(buni.bundlepath); BinaryBundle b = new BinaryBundle(new MemoryStream(bundledata)); foreach (BinaryBundle.ResEntry res in b.ResList) if (res._name == ti.name) { resdata = res._data; break; } } hb2.ByteProvider = new DynamicByteProvider(resdata); statustextures.Text = "Getting texture infos from db..."; Application.DoEvents(); TextureMetaResource tmr = new TextureMetaResource(resdata); DBAccess.ChunkInformation ci = DBAccess.GetChunkInformationById(tmr.chunkid); if (ci.bundleIndex == -1) throw new Exception("no chunk info found in db"); DBAccess.BundleInformation buni2 = DBAccess.GetBundleInformationByIndex(ci.bundleIndex); DBAccess.TOCInformation toci2 = DBAccess.GetTocInformationByIndex(buni2.tocIndex); byte[] texdata = new byte[0]; if (toci2.incas) { statustextures.Text = "Getting texture data from sha1..."; Application.DoEvents(); texdata = SHA1Access.GetDataBySha1(ci.sha1); } else { statustextures.Text = "Getting texture data from binary bundle..."; Application.DoEvents(); TOCFile toc = new TOCFile(toci2.path); byte[] bundledata = toc.ExportBundleDataByPath(buni2.bundlepath); BinaryBundle b = new BinaryBundle(new MemoryStream(bundledata)); foreach (BinaryBundle.ChunkEntry chunk in b.ChunkList) if (Helpers.MatchByteArray(chunk.id, ci.id)) { texdata = chunk._data; break; } } if (toolStripButton16.Checked) { hb3.ByteProvider = new DynamicByteProvider(texdata); hb3.BringToFront(); } else { statustextures.Text = "Making Preview..."; Application.DoEvents(); MemoryStream m = new MemoryStream(); tmr.WriteTextureHeader(m); m.Write(texdata, 0, texdata.Length); File.WriteAllBytes("tmp\\tmp.dds", m.ToArray()); try { pb1.Image = DevIL.DevIL.LoadBitmap("tmp\\tmp.dds"); pb1.BringToFront(); } catch (Exception) { statustextures.Text = "Error loading dds, after state '" + statustextures.Text + "'"; hb3.ByteProvider = new DynamicByteProvider(texdata); hb3.BringToFront(); } } statustextures.Text = "Ready"; } catch (Exception) { statustextures.Text = "General error, after state '" + statustextures.Text + "'"; } }
public void RunTextureResJobOnBundleBinary(Mod.ModJob mj, TOCFile toc, string tocpath, string bpath) { GC.Collect(); int count = 0; int index = -1; foreach (TOCFile.TOCBundleInfoStruct buni in toc.bundles) if (count++ > -1 && bpath.ToLower() == buni.id.ToLower()) { DbgPrint(" Found bundle : " + bpath); index = count - 1; break; } //if bundle found if (index != -1) { //find out if base, delta or nothing BJSON.Entry root = toc.lines[0]; BJSON.Field bundles = root.FindField("bundles"); BJSON.Entry bun = ((List<BJSON.Entry>)bundles.data)[index]; BJSON.Field isDeltaField = bun.FindField("delta"); BJSON.Field isBaseField = bun.FindField("base"); //if has base or delta prop, still from patch if (isBaseField != null) if (!ImportBundleBinaryFromBase(toc, tocpath, bpath)) return; toc = new TOCFile(toc.MyPath);//reload toc byte[] bundledataraw = toc.ExportBundleDataByPath(bpath); uint test = BitConverter.ToUInt32(bundledataraw, 4); if (test != 0xD58E799D) { DbgPrint(" Its a real delta bundle, importing from base..."); if (!ImportBundleBinaryFromBase(toc, tocpath, bpath, false)) return; toc.Save(); toc = new TOCFile(toc.MyPath);//reload toc } DbgPrint(" Updating SB file with new data..."); bundledataraw = toc.ExportBundleDataByPath(bpath); BinaryBundle bundle = new BinaryBundle(new MemoryStream(bundledataraw)); bool found = false; byte[] chunkidbuff = new byte[16]; byte[] newchunkid = new byte[16]; //find right res entry for (int j = 0; j < bundle.ResList.Count; j++) if (bundle.ResList[j]._name.ToLower() == mj.respath.ToLower()) { //get res data and extract chunk id for (int k = 0; k < 16; k++) chunkidbuff[k] = bundle.ResList[j]._data[k + 0x1C]; DbgPrint(" Found chunk id : " + Helpers.ByteArrayToHexString(chunkidbuff)); newchunkid = Guid.NewGuid().ToByteArray(); DbgPrint(" Creating new chunk id : " + Helpers.ByteArrayToHexString(newchunkid)); for (int k = 0; k < 16; k++) bundle.ResList[j]._data[k + 0x1C] = newchunkid[k]; found = true; } if (!found) { DbgPrint(" Error: cant find res, skipping!"); return; } found = false; //find right chunk entry MemoryStream m3 = new MemoryStream(); Helpers.WriteLEInt(m3, BitConverter.ToInt32(chunkidbuff, 0)); Helpers.WriteLEUShort(m3, BitConverter.ToUInt16(chunkidbuff, 4)); Helpers.WriteLEUShort(m3, BitConverter.ToUInt16(chunkidbuff, 6)); m3.Write(chunkidbuff, 8, 8); byte[] chunkidswapped = m3.ToArray(); for (int j = 0; j < bundle.ChunkList.Count; j++) if (Helpers.ByteArrayCompare(bundle.ChunkList[j].id, chunkidswapped)) { DbgPrint(" Found chunk"); found = true; BinaryBundle.ChunkEntry chunk = bundle.ChunkList[j]; m3 = new MemoryStream(); Helpers.WriteLEInt(m3, BitConverter.ToInt32(newchunkid, 0)); Helpers.WriteLEUShort(m3, BitConverter.ToUInt16(newchunkid, 4)); Helpers.WriteLEUShort(m3, BitConverter.ToUInt16(newchunkid, 6)); m3.Write(newchunkid, 8, 8); chunk.id = m3.ToArray(); chunk._data = mj.data; bundle.ChunkList[j] = chunk; break; } if (!found) { DbgPrint(" Error: Could not find Chunk by id"); return; } DbgPrint(" Recompiling bundle..."); MemoryStream m = new MemoryStream(); bundle.Save(m); DbgPrint(" Recompiling sb..."); MemoryStream m2 = new MemoryStream(); List<BJSON.Entry> list = ((List<BJSON.Entry>)bundles.data); foreach (TOCFile.TOCBundleInfoStruct buni in toc.bundles) if (!buni.isbase) { byte[] buff = new byte[0]; if (bpath.ToLower() != buni.id.ToLower()) buff = toc.ExportBundleDataByPath(buni.id); else buff = m.ToArray(); for (int i = 0; i < list.Count; i++) if ((string)list[i].FindField("id").data == buni.id) { BJSON.Entry e = list[i]; BJSON.Field f = e.fields[e.FindFieldIndex("offset")]; f.data = BitConverter.GetBytes(m2.Position); e.fields[e.FindFieldIndex("offset")] = f; f = e.fields[e.FindFieldIndex("size")]; f.data = BitConverter.GetBytes(buff.Length); e.fields[e.FindFieldIndex("size")] = f; list[i] = e; break; } m2.Write(buff, 0, buff.Length); } bundles.data = list; root.fields[root.FindFieldIndex("bundles")] = bundles; toc.lines[0] = root; DbgPrint(" Updating TOC..."); toc.Save(); toc = new TOCFile(toc.MyPath);//reload toc DbgPrint(" Saving sb..."); if (tocpath.ToLower().Contains("update")) File.WriteAllBytes(outputPath + Helpers.SkipSubFolder(tocpath.ToLower().Replace(".toc", ".sb"), 2), m2.ToArray()); else File.WriteAllBytes(outputPath + tocpath.ToLower().Replace(".toc", ".sb"), m2.ToArray()); DbgPrint(" Job successfull!"); } }
public void RunTextureResJob(Mod.ModJob mj, string tocpath, byte[] newsha1, int newcompressedsize) { DbgPrint("Loading : " + tocpath); TOCFile toc = null; if (!tocpath.ToLower().StartsWith("update")) toc = new TOCFile(outputPath + tocpath); else toc = new TOCFile(outputPath + Helpers.SkipSubFolder(tocpath, 2)); //walk through affected bundles if (toc.iscas) foreach (string bpath in mj.bundlePaths) RunTextureResJobOnBundle(mj, toc, tocpath, newsha1, bpath, newcompressedsize); else foreach (string bpath in mj.bundlePaths) RunTextureResJobOnBundleBinary(mj, toc, tocpath, bpath); UpdateTOC(toc); }
public void RunTextureResJobOnBundle(Mod.ModJob mj, TOCFile toc, string tocpath, byte[] newsha1, string bpath, int newcompressedsize) { GC.Collect(); int count = 0; int index = -1; foreach (TOCFile.TOCBundleInfoStruct buni in toc.bundles) if (count++ > -1 && bpath == buni.id) { DbgPrint(" Found bundle : " + bpath); index = count - 1; break; } //if bundle found if (index != -1) { if (!toc.iscas) { DbgPrint(" Warning: binary bundles not supported yet, skipping!"); return; } //find out if base or delta BJSON.Entry root = toc.lines[0]; BJSON.Field bundles = root.FindField("bundles"); BJSON.Entry bun = ((List<BJSON.Entry>)bundles.data)[index]; BJSON.Field isDeltaField = bun.FindField("delta"); BJSON.Field isBaseField = bun.FindField("base"); //if is base, copy from base, make delta and recompile if (isBaseField != null && (bool)isBaseField.data == true) if (!ImportBundleFromBase(toc, tocpath, index, bpath)) return; //check if already is in sb if (isDeltaField != null && (bool)isDeltaField.data == true) DbgPrint(" Its already a delta"); DbgPrint(" Updating SB file with new SHA1...");//yeah, pretty much string SBpath = outputPath + Path.GetDirectoryName(tocpath) + "\\" + Path.GetFileNameWithoutExtension(tocpath) + ".sb"; SBFile sb = new SBFile(SBpath); root = sb.lines[0]; bundles = root.FindField("bundles"); List<BJSON.Entry> bundle_list =(List<BJSON.Entry>)bundles.data; //find right bundle for (int i = 0; i < bundle_list.Count; i++) { bun = bundle_list[i]; BJSON.Field ebx = bun.FindField("ebx"); BJSON.Field res = bun.FindField("res"); BJSON.Field chunks = bun.FindField("chunks"); BJSON.Field path = bun.FindField("path"); if (!(path != null && (string)path.data == bpath) || res == null || chunks == null) continue; bool found = false; byte[] chunkidbuff = new byte[16]; byte[] newchunkid = new byte[16]; //find right res entry List<BJSON.Entry> res_list = (List<BJSON.Entry>)res.data; for (int j = 0; j < res_list.Count; j++) { BJSON.Entry res_e = res_list[j]; BJSON.Field f_sha1 = res_e.FindField("sha1"); BJSON.Field f_name = res_e.FindField("name"); BJSON.Field f_size = res_e.FindField("size"); BJSON.Field f_osize = res_e.FindField("originalSize"); BJSON.Field f_casPatchType = res_e.FindField("casPatchType"); if (f_name != null && (string)f_name.data == mj.respath && f_sha1 != null) { //get res data and extract chunk id byte[] sha1buff = (byte[])f_sha1.data; DbgPrint(" Found res sha1 : " + Helpers.ByteArrayToHexString(sha1buff)); byte[] resdata = SHA1Access.GetDataBySha1(sha1buff); if (resdata.Length == 0) { DbgPrint(" Error: cant find res data, skipping!"); break; } for (int k = 0; k < 16; k++) chunkidbuff[k] = resdata[k + 0x1C]; DbgPrint(" Found chunk id : " + Helpers.ByteArrayToHexString(chunkidbuff)); newchunkid = Guid.NewGuid().ToByteArray(); DbgPrint(" Creating new chunk id : " + Helpers.ByteArrayToHexString(newchunkid)); for (int k = 0; k < 16; k++) resdata[k + 0x1C] = newchunkid[k]; int newrescompsize = 0; byte[] newressha1 = CreateCASContainer(resdata, out newrescompsize, " "); DbgPrint(" Creating new res sha1 : " + Helpers.ByteArrayToHexString(newressha1)); f_sha1.data = newressha1; DbgPrint(" Updating res size : " + resdata.Length); f_size.data = BitConverter.GetBytes((long)newrescompsize); f_osize.data = BitConverter.GetBytes((long)resdata.Length); if (f_casPatchType != null) { if (BitConverter.ToInt32((byte[])f_casPatchType.data, 0) != 1) { DbgPrint(" CasPatchType: found and set to 1!"); f_casPatchType.data = BitConverter.GetBytes((int)1); } else DbgPrint(" CasPatchType: found and is fine!"); } else { f_casPatchType = new BJSON.Field(); f_casPatchType.fieldname = "casPatchType"; f_casPatchType.type = 8; f_casPatchType.data = BitConverter.GetBytes((int)1); res_e.fields.Add(f_casPatchType); DbgPrint(" CasPatchType: added and set to 1!"); } found = true; } } if (!found) { DbgPrint(" Error: cant find res, skipping!"); break; } found = false; //find right chunk entry List<BJSON.Entry> chunk_list = (List<BJSON.Entry>)chunks.data; for (int j = 0; j < chunk_list.Count; j++) { BJSON.Entry chunk_e = chunk_list[j]; BJSON.Field f_id = chunk_e.FindField("id"); BJSON.Field f_size = chunk_e.FindField("size"); BJSON.Field f_rangeStart = chunk_e.FindField("rangeStart"); BJSON.Field f_rangeEnd = chunk_e.FindField("rangeEnd"); BJSON.Field f_logicalOffset = chunk_e.FindField("logicalOffset"); BJSON.Field f_logicalSize = chunk_e.FindField("logicalSize"); BJSON.Field f2_sha1 = chunk_e.FindField("sha1"); BJSON.Field f_casPatchType2 = chunk_e.FindField("casPatchType"); if (f_id != null && Helpers.ByteArrayCompare((byte[])f_id.data, chunkidbuff)) { DbgPrint(" Found chunk"); f_id.data = newchunkid; found = true; if (f_casPatchType2 != null) { if (BitConverter.ToInt32((byte[])f_casPatchType2.data, 0) != 1) { DbgPrint(" CasPatchType: found and set to 1!"); f_casPatchType2.data = BitConverter.GetBytes((int)1); } else DbgPrint(" CasPatchType: found and is fine!"); } else { f_casPatchType2 = new BJSON.Field(); f_casPatchType2.fieldname = "casPatchType"; f_casPatchType2.type = 8; f_casPatchType2.data = BitConverter.GetBytes((int)1); chunk_e.fields.Add(f_casPatchType2); DbgPrint(" CasPatchType: added and set to 1!"); } f_size.data = BitConverter.GetBytes(newcompressedsize); if (f_rangeStart != null) f_rangeStart.data = BitConverter.GetBytes((int)0); if (f_rangeEnd != null) f_rangeEnd.data = BitConverter.GetBytes(newcompressedsize); if (f_logicalOffset != null) f_logicalOffset.data = BitConverter.GetBytes((int)0); if (f_logicalSize != null) f_logicalSize.data = BitConverter.GetBytes(mj.data.Length); f2_sha1.data = newsha1; DbgPrint(" Updated chunk size : " + mj.data.Length); CalcTotalSize(bun); sb.Save(); found = true; DbgPrint(" Replaced chunk sha1 and saved SB file"); DbgPrint(" Job successfull!"); break; } } if (!found) DbgPrint(" Error: Could not find Chunk by id"); } } }
public void RunTextureJob(Mod.ModJob mj) { DbgPrint("Running Texture Replacement Job for: " + mj.respath); //Check Toc Files List<string> reducedTocPaths = new List<string>(); bool found = false; foreach (string p in mj.tocPaths) { found = false; for (int i = 0; i < reducedTocPaths.Count; i++) if (p == reducedTocPaths[i]) { found = true; break; } if (!found) reducedTocPaths.Add(p); } mj.tocPaths = reducedTocPaths; List<string> reducedBundlePaths = new List<string>(); foreach (string p in mj.bundlePaths) { found = false; for (int i = 0; i < reducedBundlePaths.Count; i++) if (p == reducedBundlePaths[i]) { found = true; break; } if (!found) reducedBundlePaths.Add(p); } mj.bundlePaths = reducedBundlePaths; foreach (string tocpath in mj.tocPaths) { if (tocpath.ToLower().Contains("\\patch\\")) continue; DbgPrint("Checking for : " + tocpath); if (!tocpath.ToLower().StartsWith("update")) { if (!File.Exists(outputPath + tocpath)) { string from = GlobalStuff.FindSetting("gamepath") + tocpath; string to = outputPath + tocpath; Directory.CreateDirectory(Path.GetDirectoryName(to) + "\\"); DbgPrint("TOC file not found, copying from base!"); try { File.Copy(from, to); } catch (Exception) { DbgPrint("Error: TOC file not found, can not copy from base!\n Tried to copy from:\n\t" + from + "\n to:\n\t" + to); return; } from = GlobalStuff.FindSetting("gamepath") + tocpath.ToLower().Replace(".toc",".sb"); to = outputPath + tocpath.ToLower().Replace(".toc", ".sb"); Directory.CreateDirectory(Path.GetDirectoryName(to) + "\\"); try { File.Copy(from, to); } catch (Exception) { DbgPrint("Error: SB file not found, can not copy from base!\n Tried to copy from:\n\t" + from + "\n to:\n\t" + to); return; } DbgPrint("Fixing layout.toc..."); TOCFile toc = new TOCFile(outputPath + "Data\\layout.toc"); BJSON.Entry root = toc.lines[0]; BJSON.Field sbun = root.FindField("superBundles"); List<BJSON.Entry> list = (List<BJSON.Entry>)sbun.data; BJSON.Entry ne = new BJSON.Entry(); ne.type = 0x82; ne.fields = new List<BJSON.Field>(); ne.fields.Add(new BJSON.Field(7, "name", tocpath.Replace(".toc", ""))); ne.fields.Add(new BJSON.Field(6, "delta", true)); list.Add(ne); sbun.data = list; toc.Save(); DbgPrint("SuperBundle added"); } } else { if (!File.Exists(outputPath + Helpers.SkipSubFolder(tocpath, 2))) { string from = GlobalStuff.FindSetting("gamepath") + tocpath; string to = outputPath + Helpers.SkipSubFolder(tocpath, 2); Directory.CreateDirectory(Path.GetDirectoryName(to) + "\\"); DbgPrint("TOC file not found, copying from base!"); try { File.Copy(from, to); } catch (Exception) { DbgPrint("Error: TOC file not found, can not copy from base!\n Tried to copy from:\n\t" + from + "\n to:\n\t" + to); return; } from = GlobalStuff.FindSetting("gamepath") + tocpath.ToLower().Replace(".toc", ".sb"); to = outputPath + Helpers.SkipSubFolder(tocpath, 2).ToLower().Replace(".toc", ".sb"); Directory.CreateDirectory(Path.GetDirectoryName(to) + "\\"); try { File.Copy(from, to); } catch (Exception) { DbgPrint("Error: SB file not found, can not copy from base!\n Tried to copy from:\n\t" + from + "\n to:\n\t" + to); return; } DbgPrint("Fixing layout.toc..."); TOCFile toc = new TOCFile(outputPath + "Data\\layout.toc"); BJSON.Entry root = toc.lines[0]; BJSON.Field sbun = root.FindField("superBundles"); List<BJSON.Entry> list = (List<BJSON.Entry>)sbun.data; BJSON.Entry ne = new BJSON.Entry(); ne.type = 0x82; ne.fields = new List<BJSON.Field>(); ne.fields.Add(new BJSON.Field(7, "name", Helpers.SkipSubFolder(tocpath, 2).Replace(".toc", ""))); ne.fields.Add(new BJSON.Field(6, "delta", true)); list.Add(ne); sbun.data = list; toc.Save(); DbgPrint("SuperBundle added"); } } } DbgPrint("All found."); //create cas data int newcompressedsize = 0; byte[] newsha1 = CreateCASContainer(mj.data, out newcompressedsize); if (newsha1.Length != 0x14) { DbgPrint("Error: could not create CAS data, aborting!"); return; } //walk through affected toc files foreach (string tocpath in mj.tocPaths) RunTextureResJob(mj, tocpath, newsha1, newcompressedsize); }
public void RunRessourceJobOnBundle(Mod.ModJob mj, TOCFile toc, string tocpath, byte[] newsha1, string bpath, int newcompressedsize) { GC.Collect(); int count = 0; int index = -1; foreach (TOCFile.TOCBundleInfoStruct buni in toc.bundles) if (count++ > -1 && bpath.ToLower() == buni.id.ToLower()) { DbgPrint(" Found bundle : " + bpath); index = count - 1; break; } //if bundle found if (index != -1) { if (!toc.iscas) { DbgPrint(" Warning: binary bundles not supported yet, skipping!"); return; } //find out if base or delta BJSON.Entry root = toc.lines[0]; BJSON.Field bundles = root.FindField("bundles"); BJSON.Entry bun = ((List<BJSON.Entry>)bundles.data)[index]; BJSON.Field isDeltaField = bun.FindField("delta"); BJSON.Field isBaseField = bun.FindField("base"); //if is base, copy from base, make delta and recompile if (isBaseField != null && (bool)isBaseField.data == true) if (!ImportBundleFromBase(toc, tocpath, index, bpath)) return; //check if already is in sb if (isDeltaField != null && (bool)isDeltaField.data == true) DbgPrint(" Its already a delta"); DbgPrint(" Updating SB file with new SHA1...");//yeah, pretty much string SBpath = outputPath + Path.GetDirectoryName(tocpath) + "\\" + Path.GetFileNameWithoutExtension(tocpath) + ".sb"; SBFile sb = new SBFile(SBpath); root = sb.lines[0]; bundles = root.FindField("bundles"); List<BJSON.Entry> bundle_list = (List<BJSON.Entry>)bundles.data; //find right bundle for (int i = 0; i < bundle_list.Count; i++) { bun = bundle_list[i]; BJSON.Field ebx = bun.FindField("ebx"); BJSON.Field res = bun.FindField("res"); BJSON.Field path = bun.FindField("path"); if (!(path != null && ((string)path.data).ToLower() == bpath.ToLower()) || res == null) continue; bool found = false; //find right res entry List<BJSON.Entry> res_list = (List<BJSON.Entry>)res.data; for (int j = 0; j < res_list.Count; j++) { BJSON.Entry res_e = res_list[j]; BJSON.Field f_sha1 = res_e.FindField("sha1"); BJSON.Field f_name = res_e.FindField("name"); BJSON.Field f_size = res_e.FindField("size"); BJSON.Field f_osize = res_e.FindField("originalSize"); BJSON.Field f_casPatchType = res_e.FindField("casPatchType"); if (f_name != null && ((string)f_name.data).ToLower() == mj.respath.ToLower() && f_sha1 != null) { //get res data byte[] sha1buff = (byte[])f_sha1.data; DbgPrint(" Found res sha1 : " + Helpers.ByteArrayToHexString(sha1buff)); f_sha1.data = newsha1; DbgPrint(" Replaced res sha1 with : " + Helpers.ByteArrayToHexString(newsha1)); DbgPrint(" Updating res size : " + mj.data.Length); f_size.data = BitConverter.GetBytes((long)newcompressedsize); f_osize.data = BitConverter.GetBytes((long)mj.data.Length); if (f_casPatchType != null) { if (BitConverter.ToInt32((byte[])f_casPatchType.data, 0) != 1) { DbgPrint(" CasPatchType: found and set to 1!"); f_casPatchType.data = BitConverter.GetBytes((int)1); } else DbgPrint(" CasPatchType: found and is fine!"); } else { f_casPatchType = new BJSON.Field(); f_casPatchType.fieldname = "casPatchType"; f_casPatchType.type = 8; f_casPatchType.data = BitConverter.GetBytes((int)1); res_e.fields.Add(f_casPatchType); DbgPrint(" CasPatchType: added and set to 1!"); } CalcTotalSize(bun); sb.Save(); DbgPrint(" Job successfull!"); found = true; } } if (!found) { DbgPrint(" cant find res, adding it!"); BJSON.Entry newres = new BJSON.Entry(); newres.type = 0x82; newres.fields = new List<BJSON.Field>(); newres.fields.Add(new BJSON.Field(7, "name", mj.respath)); newres.fields.Add(new BJSON.Field(0x10, "sha1", newsha1)); newres.fields.Add(new BJSON.Field(9, "size", BitConverter.GetBytes((long)newcompressedsize))); newres.fields.Add(new BJSON.Field(9, "originalSize", BitConverter.GetBytes((long)mj.data.Length))); newres.fields.Add(new BJSON.Field(0x8, "resType", Helpers.HexStringToByteArray(mj.restype))); newres.fields.Add(new BJSON.Field(0x13, "resMeta", new byte[0x10])); newres.fields.Add(new BJSON.Field(9, "resRid", BitConverter.GetBytes((long)0))); newres.fields.Add(new BJSON.Field(8, "casPatchType", BitConverter.GetBytes((int)1))); ((List<BJSON.Entry>)res.data).Add(newres); CalcTotalSize(bun); sb.Save(); DbgPrint(" Job successfull!"); break; } } } }
public bool ImportBundleFromBase(TOCFile toc, string tocpath, int index, string bpath) { DbgPrint(" Its a base reference! Copying in from base..."); //Find base toc string basepath = GlobalStuff.FindSetting("gamepath"); if (!File.Exists(basepath + tocpath)) { DbgPrint("Error: base TOC file not found, skipping!"); return false; } TOCFile otoc = new TOCFile(basepath + tocpath); //get base bundle data byte[] buff = otoc.ExportBundleDataByPath(bpath); if (buff.Length == 0) { DbgPrint("Error: base bundle not found, skipping!"); return false; } //get old sb file string oldSBpath = outputPath + Path.GetDirectoryName(tocpath) + "\\" + Path.GetFileNameWithoutExtension(tocpath) + ".sb"; if (!File.Exists(oldSBpath)) { DbgPrint("Error: patch SB file not found, skipping!"); return false; } DbgPrint(" Got copy, recompiling..."); //recompiling new sb in memory MemoryStream newSB = new MemoryStream(); FileStream oldSB = new FileStream(oldSBpath, FileMode.Open, FileAccess.Read); long glob_off = 0; BJSON.Entry root = toc.lines[0]; BJSON.Field bundles = root.fields[0]; int count = ((List<BJSON.Entry>)bundles.data).Count(); DbgPrint(" Recompiling SB..."); //put one bundle after another that is not base as defined in toc for (int i = 0; i < count; i++) { //get entry infos BJSON.Entry b = ((List<BJSON.Entry>)bundles.data)[i]; BJSON.Field f_offset = b.FindField("offset"); BJSON.Field f_size = b.FindField("size"); BJSON.Field f_isBase = b.FindField("base"); //if not our target and not copied from base, copy from old SB if (i != index && f_isBase == null) { int size = BitConverter.ToInt32((byte[])f_size.data, 0); CopyFileStream(oldSB, newSB, BitConverter.ToInt64((byte[])f_offset.data, 0), size); f_offset.data = BitConverter.GetBytes(glob_off); glob_off += size; } //if target, replace data, make delta if (i == index) { f_offset.data = BitConverter.GetBytes(glob_off); f_size.data = BitConverter.GetBytes(buff.Length); f_isBase.fieldname = "delta"; newSB.Write(buff, 0, buff.Length); glob_off += buff.Length; } } oldSB.Close(); //rebuilding new SB oldSB = new FileStream(oldSBpath, FileMode.Create, FileAccess.Write); //creating bundle header field MemoryStream t = new MemoryStream(); Helpers.WriteLEB128(t, (int)newSB.Length); newSB.WriteByte(0); int varsize = (int)t.Length; //add root entry oldSB.WriteByte(0x82); Helpers.WriteLEB128(oldSB, varsize + 9 + (int)newSB.Length); byte[] buff2 = { 0x01, 0x62, 0x75, 0x6E, 0x64, 0x6C, 0x65, 0x73, 0x00 }; oldSB.Write(buff2, 0, 9); oldSB.Write(t.ToArray(), 0, varsize); //header done, grab header offset and put all bundles int rel_off = (int)oldSB.Position; oldSB.Write(newSB.ToArray(), 0, (int)newSB.Length); oldSB.Close(); //removing idata DbgPrint(" removing idata..."); SBFile sb = new SBFile(oldSBpath); BJSON.Entry newroot = sb.lines[0]; BJSON.Field newbundles = newroot.FindField("bundles"); List<BJSON.Entry> newbun_list = (List<BJSON.Entry>)newbundles.data; for (int i = 0; i < newbun_list.Count; i++) { BJSON.Field f_res = newbun_list[i].FindField("res"); List<BJSON.Entry> newres_list = (List<BJSON.Entry>)f_res.data; for (int j = 0; j < newres_list.Count; j++) newres_list[j].RemoveField("idata"); } sb.Save(); DbgPrint(" Recompiling TOC..."); //correct offsets in toc by new adding header offset count = ((List<BJSON.Entry>)bundles.data).Count(); for (int i = 0; i < count; i++) { BJSON.Entry b = ((List<BJSON.Entry>)bundles.data)[i]; BJSON.Field f_offset = b.FindField("offset"); BJSON.Field f_isBase = b.FindField("base"); //if is in sb file, update if (f_isBase == null) { long off = BitConverter.ToInt64((byte[])f_offset.data, 0); off += rel_off; f_offset.data = BitConverter.GetBytes(off); } } toc.Save(); DbgPrint(" Bundle imported"); return true; }
private void opnSingleToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog d = new OpenFileDialog(); d.Filter = "*.toc|*.toc"; if(d.ShowDialog() == System.Windows.Forms.DialogResult.OK) { toc = new TOCFile(d.FileName); SelectForDeletion = new List<bool>(); SelectForReplacement = new List<string>(); SelectForDuplication = new List<bool>(); foreach (TOCFile.TOCBundleInfoStruct b in toc.bundles) { SelectForDeletion.Add(false); SelectForReplacement.Add(null); SelectForDuplication.Add(false); } RefreshMe(); rtb2.Text = ""; } }
private void CompareTocs(string file1, string file2) { TOCFile toc1 = new TOCFile(file1); TOCFile toc2 = new TOCFile(file2); foreach (TOCFile.TOCBundleInfoStruct b in toc1.bundles) { TOCFile.TOCBundleInfoStruct b2 = new TOCFile.TOCBundleInfoStruct(); b2.id = ""; foreach(TOCFile.TOCBundleInfoStruct compare in toc2.bundles) if (b.id == compare.id) { b2 = compare; break; } if (b2.id == "") { P(" E:bundle not found in compare file - " + b.id); continue; } StringBuilder sb = new StringBuilder(); sb.Append(" D:bundle " + b.id + "\n"); if (b.isbase != b2.isbase) sb.AppendFormat(" -base is different ({0}) vs ({1})\n",b.isbase,b2.isbase); if (b.isdelta != b2.isdelta) sb.AppendFormat(" -delta is different ({0}) vs ({1})\n",b.isdelta,b2.isdelta); if (b.size != b2.size) sb.AppendFormat(" -size is different ({0}) vs ({1})\n",b.size, b2.size); if ((b.isbase != b2.isbase) || (b.isdelta != b2.isdelta) || (b.size != b2.size)) P(sb.ToString()); } if (!file1.ToLower().Contains("chunk")) foreach (TOCFile.TOCChunkInfoStruct b in toc1.chunks) { TOCFile.TOCChunkInfoStruct b2 = new TOCFile.TOCChunkInfoStruct(); b2.id = new byte[0]; foreach (TOCFile.TOCChunkInfoStruct compare in toc2.chunks) if (Helpers.ByteArrayCompare(b.id, compare.id)) { b2 = compare; break; } if (b2.id.Length == 0) { P(" E:chunk not found in compare file - " + Helpers.ByteArrayToHexString(b.id)); continue; } StringBuilder sb = new StringBuilder(); sb.Append(" D:chunk " + Helpers.ByteArrayToHexString(b.id) + "\n"); if (b.sha1 != null && Helpers.ByteArrayCompare(b.sha1,b2.sha1)) sb.AppendFormat(" -sha1 is different ({0}) vs ({1})\n", Helpers.ByteArrayToHexString(b.sha1), Helpers.ByteArrayToHexString(b2.sha1)); if (b.offset != b2.offset) sb.AppendFormat(" -offset is different ({0}) vs ({1})\n", b.offset, b2.offset); if (b.size != b2.size) sb.AppendFormat(" -size is different ({0}) vs ({1})\n", b.size, b2.size); if ((b.sha1 != null && Helpers.ByteArrayCompare(b.sha1, b2.sha1)) || (b.offset != b2.offset) || (b.size != b2.size)) P(sb.ToString()); } CompareSB(file1.ToLower().Replace(".toc", ".sb"), file2.ToLower().Replace(".toc", ".sb")); }
private void treeView3_AfterSelect(object sender, TreeViewEventArgs e) { TreeNode t = treeView3.SelectedNode; if (t == null || t.Nodes == null || t.Nodes.Count != 0) return; string path = Helpers.GetPathFromNode(t, "/"); for (int i = 0; i < tblist.Count; i++) if (path.Contains(tblist[i].bundlepath)) { DBAccess.BundleInformation bi = tblist[i]; if (bi.isbase) return; TOCFile toc = new TOCFile(bi.filepath); byte[] data = toc.ExportBundleDataByPath(bi.bundlepath); Bundle b = null; if (bi.incas) { List<BJSON.Entry> tmp = new List<BJSON.Entry>(); BJSON.ReadEntries(new MemoryStream(data), tmp); b = Bundle.Create(tmp[0]); } else b = Bundle.Create(data, true); if (b == null) return; if (b.ebx == null) b.ebx = new List<Bundle.ebxtype>(); if (b.res == null) b.res = new List<Bundle.restype>(); if (b.chunk == null) b.chunk = new List<Bundle.chunktype>(); int total = b.ebx.Count + b.res.Count + b.chunk.Count; StringBuilder sb = new StringBuilder(); sb.AppendFormat("Total count : {0}\n", total); sb.AppendFormat("EBX count : {0}\n", b.ebx.Count); sb.AppendFormat("RES count : {0}\n", b.res.Count); sb.AppendFormat("CHUNK count : {0}\n", b.chunk.Count); rtb1.Text = sb.ToString(); DBAccess.BundleInformation[] dupBun = DBAccess.GetBundleInformationById(bi.bundlepath); listBox3.Items.Clear(); int count = 0; int l = GlobalStuff.FindSetting("gamepath").Length; foreach (DBAccess.BundleInformation dup in dupBun) { DBAccess.TOCInformation ti = DBAccess.GetTocInformationByIndex(dup.tocIndex); listBox3.Items.Add((count++) + " : " + ti.path.Substring(l, ti.path.Length - l) + " -> Delta:" + dup.isdelta + " Base:" + dup.isbase); } } }
public bool ImportBundleBinaryFromBase(TOCFile toc, string tocpath, string bpath, bool isbase = true) { if(isbase) DbgPrint(" Its a base reference! Copying in from base..."); //Find base toc string basepath = GlobalStuff.FindSetting("gamepath"); if (!File.Exists(basepath + tocpath)) { DbgPrint("Error: base TOC file not found, skipping!"); return false; } TOCFile otoc = new TOCFile(basepath + tocpath); //get base bundle data byte[] buff = otoc.ExportBundleDataByPath(bpath); if (buff.Length == 0) { DbgPrint("Error: base bundle not found, skipping!"); return false; } //get old sb file string ttocpath = tocpath; if (tocpath.ToLower().Contains("update")) ttocpath = Helpers.SkipSubFolder(tocpath, 2); string oldSBpath = outputPath + Path.GetDirectoryName(ttocpath) + "\\" + Path.GetFileNameWithoutExtension(ttocpath) + ".sb"; if (!File.Exists(oldSBpath)) { DbgPrint("Error: patch SB file not found, skipping!"); return false; } DbgPrint(" Got copy, recompiling..."); //recompiling new sb in memory MemoryStream newSB = new MemoryStream(); FileStream oldSB = new FileStream(oldSBpath, FileMode.Open, FileAccess.Read); long glob_off = 0; BJSON.Entry root = toc.lines[0]; BJSON.Field bundles = root.fields[0]; int count = ((List<BJSON.Entry>)bundles.data).Count(); DbgPrint(" Recompiling SB..."); //put one bundle after another that is not base as defined in toc for (int i = 0; i < count; i++) { //get entry infos BJSON.Entry b = ((List<BJSON.Entry>)bundles.data)[i]; BJSON.Field f_id = b.FindField("id"); BJSON.Field f_offset = b.FindField("offset"); BJSON.Field f_size = b.FindField("size"); BJSON.Field f_isBase = b.FindField("base"); BJSON.Field f_isDelta = b.FindField("delta"); //if not our target and not copied from base, copy from old SB if (((string)f_id.data).ToLower() != bpath && f_isBase == null) { int size = BitConverter.ToInt32((byte[])f_size.data, 0); CopyFileStream(oldSB, newSB, BitConverter.ToInt64((byte[])f_offset.data, 0), size); f_offset.data = BitConverter.GetBytes(glob_off); glob_off += size; } //if target, replace data, make delta if (((string)f_id.data).ToLower() == bpath) { f_offset.data = BitConverter.GetBytes(glob_off); f_size.data = BitConverter.GetBytes(buff.Length); if (f_isBase != null) f_isBase.fieldname = "delta"; newSB.Write(buff, 0, buff.Length); glob_off += buff.Length; } } oldSB.Close(); //rebuilding new SB oldSB = new FileStream(oldSBpath, FileMode.Create, FileAccess.Write); oldSB.Write(newSB.ToArray(), 0, (int)newSB.Length); oldSB.Close(); DbgPrint(" Recompiling TOC..."); toc.Save(); DbgPrint(" Bundle imported"); return true; }
private void RefreshPreview() { try { int n = listBox2.SelectedIndex; if (n == -1) return; status.Text = "Getting header infos from db..."; Application.DoEvents(); DBAccess.RESInformation ti = ttprevlist[n]; DBAccess.BundleInformation buni = DBAccess.GetBundleInformationById(ti.bundlepath)[0]; DBAccess.TOCInformation toci = DBAccess.GetTocInformationByIndex(buni.tocIndex); BinaryBundle b = new BinaryBundle(); byte[] resdata = new byte[0]; if (toci.incas) { status.Text = "Getting header data from sha1..."; Application.DoEvents(); resdata = SHA1Access.GetDataBySha1(Helpers.HexStringToByteArray(ti.sha1)); } else { status.Text = "Getting header data from binary bundle..."; Application.DoEvents(); TOCFile toc = new TOCFile(toci.path); byte[] bundledata = toc.ExportBundleDataByPath(buni.bundlepath); b = new BinaryBundle(new MemoryStream(bundledata)); foreach (BinaryBundle.ResEntry res in b.ResList) if (res._name == ti.resname) { resdata = res._data; break; } } hb2.ByteProvider = new DynamicByteProvider(resdata); Mesh mesh = new Mesh(new MemoryStream(resdata)); foreach (Mesh.MeshLOD lod in mesh.header.LODs) { byte[] id = lod.ChunkID; byte[] data = new byte[0]; if (toci.incas) { DBAccess.ChunkInformation ci = DBAccess.GetChunkInformationById(id); if (ci.sha1 == null) continue; data = SHA1Access.GetDataBySha1(ci.sha1); } else { byte t = id[0]; id[0] = id[3]; id[3] = t; t = id[1]; id[1] = id[2]; id[2] = t; t = id[6]; id[6] = id[7]; id[7] = t; t = id[4]; id[4] = id[5]; id[5] = t; foreach (BinaryBundle.ChunkEntry c in b.ChunkList) if (Helpers.ByteArrayCompare(id, c.id)) data = c._data; if (data.Length == 0) { DBAccess.ChunkInformation ci = DBAccess.GetChunkInformationById(id); if (ci.sha1 == null) continue; data = SHA1Access.GetDataBySha1(ci.sha1); } } mesh.LoadChunkData(lod, new MemoryStream(data)); } MeshRenderObject mro = new MeshRenderObject(mesh); renderer.list.Clear(); renderer.list.Add(mro); renderer.worldoffset = -mro.center; renderer.CamDistance = mro.min.Length() + mro.max.Length(); status.Text = "Ready"; } catch (Exception ex) { status.Text = "General error, after state '" + status.Text + "' : " + ex.Message; } }
private void toolStripMenuItem3_Click(object sender, EventArgs e) { OpenFileDialog d = new OpenFileDialog(); d.Filter = "*.bundle|*.bundle"; if (d.ShowDialog() == System.Windows.Forms.DialogResult.OK) { toc = null; toolStrip1.Visible = true; splitContainer2.BringToFront(); MemoryStream m = new MemoryStream(File.ReadAllBytes(d.FileName)); binBundle = new BinaryBundle(m); tabControl1.BringToFront(); RefreshBinary(); RefreshBinaryBundle(); return; } }