C# эквивалент LZMA-JS компресс
Я использовал некоторый код javscript на стороне клиента, чтобы сжать некоторый пользовательский ввод, используя эту библиотеку javascript. В бэкэнд-коде я использовал примеры кода из этого поста для распаковки стороны сервера данных с использованием C#.
Работает отлично.
Теперь я хотел бы иметь возможность сжимать строку так же, как это делает JavaScript. Когда я сжимаю код, используя этот пример, я получаю массив целых чисел со знаком в диапазоне от -128 до 128. Теперь я хотел бы использовать свой внутренний код, чтобы сделать то же самое.
Свойства LMZA из javascript немного отличаются от свойств по умолчанию из кода C#, но даже если я изменю их на те же значения, я получу разные результаты из двух библиотек.
Сначала выходные значения из кода C# не имеют знака. Во-вторых, количество возвращаемых символов отличается. Различия могут быть внесены в свойствах декодеров, но я не знаю, как выровнять две библиотеки.
Мой C# использует LMZA SDK от 7zip
Мой код 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 "";
}
Код для сжатия данных выглядит следующим образом (количество байтов различно и без знака):
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
};
}
1 ответ
Этот код работает для создания той же строки, что и код 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);
}