Распакуйте текстовую строку с помощью zlib - PullRequest
0 голосов
/ 27 апреля 2018

Мне нужно декодировать шестнадцатеричные строки, хранящиеся в формате zlib. Пример:

1800000013000000eAFjYoAAZiDFCMQgGgQAAJwACg ==

, где 18000000 и 13000000 - размер несжатых / сжатых данных (в данном случае 24 и 19).

Также я знаю, что остальная часть строки содержит

020000000000000003000000010000000300000000000000

Где проблема? после любого урока, например https://panthema.net/2007/0328-ZLibString.html сжатие этой строки, я получаю

х? 302 @? P ??

что в шестнадцатеричном виде можно записать как

783f3330324053f503f103ff5

Это не имеет ничего общего с моей ожидаемой сжатой строкой, поэтому я не нашел способа распаковать исходную строку (это моя конечная цель)

Заранее благодарю за любой совет!

PS. Я использую распаковку из https://github.com/systemed/intersector/blob/master/helpers.cpp

Похоже, что строка была закодирована в base64 (спасибо @zdenek и @ Mark-Adler) Мне удалось расшифровать ее с помощью

BYTE *res;
int resSize = FromBase64Simple((BYTE*)actualData.c_str(),actualData.len(),res,sizeCompressed);

Вы можете прочитать реализацию из https://github.com/kengonakajima/luvit-base64/blob/master/base64.c

Но это не проблема, так как я могу вывести результат, используя

char* resChar = new char[resSize];
for(int i = 0;i<resSize;i++)
{
    int asciiCode = (BYTE)res[i];
    resChar[i]=char(asciiCode);
    char buffer [2];
    itoa (asciiCode,buffer,16);
    qDebug()<<"["<<i<<"]\t"<<asciiCode<<"\t"<<buffer;
}

Я получаю результат каждого байта в десятичном и шестнадцатеричном виде, и оба в порядке. Шестнадцатеричный выглядит как:

78 01 63 62 80 00 66 20 c5 08 c4 20 1a 04 00 00 9c 00 0a

Но resChar - это "x? Cb?" это не имеет ничего общего со значением, сказанным @ Mark-Adler "x? 302 @? P ??" (где очевидно символы «?» не для печати), я действительно думаю, что здесь проблема, но мои данные, кажется, соответствуют этой таблице: https://www.asciitable.com/, а у Марка также нет этой сети https://conv.darkbyte.ru/ возвращает те же результаты, что и мой алгоритм

Я пытался распаковать строку, используя реализацию, указанную выше, но это не удалось (также попытался https://gist.github.com/arq5x/5315739), но его распакованное значение представляет собой строку из одного символа ""

Здесь мы рассмотрим минимальный воспроизводимый случай:

#include <string>

static char LookupDigits[] = {
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //gap: ctrl chars
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //gap: ctrl chars
    0,0,0,0,0,0,0,0,0,0,0,           //gap: spc,!"#$%'()*
    62,                   // +
    0, 0, 0,             // gap ,-.
    63,                   // /
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // 0-9
    0, 0, 0,             // gap: :;<
    99,                   //  = (end padding)
    0, 0, 0,             // gap: >?@
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,
    17,18,19,20,21,22,23,24,25, // A-Z
    0, 0, 0, 0, 0, 0,    // gap: [\]^_`
    26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,
    43,44,45,46,47,48,49,50,51, // a-z
    0, 0, 0, 0,          // gap: {|}~ (and the rest...)
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};

int FromBase64Simple(const unsigned char* pSrc, int nLenSrc, unsigned char* pDst, int nLenDst)
{
    int nLenOut = 0;
    for (int j = 0; j<nLenSrc; j += 4) {
        if (nLenOut > nLenDst) {
            return(0); // error, buffer too small
        }
        unsigned char s1 = LookupDigits[*pSrc++];
        unsigned char s2 = LookupDigits[*pSrc++];
        unsigned char s3 = LookupDigits[*pSrc++];
        unsigned char s4 = LookupDigits[*pSrc++];

        unsigned char d1 = ((s1 & 0x3f) << 2) | ((s2 & 0x30) >> 4);
        unsigned char d2 = ((s2 & 0x0f) << 4) | ((s3 & 0x3c) >> 2);
        unsigned char d3 = ((s3 & 0x03) << 6) | ((s4 & 0x3f) >> 0);

        *pDst++ = d1;  nLenOut++;
        if (s3 == 99) break;      // end padding found
        *pDst++ = d2;  nLenOut++;
        if (s4 == 99) break;      // end padding found
        *pDst++ = d3;  nLenOut++;
    }
    return(nLenOut);
}


int main()
{
    std::string inputData = "eAFjYoAAZiDFCMQgGgQAAJwACg==";


    //19 is hardcoded since I know its size prior to this call
    unsigned char res[19];
    int resSize = FromBase64Simple((unsigned char*)inputData.c_str(), inputData.size(), res, 19);


    for (int i = 0; i<resSize; i++)
    {
        int asciiCode = res[i];
        printf("[%i]\t%i\t%x\n", i, asciiCode, asciiCode);
    }
    printf("\n\nres: %s", (char*)res);

    getchar();

    return 0;
}

Ответы [ 2 ]

0 голосов
/ 29 апреля 2018

Это прекрасно работает для меня. Я использовал функцию распаковки, которую вы связали, и функцию base64, которую вы предоставили. Я удалил проверку ошибок и немного переформатировал, чтобы сделать ее короче.

#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <zlib.h>

#pragma comment(lib, "zdll.lib")

static char LookupDigits[] = {
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,62,0,0,0,63,52,53,54,55,56,57,58,59,60,61,
    0,0,0,99,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
    20,21,22,23,24,25,0,0,0,0,0,0,26,27,28,29,30,31,32,33,34,35,36,
    37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};

int FromBase64Simple(const unsigned char* pSrc, int nLenSrc, unsigned char* pDst, int nLenDst)
{
    int nLenOut = 0;
    for (int j = 0; j<nLenSrc; j += 4)
    {
        if (nLenOut > nLenDst)
        {
            return(0); // error, buffer too small
        }
        unsigned char s1 = LookupDigits[*pSrc++];
        unsigned char s2 = LookupDigits[*pSrc++];
        unsigned char s3 = LookupDigits[*pSrc++];
        unsigned char s4 = LookupDigits[*pSrc++];

        unsigned char d1 = ((s1 & 0x3f) << 2) | ((s2 & 0x30) >> 4);
        unsigned char d2 = ((s2 & 0x0f) << 4) | ((s3 & 0x3c) >> 2);
        unsigned char d3 = ((s3 & 0x03) << 6) | ((s4 & 0x3f) >> 0);

        *pDst++ = d1;  nLenOut++;
        if (s3 == 99) break;      // end padding found
        *pDst++ = d2;  nLenOut++;
        if (s4 == 99) break;      // end padding found
        *pDst++ = d3;  nLenOut++;
    }
    return(nLenOut);
}

std::string decompress_string(const std::string& str)
{
    z_stream zs;                        // z_stream is zlib's control structure
    memset(&zs, 0, sizeof(zs));
    inflateInit(&zs);
    zs.next_in = (Bytef*)str.data();
    zs.avail_in = str.size();

    int ret;
    char outbuffer[32768];
    std::string outstring;
    do
    {
        zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
        zs.avail_out = sizeof(outbuffer);
        ret = inflate(&zs, 0);
        if (outstring.size() < zs.total_out)
        {
            outstring.append(outbuffer, zs.total_out - outstring.size());
        }
    }
    while (ret == Z_OK);
    inflateEnd(&zs);
    return outstring;
}

int main()
{
    std::string inputData = "eAFjYoAAZiDFCMQgGgQAAJwACg==";
    //19 is hardcoded since I know its size prior to this call
    std::string res(19, '\0');
    FromBase64Simple((unsigned char*)inputData.c_str(), inputData.size(), (unsigned char*)res.data(), res.size());
    std::string d = decompress_string(res);
    for (int c : d)
    {
        printf("%02x", c);
    }
    printf("\n");
    getchar();
    return 0;
}

Выход: 020000000000000003000000010000000300000000000000

0 голосов
/ 27 апреля 2018

"eAFjYoAAZiDFCMQgGgQAAJwACg ==" имеет кодировку Base64. Вы должны сначала декодировать это в двоичный файл, чтобы получить что-то, что может быть распаковано. Этот двоичный файл, выраженный в шестнадцатеричном виде:

78 01 63 62 80 00 66 20 c5 08 c4 20 1a 04 00 00 9c 00 0a

Это действительный поток zlib, который распаковывается в него, выраженный в шестнадцатеричном формате:

02 00 00 00 00 00 00 00 03 00 00 00 01 00 00 00 03 00 00 00 00 00 00 00

Ваш результат сжатия "x? 302 @? P ??" изначально был в двоичном формате, и не может быть напечатан. Эти вопросительные знаки в действительности не являются вопросительными знаками в оригинале, а представляют собой некоторые другие байты, которые не печатаются. Так что не печатайте это. Полученная вами попытка конвертировать напечатанный результат в гекс неверна, поскольку у вас есть вопросительные знаки (3f) в гексе.

...