2012-01-07 3 views
2

메모리에있는 gzip 파일이 있는데, zlib, version 1.1.3을 사용하여 압축을 풀고 싶습니다. Uncompress()는 소스 데이터가 손상되었음을 나타내는 -3, Z_DATA_ERROR를 반환합니다.zlib 버전 1.1.3을 사용하여 메모리에 gzip 파일 압축 풀기

내 메모리 버퍼가 정확하다는 것을 알고 있습니다. 버퍼에 파일을 쓰면 내 소스 gzip 파일과 같습니다.

The gzip file format은 10 바이트 헤더, 선택적 헤더, 데이터 및 바닥 글이 있음을 나타냅니다. 데이터가 시작되는 위치를 결정하고 해당 부분을 제거 할 수 있습니까? 이 주제에 대한 검색을 수행했으며 몇 명의 사람들이 inflateInit2()를 사용하도록 제안했습니다. 그러나, 내 버전의 zlib에서, 그 함수는 이상하게 주석 처리되었습니다. 다른 옵션이 있습니까?

+4

버전 1.1.3을 사용하려는 특별한 이유가 있습니까? 버전 1.1.4는 2002 년 3 월에 출시되었으며 최신 버전은 1.2.5입니다. – ruakh

+0

사용하고있는 버전이 꽤 오래되었다는 것을 알고 있습니다. 그러나 이것은 zlib의 업데이트를 허용하지 않는 레거시 프로젝트입니다. – gmletzkojr

답변

0

데이터가 시작되는 위치를 결정하고 그 부분을 제거 할 수 있습니까?

Gzip으로는있는 magic number 다음

static const unsigned char gzipMagicBytes[] = { 0x1f, 0x8b, 0x08, 0x00 }; 

당신은 파일 스트림을 읽어이 바이트도 찾아보실 수 있습니다 :

static const int testElemSize = sizeof(unsigned char); 
static const int testElemCount = sizeof(gzipMagicBytes); 

const char *fn = "foo.bar"; 
FILE *fp = fopen(fn, "rbR"); 
char testMagicBuffer[testElemCount] = {0}; 
unsigned long long testMagicOffset = 0ULL; 

if (fp != NULL) { 
    do { 
     if (memcmp(testMagicBuffer, gzipMagicBytes, sizeof(gzipMagicBytes)) == 0) { 
      /* we found gzip magic bytes, do stuff here... */ 
      fprintf(stdout, "gzip stream found at byte offset: %llu\n", testMagicOffset); 
      break; 
     } 
     testMagicOffset += testElemSize * testElemCount; 
     fseek(fp, testMagicOffset - testElemCount + 1, SEEK_SET); 
     testMagicOffset -= testElemCount + 1; 
    } while (fread(testMagicBuffer, testElemSize, testElemCount, fp)); 
} 

fclose(fp); 

복사 작업이 오프셋되면, 당신이 할 수있는 및 붙여 넣기 작업을 수행하거나 다른 바이트를 덮어 씁니다.

1

다른 zlib 버전 (1.2.7)
inflateInit2()가 주석 처리 된 이유를 모르겠습니다. inflateInit2하면 다음과 같은 작업을 수행 할 수 호출하지 않고

:

err = inflateInit(&d_stream); 
err = inflateReset2(&d_stream, 31); 

inflateReset2도 inflateInit에 의해 호출됩니다. inflateInit 내부에 WindowBits가 15 (1111 바이너리)로 설정됩니다. 하지만 gzip을 작동 시키려면 31 (11111)로 설정해야합니다.

이유는 여기에있다 :

inflateReset2 내부 다음이 수행된다 : 창 비트 15 (1,111 진수)로 설정하는 경우는 2 윈도우 비트가 설정되는 경우 1로 연결

wrap = (windowBits >> 4) + 1; 

이제 HEAD 상태에서 다음 줄은 gzip을

if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ 
01을위한 매직 넘버와 함께 상태 -> 랩 값을 확인) (팽창 호출하는 경우 (31) (11111)

23,516,

그래서 다음 코드 나 메모리의 gzip 압축 해제를 할 수 있었다 : (참고 :이 코드는 압축 해제 할 수있는 완전한 데이터가 메모리 및 압축 해제 된 데이터에 대한 버퍼 크기가 충분 있다는 것을 가정)

int err; 
z_stream d_stream; // decompression stream 



d_stream.zalloc = (alloc_func)0; 
d_stream.zfree = (free_func)0; 
d_stream.opaque = (voidpf)0; 

d_stream.next_in = deflated; // where deflated is a pointer the the compressed data buffer 
d_stream.avail_in = deflatedLen; // where deflatedLen is the length of the compressed data 
d_stream.next_out = inflated; // where inflated is a pointer to the resulting uncompressed data buffer 
d_stream.avail_out = inflatedLen; // where inflatedLen is the size of the uncompressed data buffer 

err = inflateInit(&d_stream); 
err = inflateReset2(&d_stream, 31); 
err = inflateEnd(&d_stream); 

inflateInit2()에 주석을다는 것은 oder 솔루션입니다. 여기 WindowBits를 직접 설정할 수 있습니다