private void DoExtractHandler(object sender, DoWorkEventArgs e) { extractProgress = 0; if (fileNodeList.Count > 0) { FileNode rootnode = fileNodeList[0]; totalProgress = rootnode.getSelectedCount(); SetProgressbarMax(totalProgress); SetProgressbar(0, totalProgress); } if (totalProgress == 0) { if (!CNMode) { PrintLog("Nothing selected."); } else { PrintLog("未选择任何文件"); } Dispatcher.BeginInvoke(new Action(() => { ExtractBtn.IsEnabled = true; RegExCheckBox.IsEnabled = true; FilterBox.IsEnabled = true; ApplyFilterBtn.IsEnabled = true; PauseBtn.Visibility = Visibility.Hidden; TerminateBtn.Visibility = Visibility.Hidden; })); return; } if (!CNMode) { PrintLog("Export to: " + outputDirectory, true); PrintLog("It may take a long time to extract all the files you selected which depends on the file size and amount you selected."); } else { PrintLog("解包至: " + outputDirectory, true); PrintLog("根据你所选取的文件数量和大小,这可能会花费很长时间,请耐心等待"); } int failed = 0; if (mergeChecked) { chunkMap.FirstOrDefault().Value.ExtractSelected(fileNodeList, outputDirectory, this); } else { failed = mainChunk.ExtractSelected(fileNodeList, outputDirectory, this); } if (failed > 0) { if (!CNMode) { PrintLog($"{failed} files failed to extract in total."); } else { PrintLog($"总计{failed}个文件提取失败"); } } Dispatcher.BeginInvoke(new Action(() => { ExtractBtn.IsEnabled = true; RegExCheckBox.IsEnabled = true; FilterBox.IsEnabled = true; ApplyFilterBtn.IsEnabled = true; PauseBtn.Visibility = Visibility.Hidden; TerminateBtn.Visibility = Visibility.Hidden; PauseBtn.Background = System.Windows.Media.Brushes.Orange; PauseBtn.Content = CNMode ? "暂停" : "Pause"; terminateFlag = false; pauseFlag = false; })); if (!CNMode) { PrintLog("Finished!"); } else { PrintLog("提取完成!"); } }
// Learns from WorldChunkTool by MHVuze https://github.com/mhvuze/WorldChunkTool public List <FileNode> AnalyzeChunk(String FileInput, MainWindow mainwindow, List <FileNode> inputFileList) { bindingWindow = mainwindow; fileinput = FileInput; FileInfo fileinputInfo = new FileInfo(fileinput); if (!MainWindow.CNMode) { mainwindow.printlog($"Now analyzing {fileinputInfo.Name}"); } else { mainwindow.printlog($"正在解析 {fileinputInfo.Name}"); } ChunkCache = new Dictionary <int, byte[]>(); List <FileNode> filelist = inputFileList; MetaChunk = new Dictionary <long, long>(); ChunkOffsetDict = new Dictionary <int, long>(); string NamePKG = $"{Environment.CurrentDirectory}\\{Path.GetFileNameWithoutExtension(FileInput)}.pkg"; Reader = new BinaryReader(File.Open(FileInput, FileMode.Open, FileAccess.Read)); // Read header Reader.BaseStream.Seek(4, SeekOrigin.Begin); int ChunkCount = Reader.ReadInt32(); int ChunkPadding = ChunkCount.ToString().Length; if (!MainWindow.CNMode) { mainwindow.printlog($"{ChunkCount} subchunks detected."); } else { mainwindow.printlog($"解析到{ChunkCount}个子chunk "); } // Read file list DictCount = 0; long totalChunkSize = 0; for (int i = 0; i < ChunkCount; i++) { // Process file size byte[] ArrayTmp1 = new byte[8]; byte[] ArrayChunkSize = Reader.ReadBytes(3); int High = ArrayChunkSize[0] >> 4; ArrayChunkSize[0] = BitConverter.GetBytes(High)[0]; Array.Copy(ArrayChunkSize, ArrayTmp1, ArrayChunkSize.Length); long ChunkSize = BitConverter.ToInt64(ArrayTmp1, 0); // Fixes the original code's error on ChunkSize ChunkSize = (ChunkSize >> 4) + (ChunkSize & 0xF); totalChunkSize += ChunkSize; // Process offset byte[] ArrayTmp2 = new byte[8]; byte[] ArrayChunkOffset = Reader.ReadBytes(5); Array.Copy(ArrayChunkOffset, ArrayTmp2, ArrayChunkOffset.Length); long ChunkOffset = BitConverter.ToInt64(ArrayTmp2, 0); MetaChunk.Add(ChunkOffset, ChunkSize); ChunkOffsetDict.Add(i, ChunkOffset); DictCount = i + 1; } cur_index = 0; long cur_offset = ChunkOffsetDict[cur_index]; long cur_size = MetaChunk[cur_offset]; ChunkDecompressed = getDecompressedChunk(cur_offset, cur_size, Reader, cur_index); if (cur_index + 1 < DictCount) { NextChunkDecompressed = getDecompressedChunk(ChunkOffsetDict[cur_index + 1], MetaChunk[ChunkOffsetDict[cur_index + 1]], Reader, cur_index + 1); } else { NextChunkDecompressed = new byte[0]; } cur_pointer = 0x0C; int TotalParentCount = BitConverter.ToInt32(ChunkDecompressed, cur_pointer); cur_pointer += 4; int TotalChildrenCount = BitConverter.ToInt32(ChunkDecompressed, cur_pointer); cur_pointer = 0x100; FileNode root_node = null; for (int i = 0; i < TotalParentCount; i++) { string StringNameParent = getName(0x3C); long FileSize = getInt64(); long FileOffset = getInt64(); int EntryType = getInt32(); int CountChildren = getInt32(); if (filelist.Count == 0) { root_node = new FileNode(StringNameParent, false, FileInput); root_node.EntireName = root_node.Name; filelist.Add(root_node); } else { root_node = filelist[0]; root_node.FromChunk = fileinput; root_node.FromChunkName = $"({System.IO.Path.GetFileNameWithoutExtension(fileinput)})"; } for (int j = 0; j < CountChildren; j++) { int origin_pointer = cur_pointer; int origin_loc = cur_index; if (!ChunkCache.ContainsKey(cur_index)) { ChunkCache.Add(cur_index, ChunkDecompressed); } if (!ChunkCache.ContainsKey(cur_index + 1)) { ChunkCache.Add(cur_index + 1, NextChunkDecompressed); } string StringNameChild = getName(0xA0); FileSize = getInt64(); FileOffset = getInt64(); EntryType = getInt32(); int Unknown = getInt32(); if (EntryType == 0x02) { cur_pointer = origin_pointer; if (cur_index != origin_loc) { cur_index = origin_loc; ChunkDecompressed = ChunkCache[cur_index]; NextChunkDecompressed = ChunkCache[cur_index + 1]; ChunkCache.Remove(cur_index); ChunkCache.Remove(cur_index + 1); } StringNameChild = getName(0x50); getOnLength(0x68, new byte[0x68], 0); } string[] fathernodes = StringNameChild.Split('\\'); bool isFile = false; if (EntryType == 0x02 || EntryType == 0x00) { isFile = true; } FileNode child_node = new FileNode(fathernodes[fathernodes.Length - 1], isFile, FileInput); if (isFile) { child_node.Size = FileSize; child_node.Offset = FileOffset; child_node.ChunkIndex = (int)(FileOffset / 0x40000); child_node.ChunkPointer = (int)(FileOffset % 0x40000); } child_node.EntireName = StringNameChild; FileNode target_node = root_node; foreach (string node_name in fathernodes) { if (node_name.Equals("")) { continue; } foreach (FileNode node in target_node.Childern) { if (node.Name == node_name) { if (node.Name == child_node.Name) { break; } target_node = node; break; } } } bool need_add = true; foreach (FileNode tmp_node in target_node.Childern) { if (tmp_node.Name == child_node.Name) { if (child_node.IsFile) { target_node.Childern.Remove(tmp_node); } else { tmp_node.FromChunk = child_node.FromChunk; tmp_node.FromChunkName = child_node.FromChunkName; need_add = false; } break; } } if (need_add) { target_node.Childern.Add(child_node); } } mainwindow.setProgressbar(i + 1, TotalParentCount); } ChunkCache.Clear(); if (filelist.Count > 0) { filelist[0].getSize(); } return(filelist); }
private void DoExtractHandler(object sender, DoWorkEventArgs e) { extract_progress = 0; if (itemlist.Count > 0) { FileNode rootnode = itemlist[0]; total_progress = rootnode.getSelectedCount(); setProgressbarMax(total_progress); } if (total_progress == 0) { printlog("Nothing selected."); Dispatcher.BeginInvoke(new Action(() => { ExtractBtn.IsEnabled = true; })); return; } if (!CNMode) { printlog("Export to: " + output_directory); printlog("It may take a long time to extract all the files you selected which depends on the file size and amount you selected."); } else { printlog("解包至: " + output_directory); printlog("根据你所选取的文件数量和大小,这可能会花费很长时间,请耐心等待"); } int failed = 0; if (CombineChecked) { chunkMap.FirstOrDefault().Value.ExtractSelected(itemlist, output_directory, this); } else { failed = mainChunk.ExtractSelected(itemlist, output_directory, this); } if (failed > 0) { if (!CNMode) { printlog($"{failed} files failed to extract in total."); } else { printlog($"总计{failed}个文件提取失败"); } } Dispatcher.BeginInvoke(new Action(() => { ExtractBtn.IsEnabled = true; })); if (!CNMode) { printlog("Finished!"); } else { printlog("提取完成!"); } }