private void ExtractCallback(object ctx) { WorkUnit unit = (WorkUnit)ctx; EmbeddedFileInfo efi = unit.efi; byte[] buffer = new byte[efi.size]; IntPtr fileMemAddress = new IntPtr(unit.fileVolAddress); Marshal.Copy(fileMemAddress, buffer, 0, buffer.Length); if (unit.callback != null) { unit.callback(String.Format("Extracted {0} from VOL", efi.name)); } // I tried async-ing this write in the decomp case, but it was magnitudes slower unit.destFile.Write(buffer, 0, buffer.Length); if (unit.callback != null) { unit.callback(String.Format("Finished writing {0} bytes of {1}", buffer.Length, efi.name)); } if (unit.shouldDecompAfter) { // create a mem stream on the buffer so we can decomp without having to hit the filesystem // on both the read and the write MemoryStream memGz = new MemoryStream(buffer, false); using (FileStream destFile = GetUnzippedFileFromOrig(unit.destFile.Name)) using (GZipInputStream srcStream = new GZipInputStream(memGz)) { byte[] readBuf = new byte[0x8000]; StreamUtils.Copy(srcStream, destFile, readBuf); if (unit.callback != null) { unit.callback(String.Format("Ungzipped {0} bytes to {1} for {2}", memGz.Length, destFile.Position, efi.name)); } } } unit.finishedHandle.Set(); string fileName = unit.destFile.Name; unit.destFile.Close(); DateTime fileTime = new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(unit.efi.dateTime); File.SetCreationTime(fileName, fileTime); File.SetLastWriteTime(fileName, fileTime); File.SetLastAccessTime(fileName, fileTime); }
private void ExtractSingleFile(EmbeddedFileInfo efi, string dir, bool decompGZ, bool waitForCompletion, ExplodeProgressCallback epc) { ManualResetEvent finEvent = new ManualResetEvent(false); if (!waitForCompletion) { outstandingRequests.Add(finEvent); } WorkUnit unit = new WorkUnit(dir, efi, this, decompGZ, finEvent, epc); if (!ThreadPool.QueueUserWorkItem(new WaitCallback(ExtractCallback), unit)) { throw new ThreadInterruptedException("No Threadpool Threads"); } if (waitForCompletion) { finEvent.WaitOne(); finEvent.Close(); } }
public WorkUnit( string dir, EmbeddedFileInfo efiParam, VolFile volFile, bool decompGZ, ManualResetEvent compEvent, ExplodeProgressCallback epc ) { efi = efiParam; destFile = new FileStream( Path.Combine(dir, efi.name), FileMode.Create, FileAccess.ReadWrite, FileShare.None, 8192, false ); fileVolAddress = volFile.volMappingAddrAsNum + efi.fileAddress; shouldDecompAfter = (decompGZ && efi.name.EndsWith(".gz")); finishedHandle = compEvent; callback = epc; }
public void ExtractSingleFile(EmbeddedFileInfo efi, string dir, bool decompGZ) { ExtractSingleFile(efi, dir, decompGZ, true, null); }
static void ReadEmbeddedFileData( List <EmbeddedFileInfo> files, short numFiles, BinaryReader src, uint[] fileOffsets, TocFileNotify notifyFn, long volStartAddress ) { List <string> directories = new List <string>(); string dirBeingParsed = String.Empty; EmbeddedFileInfo lastFile = null; int dirIndex = 0, dirInsertIndex = 0; short i = 0; for (; i < numFiles; ++i) { EmbeddedFileInfo efi = new EmbeddedFileInfo(); efi.dateTime = src.ReadInt32(); int offsetIndex = src.ReadInt16(); byte flags = src.ReadByte(); uint bytesFromLastSector = 0; // flags // 0x00 = regular file // 0x01 = directory // 0x80 = last entry for this directory if (offsetIndex == 0 || (flags & 0x1) == 0x1) { // '..' entries and directories don't have an offset efi.fileAddress = 0; efi.pFileStart = IntPtr.Zero; } else { efi.fileAddress = SanitiseOffset(fileOffsets[offsetIndex], out bytesFromLastSector); efi.pFileStart = new IntPtr(volStartAddress + efi.fileAddress); } // cache this here for now, it's not the actual size, but it's used in its calculation efi.size = bytesFromLastSector; efi.name = Path.Combine(dirBeingParsed, Encoding.ASCII.GetString(src.ReadBytes(25)).TrimEnd('\0')); if ((flags & 0x1) != 0) { // '..' don't need saving if (!efi.name.EndsWith("..")) { // if we're parsing one, this is a child directory // its' contents are after the one being parsed, not at the end of the list if (dirBeingParsed != String.Empty) { directories.Insert(dirInsertIndex++, efi.name); } else { directories.Add(efi.name); } } } else { if (lastFile != null) { uint realSize = efi.fileAddress - lastFile.fileAddress - lastFile.size; // realsize can be 0 if files are 0 bytes (everything in the replay dir) lastFile.size = realSize; if (notifyFn != null) { notifyFn(lastFile); } } lastFile = efi; } // if this is the last entry for this directory // change which dir we use as the parent if ((flags & 0x80) != 0) { // directories are listed in order of first encounter // so a simple iteration will suffice dirBeingParsed = (dirIndex < directories.Count) ? directories[dirIndex++] : String.Empty; dirInsertIndex = dirIndex; } // '..' entries don't need to be saved if (offsetIndex != 0) { files.Add(efi); } } // the last fileOffset is the length of the whole file lastFile.size = fileOffsets[fileOffsets.Length - 1] - lastFile.fileAddress - lastFile.size; lastFile.size = (lastFile.size > 0) ? lastFile.size : 0x800; if (notifyFn != null) { notifyFn(lastFile); } }
static void EmbeddedFileNotify(EmbeddedFileInfo efi) { Console.WriteLine("{3:x}: Found {0} at offset 0x{1:X} of size {2}", efi.name, efi.fileAddress, efi.size, i++); }