//------------------------- GUI Treeview Functions -------------------------- private void treeViewSfar_AfterSelect(object sender, TreeViewEventArgs e) { TreeNode node = treeViewSfar.SelectedNode; if (node == null || isFolder(node)) { return; } //prevents the image change node.SelectedImageIndex = node.ImageIndex; // if the program is extracting or replacing a file, it doesn't update the bottom status label if (!backgroundWorkerExtractFile.IsBusy && !backgroundWorkerEditFile.IsBusy) { toolStripStatusLabel.Text = node.Name; toolStripStatusLabel.Visible = true; } if (!dlcBase.fileList.Contains(FileNameHash.Compute(node.Name))) { return; } //the hard part begins here! sfarFile entry = dlcBase.fileList[FileNameHash.Compute(node.Name)]; int fileBlockIndex; int fileComprSize = 0; float fileSize; string strFileSize = ""; fileBlockIndex = entry.blockSizeIndex; textBoxFullName.Text = node.Name; textBoxHash.Text = entry.nameHash.ToString(); setSize(entry.uncompressedSize, out fileSize, ref strFileSize); textBoxUncSize.Text = fileSize.ToString("0.0", CultureInfo.InvariantCulture); labelUncSizeBytes.Text = strFileSize; if (fileBlockIndex != -1) { for (int i = 0; i < entry.blockSizeArray.Length; i++) { fileComprSize += entry.blockSizeArray[i]; } setSize(fileComprSize, out fileSize, ref strFileSize); textBoxComprSize.Text = fileSize.ToString("0.0", CultureInfo.InvariantCulture); labelComprSizeBytes.Text = strFileSize; } else { setSize(entry.uncompressedSize, out fileSize, ref strFileSize); textBoxComprSize.Text = fileSize.ToString("0.0", CultureInfo.InvariantCulture); labelComprSizeBytes.Text = strFileSize; } textBoxEntry.Text = "0x" + entry.entryOffset.ToString("X8"); textBoxBlockIndex.Text = fileBlockIndex.ToString(); textBoxDataOffset.Text = "0x" + entry.dataOffset[0].ToString("X8"); }
private void propertiesToolStripMenuItem_Click(object sender, EventArgs e) { TreeNode node = treeViewSfar.SelectedNode; string message = ""; float fileSize; float comprRatio; string strFileSize = ""; if (isFile(node)) { FileNameHash fileHash = FileNameHash.Compute(node.Name); sfarFile entry = dlcBase.fileList[fileHash]; int compressedSize = 0; if (entry.blockSizeIndex != -1) { foreach (int i in entry.blockSizeArray) { compressedSize += i; } } else { compressedSize = (int)entry.uncompressedSize; } message += "Full Path: " + entry.fileName + "\n\nHash file name: " + fileHash; setSize(entry.uncompressedSize, out fileSize, ref strFileSize); message += "\n\nFile size: " + fileSize.ToString("0.0", CultureInfo.InvariantCulture) + " " + strFileSize; message += " (" + entry.uncompressedSize.ToString("0,0", CultureInfo.InvariantCulture) + " Bytes)"; setSize(compressedSize, out fileSize, ref strFileSize); message += "\n\nCompressed size: " + fileSize.ToString("0.0", CultureInfo.InvariantCulture) + " " + strFileSize; message += " (" + compressedSize.ToString("0,0", CultureInfo.InvariantCulture) + " Bytes)"; comprRatio = compressedSize / (float)entry.uncompressedSize * 100; message += "\n\nCompression Ratio: " + comprRatio.ToString("0.#") + "%"; MessageBox.Show(message, "Properties - " + node.Text, MessageBoxButtons.OK, MessageBoxIcon.None); } }
//int highPerc = 0; #else public void Execute(string outputFile) { #endif var inputPath = dlcBase.fileName; if (!File.Exists(inputPath)) throw new FileNotFoundException("Error: the input file doesn't exists"); /*string filePathToReplace = selectedFile; string fileToReplace = Path.GetFileName(filePathToReplace); FileNameHash fileToReplaceHash = new FileNameHash();*/ string outputFileName = Path.GetFileNameWithoutExtension(inputPath); int inPointerBlockSize = 0; int outPointerEntry = 0x20; int outPointerEntryFileList = 0; int outPointerBlockSize = 0; int outPointerData = 0; int blocksToRemove = 0; int blocksToAdd = 0; using (FileStream input = File.OpenRead(inputPath), output = File.OpenWrite(outputFile)) { string dlcFileList = ""; int outNumOfEntries = 0; //recreating the file list foreach (var kvp in listComplete) { if (kvp.Value != action.delete) { outNumOfEntries++; if (kvp.Key == DLCBase.fileListHash) continue; switch (kvp.Value) { case action.copy: case action.replace: dlcFileList += dlcBase.fileList[kvp.Key].fileName + Environment.NewLine; break; case action.add: dlcFileList += listAdd[kvp.Key].fileName + Environment.NewLine; break; } } } blocksToRemove += dlcBase.fileList[DLCBase.fileListHash].blockSizeArray.Length; blocksToAdd += (int)Math.Ceiling((double)dlcFileList.Length / (double)DLCBase.MaximumBlockSize); foreach (var kvp in listAdd) { string fPath = kvp.Value.filePath; if ((Path.GetExtension(fPath) != ".bik" && Path.GetExtension(fPath) != ".afc")) blocksToAdd += (int)Math.Ceiling((double)DLCPack.Getsize(kvp.Value.filePath) / (double)DLCBase.MaximumBlockSize); } foreach (var kvp in listReplace) { if (dlcBase.fileList[kvp.Key].blockSizeIndex != -1) { blocksToRemove += dlcBase.fileList[kvp.Key].blockSizeArray.Length; blocksToAdd += (int)Math.Ceiling((double)DLCPack.Getsize(kvp.Value) / (double)DLCBase.MaximumBlockSize); } } foreach (var kvp in listDelete) { if (dlcBase.fileList[kvp.Key].blockSizeIndex != -1) blocksToRemove += dlcBase.fileList[kvp.Key].blockSizeArray.Length; } var inputBlock = new byte[DLCBase.MaximumBlockSize]; var outputBlock = new byte[DLCBase.MaximumBlockSize]; //writing header of new sfar file input.Seek(0, 0); input.Read(inputBlock, 0, 32); output.Write(inputBlock, 0, 32); //getting initial blocks and data offsets inPointerBlockSize = 0x20 + (dlcBase.fileList.Count * 0x1E); outPointerBlockSize = 0x20 + ((int)outNumOfEntries * 0x1E); input.Seek(8, 0); int inDataOffset = input.ReadValueS32(); int outBlockCount = ((inDataOffset - inPointerBlockSize) / 2) - blocksToRemove + blocksToAdd; outPointerData = outPointerBlockSize + (outBlockCount * 2); //writing new header's values output.Seek(8, 0); output.WriteValueS32(outPointerData); output.Seek(16, 0); output.WriteValueS32(outNumOfEntries); output.Seek(20, 0); output.WriteValueS32(outPointerBlockSize); if (verbose) { Console.WriteLine("num entries: {0}", outNumOfEntries); Console.WriteLine("data offset: {0:X8}", inDataOffset); Console.WriteLine("blocks to remove: {0}", blocksToRemove); Console.WriteLine("blocks to add: {0}", blocksToAdd); Console.WriteLine("old block offset: {0:X8}", inPointerBlockSize); Console.WriteLine("new block offset: {0:X8}", outPointerBlockSize); Console.WriteLine("old block count: {0}", (inDataOffset - inPointerBlockSize) / 2); Console.WriteLine("new block count: {0}", outBlockCount); Console.WriteLine("pointer data: {0:X8}\n", outPointerData); } int numBlocks; int outDataOffset; int blockIndexCounter = 0; int outBlockIndex = 0; int fileSize = 0; int outInitialDataOffset = outPointerData; int outInitialBlockOffset = outPointerBlockSize; foreach (var kvp in listComplete) { count++; if (kvp.Value == action.delete) continue; if (kvp.Key == DLCBase.fileListHash) { //Console.WriteLine("File List Found at {0:X8}", outPointerEntry); outPointerEntryFileList = outPointerEntry; outPointerEntry += 0x1E; continue; } sfarFile entry; FileNameHash hashEntry = kvp.Key; if (kvp.Value == action.add) { string fPath = listAdd[kvp.Key].filePath; entry = new sfarFile(); entry.nameHash = kvp.Key; entry.dataOffset = new long[1]; fileSize = (int)DLCPack.Getsize(fPath); if ((Path.GetExtension(fPath) == ".bik" || Path.GetExtension(fPath) == ".afc")) entry.blockSizeIndex = -1; } else { entry = dlcBase.fileList[kvp.Key]; fileSize = (int)entry.uncompressedSize; } outDataOffset = outPointerData; outBlockIndex = blockIndexCounter; /*#if (WITH_GUI) int perc = (int)Math.Ceiling((float)count++ / (float)listComplete.Count * 100); if (perc > highPerc) { highPerc = perc; if (perc > 100) perc = 100; worker.ReportProgress(perc); } #endif*/ switch (kvp.Value) { case action.copy: if (worker != null) worker.ReportProgress(0, count + "/" + listComplete.Count + ": Copying " + Path.GetFileName(entry.fileName)); if (entry.blockSizeIndex == -1) { inDataOffset = (int)entry.dataOffset[0]; input.Seek((long)inDataOffset, 0); inputBlock = new byte[fileSize]; input.Read(inputBlock, 0, fileSize); output.Seek((long)outPointerData, 0); output.Write(inputBlock, 0, fileSize); outPointerData += fileSize; outBlockIndex = entry.blockSizeIndex; } else { numBlocks = (int)Math.Ceiling((double)fileSize / (double)DLCBase.MaximumBlockSize); inDataOffset = (int)entry.dataOffset[0]; for (int i = 0; i < numBlocks; i++) { uint blockSize = entry.blockSizeArray[i]; if ((ushort)blockSize != entry.blockSizeArray[i]) throw new Exception("different blocksizes"); blockSize = blockSize == 0 ? DLCBase.MaximumBlockSize : blockSize; inputBlock = new byte[blockSize]; input.Seek((long)inDataOffset, 0); input.Read(inputBlock, 0, (int)blockSize); inDataOffset += (int)blockSize; output.Seek((long)outPointerBlockSize, 0); if (blockSize == DLCBase.MaximumBlockSize) output.WriteValueU16(0); else output.WriteValueU16((ushort)blockSize); if (outPointerBlockSize > outInitialDataOffset) throw new Exception("Block index offset values out of range,\n last block: " + blockIndexCounter + "\n Pointer Block: " + outPointerBlockSize.ToString("X8") + "\n Data Offset: " + outInitialDataOffset.ToString("X8")); outPointerBlockSize += 2; output.Seek((long)outPointerData, 0); output.Write(inputBlock, 0, (int)blockSize); if (output.Position - outPointerData != blockSize) { Console.WriteLine(" diff position: {0}, blocksize: {1}", output.Position - outPointerData, blockSize); throw new Exception("error writing file"); } outPointerData += (int)blockSize; } blockIndexCounter += numBlocks; } break; case action.add: case action.replace: string selectedFile; if (kvp.Value == action.replace) { selectedFile = listReplace[kvp.Key]; if (worker != null) worker.ReportProgress(0, count + "/" + listComplete.Count + ": Replacing " + Path.GetFileName(selectedFile)); } else { selectedFile = listAdd[kvp.Key].filePath; if (worker != null) worker.ReportProgress(0, count + "/" + listComplete.Count + ": Adding " + Path.GetFileName(selectedFile)); } output.Seek((long)outPointerBlockSize, 0); //compressing the replacing file ushort[] blockSizeArray; using (FileStream streamFile = new FileStream(selectedFile, FileMode.Open, FileAccess.Read)) { fileSize = (int)streamFile.Length; if ((Path.GetExtension(selectedFile) == ".bik" || Path.GetExtension(selectedFile) == ".afc") && entry.blockSizeIndex == -1) { outBlockIndex = -1; output.Seek((long)outPointerData, SeekOrigin.Begin); output.WriteFromStream(streamFile, streamFile.Length); outPointerData += (int)streamFile.Length; } else { byte[][] comprArr; DLCPack.CompressFile(streamFile, out blockSizeArray, out comprArr, Threads); for (int i = 0; i < blockSizeArray.Length; i++) output.WriteValueU16(blockSizeArray[i]); outPointerBlockSize += (blockSizeArray.Length * 2); blockIndexCounter += blockSizeArray.Length; output.Seek((long)outPointerData, SeekOrigin.Begin); int totallength = 0; for (int i = 0; i < comprArr.Length; i++) { output.WriteBytes(comprArr[i]); totallength += comprArr[i].Length; } //outPointerData += (int)streamFile.Length; outPointerData += totallength; } } #region blah di blah /* FileStream streamFile = File.OpenRead(selectedFile); if ((Path.GetExtension(selectedFile) == ".bik" || Path.GetExtension(selectedFile) == ".afc") && entry.blockSizeIndex == -1) { streamFile.CopyTo(encStream); outBlockIndex = -1; } else { //DLCPack.CompressFile(streamFile, out blockSizeArray, encStream, worker); byte[][] comprArr; DLCPack.CompressFile(streamFile, out blockSizeArray, out comprArr); for (int i = 0; i < blockSizeArray.Length; i++) { output.WriteValueU16(blockSizeArray[i]); } outPointerBlockSize += (blockSizeArray.Length * 2); blockIndexCounter += blockSizeArray.Length; } output.Seek((long)outPointerData, 0); encStream.WriteTo(output); outPointerData += (int)encStream.Length; fileSize = (int)streamFile.Length; streamFile.Close(); */ #endregion break; }// end switch if (worker != null) worker.ReportProgress(100); output.Seek((long)outPointerEntry, 0); output.WriteValueU32(hashEntry.A.Swap()); output.WriteValueU32(hashEntry.B.Swap()); output.WriteValueU32(hashEntry.C.Swap()); output.WriteValueU32(hashEntry.D.Swap()); output.WriteValueS32(outBlockIndex); output.WriteValueS32(fileSize); output.WriteValueU8(0); output.WriteValueS32(outDataOffset); output.WriteValueU8(0); outPointerEntry += 0x1E; if (outPointerEntry > outInitialBlockOffset) { throw new Exception("Entry index offset values out of range"); } }// end of foreach //writing the file list entry, blocksizes & data outDataOffset = outPointerData; outBlockIndex = blockIndexCounter; { MemoryStream streamRead = new MemoryStream(ASCIIEncoding.Default.GetBytes(dlcFileList)); ushort[] blockSizeArray; MemoryStream encStream = new MemoryStream(); DLCPack.CompressFile(streamRead, out blockSizeArray, encStream); output.Seek((long)outPointerBlockSize, 0); for (int i = 0; i < blockSizeArray.Length; i++) { output.WriteValueU16(blockSizeArray[i]); } outPointerBlockSize += (blockSizeArray.Length * 2); blockIndexCounter += blockSizeArray.Length; output.Seek((long)outPointerData, 0); encStream.WriteTo(output); outPointerData += (int)encStream.Length; fileSize = (int)streamRead.Length; output.Seek((long)outPointerEntryFileList, 0); output.WriteValueU32(DLCBase.fileListHash.A.Swap()); output.WriteValueU32(DLCBase.fileListHash.B.Swap()); output.WriteValueU32(DLCBase.fileListHash.C.Swap()); output.WriteValueU32(DLCBase.fileListHash.D.Swap()); output.WriteValueS32(outBlockIndex); output.WriteValueS32((int)fileSize); output.WriteValueU8(0x00); output.WriteValueS32(outDataOffset); output.WriteValueU8(0x00); outPointerEntry = (int)output.Position; } }// end of using... }
private void extractToolStripMenuItem_Click(object sender, EventArgs e) { TreeNode node = treeViewSfar.SelectedNode; extractFileDialog.FileName = node.Text; List <sfarFile> listFiles = new List <sfarFile>(); //add selected file(s) to the extraction list if (isFile(node) && extractFileDialog.ShowDialog() == DialogResult.OK) { sfarFile entry = dlcBase.fileList[FileNameHash.Compute(node.Name)]; listFiles.Add(entry); } else if (isFolder(node) && extractFolderDialog.ShowDialog() == Microsoft.WindowsAPICodePack.Dialogs.CommonFileDialogResult.Ok) { foreach (sfarFile entry in dlcBase.fileList) { string fileName = entry.fileName; int indexStr; if (fileName == null) { continue; } indexStr = fileName.IndexOf(node.Text); if (indexStr != -1) { listFiles.Add(entry); } } } else // safety else, hopefully never enters { return; } toolStripProgressBar.Visible = true; toolStripStatusLabel.Visible = true; try { //main extraction backgroundWorkerExtractFile.RunWorkerAsync(new object[2] { listFiles, node }); while (backgroundWorkerExtractFile.IsBusy) { // Keep UI messages moving, so the form remains // responsive during the asynchronous operation. if (backgroundWorkerExtractFile.CancellationPending) { return; } else { Application.DoEvents(); } } toolStripStatusLabel.Text = "Done."; if (isFile(node)) { MessageBox.Show("File " + node.Text + " has been successfully extracted.", "Extraction success", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { MessageBox.Show("All files from folder " + node.Text + " have been successfully extracted.", "Extraction success", MessageBoxButtons.OK, MessageBoxIcon.Information); } toolStripProgressBar.Visible = false; } catch (Exception exc) { MessageBox.Show("An error occurred while extracting " + node.Text + ":\n" + exc.Message, "Exception Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }