简体   繁体   English

C#相当于LZMA-JS压缩

[英]C# equivalent of LZMA-JS compress

I have used some client side javscript code to compress some user input using this javascript library . 我使用了一些客户端javscript代码来使用这个javascript库压缩一些用户输入。 In the backend code I have used the code samples from this post to decompress the data server side using C#. 在后端代码中,我使用了这篇文章中的代码示例,使用C#解压缩数据服务器端。

The works perfectly. 工作完美。

Now I would like to be able to compress a string the same way the javascript does. 现在我希望能够以与javascript相同的方式压缩字符串。 When I compress the code using this sample I get an array of signed integers ranging from -128 to 128. Now I would like to use my backend code to do the same. 当我使用这个示例压缩代码时,我得到一个从-128到128的有符号整数数组。现在我想使用我的后端代码来做同样的事情。

The LMZA properties from the javascript are a bit different than the default properties from the C# code but even if I change those to the same values I get different results from the two libraries. 来自javascript的LMZA属性与C#代码的默认属性略有不同,但即使我将这些属性更改为相同的值,我也会得到两个库的不同结果。

At first the output values from the C# code are unsigned. 首先,C#代码的输出值是无符号的。 Secondly the number of characters returned are different. 其次,返回的字符数不同。 The differences may be introduced by the properties of the decoders but I have no idea how to get the two libraries aligned. 差异可能由解码器的属性引入,但我不知道如何使两个库对齐。

My C# uses the LMZA SDK from 7zip 我的C#使用7zip的LMZA SDK

My C# code to decompress the javascript compressed data (comma separated array of signed integers): 我的C#代码解压缩javascript压缩数据(逗号分隔的有符号整数数组):

public static void Decompress(Stream inStream, Stream outStream)
{
    byte[] properties = new byte[5];
    inStream.Read(properties, 0, 5);
    SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
    decoder.SetDecoderProperties(properties);
    long outSize = 0;
    for (int i = 0; i < 8; i++)
    {
        int v = inStream.ReadByte();
        outSize |= ((long)(byte)v) << (8 * i);
    }
    long compressedSize = inStream.Length - inStream.Position;
    decoder.Code(inStream, outStream, compressedSize, outSize, null);
}

public static string DecompressLzma(string inputstring)
{
    if (!string.IsNullOrEmpty(inputstring))
    {
        byte[] myInts = Array.ConvertAll(inputstring.Split(','), s => (byte)int.Parse(s));
        var stream = new MemoryStream(myInts);
        var outputStream = new MemoryStream();
        Decompress(stream, outputStream);
        using (var reader = new StreamReader(outputStream))
        {
            outputStream.Position = 0;
            string output = reader.ReadToEnd();
            return output;
        }
    }

    return "";
}

The code to compress the data is like this (number of bytes are diffrent and unsigned): 压缩数据的代码是这样的(字节数是不同的和无符号的):

public static string CompressLzma(string inputstring)
{
    if (!string.IsNullOrEmpty(inputstring))
    {               
        var stream = new MemoryStream(Encoding.Unicode.GetBytes(inputstring ?? ""));
        var outputStream = new MemoryStream();
        Compress(stream, outputStream);



        byte[] bytes = outputStream.ToArray();


    }

    return "";
}

public static void Compress(MemoryStream inStream, MemoryStream outStream)
{
    CoderPropID[] propIDs;
    object[] properties;
    PrepareEncoder(out propIDs, out properties);

    SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
    encoder.SetCoderProperties(propIDs, properties);
    encoder.WriteCoderProperties(outStream);
    Int64 fileSize = inStream.Length;
    for (int i = 0; i < 8; i++)
    {
        outStream.WriteByte((Byte)(fileSize >> (8 * i)));
    }
    encoder.Code(inStream, outStream, -1, -1, null);
}

public static void PrepareEncoder(out CoderPropID[] propIDs, out object[] properties)
{
    bool eos = true;
    Int32 dictionary = 1 << 16;
    Int32 posStateBits = 2;
    Int32 litContextBits = 3; // for normal files
    // UInt32 litContextBits = 0; // for 32-bit data
    Int32 litPosBits = 0;
    // UInt32 litPosBits = 2; // for 32-bit data
    Int32 algorithm = 2;
    Int32 numFastBytes = 32;
    string mf = "bt2";

    propIDs = new CoderPropID[]
    {
        CoderPropID.DictionarySize,
        CoderPropID.PosStateBits,
        CoderPropID.LitContextBits,
        CoderPropID.LitPosBits,
        CoderPropID.Algorithm,
        CoderPropID.NumFastBytes,
        CoderPropID.MatchFinder,
        CoderPropID.EndMarker
    };
    properties = new object[]
    {
        dictionary,
        posStateBits,
        litContextBits,
        litPosBits,
        algorithm,
        numFastBytes,
        mf,
        eos
    };
}

This code works to create the same string the javascript code would, the LMZA settings are included: 此代码用于创建javascript代码所使用的相同字符串,包含LMZA设置:

public static string CompressLzma(string inputstring)
{
    if (!string.IsNullOrEmpty(inputstring))
    {
        var stream = new MemoryStream(Encoding.UTF8.GetBytes(inputstring ?? ""));
        var outputStream = new MemoryStream();
        Compress(stream, outputStream);


        byte[] bytes = outputStream.ToArray();
        var result = string.Join(",", Array.ConvertAll(bytes, v => signedInt((int)v)));
        return result;
    }

    return "";
}


public static void PrepareEncoder(out CoderPropID[] propIDs, out object[] properties)
{
    bool eos = true;
    Int32 dictionary = 1 << 16;
    Int32 posStateBits = 2;
    Int32 litContextBits = 3; // for normal files
    // UInt32 litContextBits = 0; // for 32-bit data
    Int32 litPosBits = 0;
    // UInt32 litPosBits = 2; // for 32-bit data
    Int32 algorithm = 2;
    Int32 numFastBytes = 64;
    string mf = "bt4";

    propIDs = new CoderPropID[]
    {
       CoderPropID.DictionarySize,
       CoderPropID.PosStateBits,
       CoderPropID.LitContextBits,
       CoderPropID.LitPosBits,
       CoderPropID.Algorithm,
       CoderPropID.NumFastBytes,
       CoderPropID.MatchFinder,
       CoderPropID.EndMarker
    };
    properties = new object[]
    {
       dictionary,
       posStateBits,
       litContextBits,
       litPosBits,
       algorithm,
       numFastBytes,
       mf,
       eos
    };
}

private static int signedInt(int unsignedInt)
{
    return unsignedInt >= 128 ? Math.Abs(128 - unsignedInt) - 128 : unsignedInt;
}


public static void Compress(MemoryStream inStream, MemoryStream outStream)
{
    CoderPropID[] propIDs;
    object[] properties;
    PrepareEncoder(out propIDs, out properties);

    SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
    encoder.SetCoderProperties(propIDs, properties);
    encoder.WriteCoderProperties(outStream);
    Int64 fileSize = inStream.Length;
    for (int i = 0; i < 8; i++)
    {
        outStream.WriteByte((Byte)(fileSize >> (8 * i)));
    }
    encoder.Code(inStream, outStream, -1, -1, null);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM