2016-01-03 9 views
4

Архив LZH встроен в файл. Файл был прочитан в байт [], а часть LZH идентифицирована как младший байт [].LZH в байт-массиве Decompress в .NET?

Как встроенные байты LZH декомпрессируются в другой байт [] с использованием .NET Framework 4.6 (C#)? Я вижу только http://www.infoq.com/news/2008/06/7-Zip-from-.NET, который точно не делает то, что мне нужно.

Спасибо.

+0

Я предполагаю, что вы уже смотрели на system.io.compression и что не в состоянии прочитать байты в формате LZH? У меня нет байтового массива для игры, или я попробую его, прежде чем спрашивать;) – bri

+0

Библиотеки сжатия в .NET не поддерживают LZH. Я ищу решение с управляемым кодом, которое можно безопасно выполнять в размещенной веб-среде для специального приложения. – Snowy

+0

Да. Я понял, что system.io.compression слишком очевиден ;-). Никогда не боюсь спросить, я полагаю. – bri

ответ

1

фрагмент кода, который следует взят из примера программы из этой статьи http://www.codeproject.com/Articles/27148/C-NET-Interface-for-Zip-Archive-DLLs

Там нет каких-либо существенных изменений: вместо чтения и записи файлов, он читает и писать массивы байтов. Изменения отмечены комментариями Run с sevenzip.exe e "C:\temp\gwo0.11-sample-win32.lzh" 3, например

https://dl.dropboxusercontent.com/u/71459360/7z.zip

using System; 
using System.Collections.Generic; 
using System.Text; 
using Nomad.Archive.SevenZip; 
using System.IO; 
using System.Runtime.InteropServices; 
using System.Reflection; 

namespace SevenZip 
{ 
    class Program 
    { 
     private static void ShowHelp() 
     { 
      Console.WriteLine("SevenZip"); 
      Console.WriteLine("SevenZip l {ArchiveName}"); 
      Console.WriteLine("SevenZip e {ArchiveName} {FileNumber}"); 
     } 

     static void Main(string[] args) 
     { 
      if (args.Length < 2) 
      { 
       ShowHelp(); 
       return; 
      } 

      try 
      { 
       string ArchiveName; 
       uint FileNumber = 0xFFFFFFFF; 
       bool Extract; 

       switch (args[0]) 
       { 
        case "l": 
         ArchiveName = args[1]; 
         Extract = false; 
         break; 
        case "e": 
         ArchiveName = args[1]; 
         Extract = true; 
         if ((args.Length < 3) || !uint.TryParse(args[2], out FileNumber)) 
         { 
          ShowHelp(); 
          return; 
         } 
         break; 
        default: 
         ShowHelp(); 
         return; 
       } 

       using (SevenZipFormat Format = new SevenZipFormat(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "7z.dll"))) 
       { 
        IInArchive Archive = Format.CreateInArchive(SevenZipFormat.GetClassIdFromKnownFormat(KnownSevenZipFormat.Lzh)); 
        if (Archive == null) 
        { 
         ShowHelp(); 
         return; 
        } 

        try 
        { 
         //the byte array is provided by you. here it's coming from a file 
         byte[] data; 
         using (var stream = File.OpenRead(ArchiveName)) 
         { 
          data = new byte[stream.Length]; 
          stream.Read(data, 0, data.Length); 
         } 

         using (InStreamWrapper ArchiveStream = new InStreamWrapper(new MemoryStream(data))) //modified here 
         { 
          ulong CheckPos = 32 * 1024; 
          if (Archive.Open(ArchiveStream, ref CheckPos, null) != 0) 
           ShowHelp(); 

          Console.Write("Archive: "); 
          Console.WriteLine(ArchiveName); 

          if (Extract) 
          { 
           PropVariant Name = new PropVariant(); 
           Archive.GetProperty(FileNumber, ItemPropId.kpidPath, ref Name); 
           string FileName = (string) Name.GetObject(); 

           Console.Write("Extracting: "); 
           Console.Write(FileName); 
           Console.Write(' '); 

           MemoryStream ms = new MemoryStream(); 
           Archive.Extract(new uint[] { FileNumber }, 1, 0, new ArchiveMemoryCallback(FileNumber, ms)); //modified here 
           byte[] output = ms.ToArray(); //here you have the output byte array 
           output.ToString(); 
          } 
          else 
          { 
           Console.WriteLine("List:"); 
           uint Count = Archive.GetNumberOfItems(); 
           for (uint I = 0; I < Count; I++) 
           { 
            PropVariant Name = new PropVariant(); 
            Archive.GetProperty(I, ItemPropId.kpidPath, ref Name); 
            Console.Write(I); 
            Console.Write(' '); 
            Console.WriteLine(Name.GetObject()); 
           } 
          } 
         } 
        } 
        finally 
        { 
         Marshal.ReleaseComObject(Archive); 
        } 
       } 
      } 
      catch (Exception e) 
      { 
       Console.Write("Error: "); 
       Console.WriteLine(e.Message); 
      } 
     } 
    } 

    class ArchiveCallback : IArchiveExtractCallback 
    { 
     private uint FileNumber; 
     private string FileName; 
     private OutStreamWrapper FileStream; 

     public ArchiveCallback(uint fileNumber, string fileName) 
     { 
      this.FileNumber = fileNumber; 
      this.FileName = fileName; 
     } 

     #region IArchiveExtractCallback Members 

     public void SetTotal(ulong total) 
     { 
     } 

     public void SetCompleted(ref ulong completeValue) 
     { 
     } 

     public int GetStream(uint index, out ISequentialOutStream outStream, AskMode askExtractMode) 
     { 
      if ((index == FileNumber) && (askExtractMode == AskMode.kExtract)) 
      { 
       string FileDir = Path.GetDirectoryName(FileName); 
       if (!string.IsNullOrEmpty(FileDir)) 
        Directory.CreateDirectory(FileDir); 
       FileStream = new OutStreamWrapper(File.Create(FileName)); 

       outStream = FileStream; 
      } 
      else 
       outStream = null; 

      return 0; 
     } 

     public void PrepareOperation(AskMode askExtractMode) 
     { 
     } 

     public void SetOperationResult(OperationResult resultEOperationResult) 
     { 
      FileStream.Dispose(); 
      Console.WriteLine(resultEOperationResult); 
     } 

     #endregion 
    } 


    //new 
    class ArchiveMemoryCallback : IArchiveExtractCallback 
    { 
     private uint FileNumber; 
     private Stream stream; 
     private OutStreamWrapper FileStream; 

     public ArchiveMemoryCallback(uint fileNumber, Stream stream) 
     { 
      this.FileNumber = fileNumber; 
      this.stream = stream; 
     } 

     #region IArchiveExtractCallback Members 

     public void SetTotal(ulong total) 
     { 
     } 

     public void SetCompleted(ref ulong completeValue) 
     { 
     } 

     public int GetStream(uint index, out ISequentialOutStream outStream, AskMode askExtractMode) 
     { 
      if ((index == FileNumber) && (askExtractMode == AskMode.kExtract)) 
      { 
       FileStream = new OutStreamWrapper(stream); 

       outStream = FileStream; 
      } 
      else 
       outStream = null; 

      return 0; 
     } 

     public void PrepareOperation(AskMode askExtractMode) 
     { 
     } 

     public void SetOperationResult(OperationResult resultEOperationResult) 
     { 
      FileStream.Dispose(); 
      Console.WriteLine(resultEOperationResult); 
     } 

     #endregion 
    } 
} 
+0

Маршал освобождает COM-защелку на сторонней DLL-версии делает это непригодным для моей цели, извините. Я ищу решение «все-в-памяти», которое выполняется в управляемом .NET. – Snowy

+0

Похоже, вам не повезло: LZH не такой популярный формат сжатия, особенно на окнах (и так далее .net). Я никогда не нашел уже созданную полностью управляемую библиотеку, которая бы справилась с этим. Могу ли я спросить, почему interop не работает? –

+0

Interop не работает, потому что мне нужно запустить в среде, где все должно быть в пространстве памяти веб-приложения. – Snowy