static PyObject *py_lz4f_getFrameInfo(PyObject *self, PyObject *args) { const char *source; int src_size; LZ4F_decompressionContext_t dCtx; LZ4F_frameInfo_t frameInfo; PyObject *blkSize; PyObject *blkMode; PyObject *contChkFlag; PyObject *py_dCtx; PyObject *result = PyDict_New(); size_t ssrc_size; size_t err; (void)self; if (!PyArg_ParseTuple(args, "s#O", &source, &src_size, &py_dCtx)) { return NULL; } dCtx = (LZ4F_decompressionContext_t)PyCapsule_GetPointer(py_dCtx, NULL); ssrc_size = (size_t)src_size; err = LZ4F_getFrameInfo(dCtx, &frameInfo, (unsigned char*)source, &ssrc_size); CHECK(LZ4F_isError(err), "Failed getting frameInfo. (error %i)", (int)err); blkSize = PyInt_FromSize_t(frameInfo.blockSizeID); blkMode = PyInt_FromSize_t(frameInfo.blockMode); contChkFlag = PyInt_FromSize_t(frameInfo.contentChecksumFlag); PyDict_SetItemString(result, "blkSize", blkSize); PyDict_SetItemString(result, "blkMode", blkMode); PyDict_SetItemString(result, "chkFlag", contChkFlag); return result; _output_error: return Py_None; }
SEXP do_lzDecompress (SEXP FROM) { SEXP ANS; LZ4F_decompressionContext_t ctx; LZ4F_frameInfo_t info; char *from; char *ans; void *src; size_t m, n, output_size, input_size = xlength(FROM); size_t ibuf, obuf, icum, ocum; if(TYPEOF(FROM) != RAWSXP) error("'from' must be raw or character"); from = (char *)RAW(FROM); /* An implementation following the standard API would do this: * LZ4F_errorCode_t err = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION); * if (LZ4F_isError (err)) error("could not create LZ4 decompression context"); * ... * LZ4F_freeDecompressionContext(ctx); * The problem with that approach is that LZ4F_createDecompressionContext * allocates memory with calloc internally. Later, if R's allocVector fails, * for example, or if R interrupts this function somewhere in '...' then * those internal allocations in LZ4F_createDecompressionContext leak--that is * they aren't ever de-allocated. * * We explicitly allocat the LZ4F_decompressionContext_t pointer using a * replica of the internal LZ4F_dctx_t structure defined near the top of this * file, see the note and corresponding warning! We allocate on the heap (via * R_alloc) here instead of a seemingly simpler stack allocation because LZ4 * indicates that the address needs to be aligned to 8-byte boundaries which is * provided by R_alloc, see: * https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Transient-storage-allocation */ LZ4F_dctx_t *dctxPtr = (LZ4F_dctx_t *)R_alloc(1, sizeof(LZ4F_dctx_t)); memset(dctxPtr, 0, sizeof(LZ4F_dctx_t)); dctxPtr->version = LZ4F_VERSION; ctx = (LZ4F_decompressionContext_t)dctxPtr; m = input_size; n = LZ4F_getFrameInfo(ctx, &info, (void *)from, &input_size); if (LZ4F_isError (n)) error("LZ4F_getFrameInfo"); src = from + input_size; // lz4 frame header offset output_size = (size_t) info.contentSize; ANS = allocVector(RAWSXP, output_size); ans = (char *)RAW(ANS); input_size = m - input_size; icum = 0; ibuf = lzframe_chunksize; if(ibuf > input_size) ibuf = input_size; ocum = 0; obuf = output_size; for(;;) { n = LZ4F_decompress(ctx, ans, &obuf, src, &ibuf, NULL); if (LZ4F_isError (n)) error("LZ4F_decompress"); icum = icum + ibuf; ocum = ocum + obuf; if(icum >= input_size) break; ans = ans + obuf; src = src + ibuf; ibuf = lzframe_chunksize; if(ibuf > (input_size - icum)) ibuf = input_size - icum; obuf = output_size - ocum; } return ANS; }
static int verify_basic_LZ4F_decompression(const void* compressedBuffer, int cSize, U64 crcOrig, void* decodedBuffer, const size_t decodedBufferSize) { DISPLAYLEVEL(3, "%s (cSize %i, crcOrig %08x, decodedBufferSize %i)\n", __FUNCTION__, cSize, (unsigned int)crcOrig, (int)decodedBufferSize); LZ4F_decompressionContext_t dCtx = NULL; U64 crcDest; size_t compressedBufferSize = cSize; BYTE* op = (BYTE*) decodedBuffer; BYTE* const oend = (BYTE*) decodedBuffer + decodedBufferSize; const BYTE* ip = (const BYTE*) compressedBuffer; const BYTE* const iend = (const BYTE*) compressedBuffer + cSize; LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); memset(decodedBuffer, 0, decodedBufferSize); DISPLAYLEVEL(3, "Single Block : \n"); size_t destSize = decodedBufferSize; errorCode = LZ4F_decompress(dCtx, decodedBuffer, &destSize, compressedBuffer, &compressedBufferSize, NULL); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); crcDest = XXH64(decodedBuffer, decodedBufferSize, 1); DISPLAYLEVEL(3, "Regenerated %i bytes (%08x)\n", (int )decodedBufferSize, (unsigned int)crcDest); UT_VERIFY(crcDest == crcOrig, return __LINE__); memset(decodedBuffer, 0, decodedBufferSize); DISPLAYLEVEL(4, "Reusing decompression context \n"); { size_t iSize = compressedBufferSize - 4; const BYTE* cBuff = (const BYTE*) compressedBuffer; DISPLAYLEVEL(3, "Missing last 4 bytes : "); destSize = decodedBufferSize; errorCode = LZ4F_decompress(dCtx, decodedBuffer, &destSize, cBuff, &iSize, NULL); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); UT_VERIFY(errorCode, return __LINE__); crcDest = XXH64(decodedBuffer, destSize, 1); DISPLAYLEVEL(3, "crcDest (%08x)\n", (unsigned int)crcDest); DISPLAYLEVEL(3, "indeed, request %u bytes \n", (unsigned )errorCode); cBuff += iSize; iSize = errorCode; errorCode = LZ4F_decompress(dCtx, decodedBuffer, &destSize, cBuff, &iSize, NULL); UT_VERIFY(errorCode == 0, return __LINE__); crcDest = XXH64(decodedBuffer, decodedBufferSize, 1); DISPLAYLEVEL(3, "crcDest (%08x)\n", (unsigned int)crcDest); UT_VERIFY(crcDest == crcOrig, return __LINE__); } { size_t oSize = 0; size_t iSize = 0; LZ4F_frameInfo_t fi; DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : "); errorCode = LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); DISPLAYLEVEL(3, " %u \n", (unsigned )errorCode); DISPLAYLEVEL(3, "get FrameInfo on null input : "); errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize); UT_VERIFY(errorCode == (size_t) -LZ4F_ERROR_frameHeader_incomplete, return __LINE__); DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(errorCode)); DISPLAYLEVEL(3, "get FrameInfo on not enough input : "); iSize = 6; errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize); UT_VERIFY(errorCode == (size_t) -LZ4F_ERROR_frameHeader_incomplete, return __LINE__); DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(errorCode)); ip += iSize; DISPLAYLEVEL(3, "get FrameInfo on enough input : "); iSize = 15 - iSize; errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); DISPLAYLEVEL(3, " correctly decoded \n"); ip += iSize; } DISPLAYLEVEL(3, "Byte after byte : \n"); while (ip < iend) { size_t oSize = oend - op; size_t iSize = 1; errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); op += oSize; ip += iSize; } crcDest = XXH64(decodedBuffer, decodedBufferSize, 1); UT_VERIFY(crcDest == crcOrig, return __LINE__); DISPLAYLEVEL(3, "Regenerated %u/%u bytes \n", (unsigned )(op - (BYTE* )decodedBuffer), (unsigned )decodedBufferSize); errorCode = LZ4F_freeDecompressionContext(dCtx); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); dCtx = NULL; return 0; }