Портирование алгоритма Java DEFLATE на C # - PullRequest
0 голосов
/ 14 января 2019

У нас есть требование распаковать некоторые данные, созданные системой Java с использованием алгоритма DEFLATE. Это мы не можем контролировать.

Хотя мы не знаем точного варианта, мы можем распаковать данные, отправленные нам, используя следующий код Java:

 public static String inflateBase64(String base64)
    {
        try (Reader reader = new InputStreamReader(
                new InflaterInputStream(
                        new ByteArrayInputStream(
                                Base64.getDecoder().decode(base64)))))
        {
            StringWriter sw = new StringWriter();
            char[] chars = new char[1024];
            for (int len; (len = reader.read(chars)) > 0; )
                sw.write(chars, 0, len);
            return sw.toString();
        }
        catch (IOException e)
        {
            System.err.println(e.getMessage());
            return "";
        }
    }

К сожалению, наша экосистема основана на C #. В настоящее время мы работаем с Java-программой, используя объект Process, но это явно неоптимально с точки зрения производительности, поэтому мы хотели бы перенести приведенный выше код на C #, если это вообще возможно.

Некоторые примеры ввода и вывода:

>java -cp . Deflate -c "Pack my box with five dozen liquor jugs."
eJwLSEzOVsitVEjKr1AozyzJUEjLLEtVSMmvSs1TyMksLM0vUsgqTS/WAwAm/w6Y
>java -cp . Deflate -d eJwLSEzOVsitVEjKr1AozyzJUEjLLEtVSMmvSs1TyMksLM0vUsgqTS/WAwAm/w6Y
Pack my box with five dozen liquor jugs.
>

Нам сказали, что система Java соответствует RFC 1951 , поэтому мы рассмотрели довольно много библиотек, но ни одна из них, похоже, не распаковывает данные правильно (если вообще). Одним из примеров является DotNetZip:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ionic.Zlib;

namespace Decomp
{
    class Program
    {
        static void Main(string[] args)
        {                        
            // Deflate

            String start = "Pack my box with five dozen liquor jugs.";

            var x = DeflateStream.CompressString(start);
            var res1 = Convert.ToBase64String(x, 0, x.Length);

            // Inflate 

            //String source = "eJwLSEzOVsitVEjKr1AozyzJUEjLLEtVSMmvSs1TyMksLM0vUsgqTS/WAwAm/w6Y"; // *** FAILS ***
            String source = "C0hMzlbIrVRIyq9QKM8syVBIyyxLVUjJr0rNU8jJLCzNL1LIKk0v1gMA"; 

            var part1 = Convert.FromBase64String(source);            

            var res2 =  DeflateStream.UncompressString(part1);
        }
    }
}

Это реализует RFC 1951 в соответствии с документацией, но неправильно расшифровывает строку (предположительно из-за незначительных различий алгоритма между реализациями).

С точки зрения разработки мы могли бы понять, какой именно вариант нам нужно написать. Есть ли какая-либо информация заголовка или онлайн-инструменты, которые мы могли бы использовать, чтобы обеспечить начальное управление? Такое ощущение, что мы немного стреляем в темноте.

1 Ответ

0 голосов
/ 14 января 2019

https://www.nuget.org/packages/ICSharpCode.SharpZipLib.dll/

using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using System;
using System.IO;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string input = "Pack my box with five dozen liquor jugs.";

            string encoded = Encode(input);
            string decoded = Decode(encoded);

            Console.WriteLine($"Input: {input}");
            Console.WriteLine($"Encoded: {encoded}");
            Console.WriteLine($"Decoded: {decoded}");

            Console.ReadKey(true);
        }

        static string Encode(string text)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(text);

            using (MemoryStream inms = new MemoryStream(bytes))
            {
                using (MemoryStream outms = new MemoryStream())
                {
                    using (DeflaterOutputStream dos = new DeflaterOutputStream(outms))
                    {
                        inms.CopyTo(dos);

                        dos.Finish();

                        byte[] encoded = outms.ToArray();                                              

                        return Convert.ToBase64String(encoded);
                    }
                }
            }
        }

        static string Decode(string base64)
        {
            byte[] bytes = Convert.FromBase64String(base64);

            using (MemoryStream ms = new MemoryStream(bytes))
            {
                using (InflaterInputStream iis = new InflaterInputStream(ms))
                {
                    using (StreamReader sr = new StreamReader(iis))
                    {
                        return sr.ReadToEnd();
                    }
                }
            }
        }
    }
}
...