public static string DecompressLZMA(byte[] compressedFile) { IntPtr intPtr = new IntPtr(compressedFile.Length - 13); byte[] array = new byte[intPtr.ToInt64()]; IntPtr outPropsSize = new IntPtr(5); byte[] array2 = new byte[5]; compressedFile.CopyTo(array, 13); for (int i = 0; i < 5; i++) { array2[i] = compressedFile[i]; } int num = 0; for (int j = 0; j < 8; j++) { num += (int)compressedFile[j + 5] << 8 * j; } IntPtr intPtr2 = new IntPtr(num); byte[] array3 = new byte[num]; int num2 = LZMA.LzmaUncompress(array3, ref intPtr2, array, ref intPtr, array2, outPropsSize); if (num2 != 0) { MessageBox.Show("Decompression returned " + num2); } return(new string(Encoding.UTF8.GetString(array3).ToCharArray())); }
// Extract a LZMA-compressed file. private async Task HandleCompressedFile(SFileInfo fileInfo, BinaryReader binaryReader, string sectionUrl) { // Console.WriteLine($"[FILE-{fileInfo.Section} {fileInfo.FullPath}]: handling compressed file"); // A multipart file can span multiple sections, // so we have to keep track of how much has been read. // This code is kind of irritating and semi-confusing, but it works. if (binaryReader.BaseStream.Position + fileInfo.CompressedLength > binaryReader.BaseStream.Length) { // Console.WriteLine( // $" Multi-part file detected @ 0x{binaryReader.BaseStream.Position:X8} (total {fileInfo.CompressedLength}, reader has {binaryReader.BaseStream.Length - binaryReader.BaseStream.Position})"); var bytesRead = 0; var maxBytesRead = fileInfo.CompressedLength - 13; // header is 13 bytes var curSection = fileInfo.Section; var props = binaryReader.ReadBytes(5); binaryReader.BaseStream.Seek(8, SeekOrigin.Current); // Here we're reading fragments until we've got everything. // First we read as much data from the current section as we can. var bytes = new List <byte>(); var readFromMaster = (int)(binaryReader.BaseStream.Length - binaryReader.BaseStream.Position); bytes.AddRange(binaryReader.ReadBytes(readFromMaster)); bytesRead += readFromMaster; // Then, we continuously jump to the next section, until all the data is retrieved. while (bytesRead < maxBytesRead) { // Create a new section URL that gives us access to the next section. var newSectUrl = sectionUrl.Replace($"section{fileInfo.Section}", $"section{++curSection}"); // Fetch a BinaryReader for the new section. var newSectReader = await FetchSection(newSectUrl); // Calculate the remaining number of bytes to read. // This takes into account the length of the section as opposed to the total length of the file. var bytesToRead = (int)Math.Min(newSectReader.BaseStream.Length, maxBytesRead - bytes.Count); bytes.AddRange(newSectReader.ReadBytes(bytesToRead)); bytesRead += bytesToRead; } var destLen = new IntPtr(fileInfo.Length); var srcLen = new IntPtr(fileInfo.CompressedLength - 13); var inData = bytes.ToArray(); bytes.Clear(); var decompressedOutput = new byte[destLen.ToInt32()]; LZMA.LzmaUncompress(decompressedOutput, ref destLen, inData, ref srcLen, props, _propsSizePtr); using (var outStream = new FileStream(fileInfo.FullPath, FileMode.Create)) { outStream.Write(decompressedOutput, 0, decompressedOutput.Length); } decompressedOutput = null; props = null; inData = null; } else { // Thankfully there are some files that are small and don't require reading multiple sections at a time. var destLen = new IntPtr(fileInfo.Length); var srcLen = new IntPtr(fileInfo.CompressedLength - 13); var props = binaryReader.ReadBytes(5); binaryReader.BaseStream.Seek(8, SeekOrigin.Current); var bytes = new byte[fileInfo.CompressedLength]; binaryReader.Read(bytes, 0, bytes.Length); var decompressedOutput = new byte[destLen.ToInt32()]; LZMA.LzmaUncompress(decompressedOutput, ref destLen, bytes, ref srcLen, props, _propsSizePtr); using (var outStream = new FileStream(fileInfo.FullPath, FileMode.Create)) { outStream.Write(decompressedOutput, 0, decompressedOutput.Length); } bytes = null; decompressedOutput = null; props = null; } }
public void LzmaUncompress(SharedSettings s) { switch (s.Variant) { case 1: { var decoder = new LZMA.CLzmaDec(); decoder.LzmaDec_Construct(); var res = decoder.LzmaDec_Allocate(P.From(s.Enc), checked ((uint)s.Enc.Length), LZMA.ISzAlloc.SmallAlloc); if (res != LZMA.SZ_OK) { throw new Exception("Allocate failed: " + res); } decoder.LzmaDec_Init(); P <byte> dstPtr = P.From(s.Dst); long s_WrittenSize = s.Dst.Length; s.WrittenSize = 0; P <byte> srcPtr = P.From(s.Src); long s_UsedSize = s.Src.Length; s.UsedSize = 0; for (;;) { LZMA.ELzmaStatus status; res = decoder.LzmaDec_DecodeToBuf(dstPtr, ref s_WrittenSize, srcPtr, ref s_UsedSize, LZMA.ELzmaFinishMode.LZMA_FINISH_END, out status); if (res != LZMA.SZ_OK) { throw new Exception("DecodeToBuf failed: " + res); } s.WrittenSize += checked ((int)s_WrittenSize); s.UsedSize += checked ((int)s_UsedSize); dstPtr += s_WrittenSize; srcPtr += s_UsedSize; s_WrittenSize = dstPtr.mBuffer.Length - dstPtr.mOffset; s_UsedSize = srcPtr.mBuffer.Length - srcPtr.mOffset; if (status == LZMA.ELzmaStatus.LZMA_STATUS_NEEDS_MORE_INPUT || status == LZMA.ELzmaStatus.LZMA_STATUS_NOT_FINISHED) { continue; } if (status == LZMA.ELzmaStatus.LZMA_STATUS_FINISHED_WITH_MARK) { if (s.ActualWriteEndMark == 0) { throw new Exception("Finished with mark even though we didn't want to write one."); } break; } if (status == LZMA.ELzmaStatus.LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) { if (s.ActualWriteEndMark != 0) { break; } } throw new NotSupportedException("Unsupported status case: " + status); } decoder.LzmaDec_Free(LZMA.ISzAlloc.SmallAlloc); s.WrittenSize = (int)dstPtr.mOffset; s.UsedSize = (int)srcPtr.mOffset; } break; default: { long s_WrittenSize = s.Dst.Length; long s_UsedSize = s.Src.Length; var res = LZMA.LzmaUncompress( P.From(s.Dst), ref s_WrittenSize, P.From(s.Src), ref s_UsedSize, P.From(s.Enc), s.Enc.Length); if (res != LZMA.SZ_OK) { throw new Exception("LzmaUcompress failed: " + res); } s.WrittenSize = (int)s_WrittenSize; s.UsedSize = (int)s_UsedSize; } break; } }