#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "LzmaDecode.c" #include "ppport.h" typedef struct Content_s { char *content; unsigned long size; } Content; /* Converted from LzmaTest.c to .xs by Fabien POTENCIER LZMA SDK 4.01 Copyright (c) 1999-2004 Igor Pavlov (2004-02-15) */ size_t MyReadFile(FILE *file, void *data, size_t size) { return ((size_t)fread(data, 1, size, file) == (size_t)size); } #ifdef _LZMA_IN_CB typedef struct _CBuffer { ILzmaInCallback InCallback; unsigned char *Buffer; unsigned int Size; } CBuffer; int LzmaReadCompressed(void *object, unsigned char **buffer, unsigned int *size) { CBuffer *bo = (CBuffer *)object; *size = bo->Size; /* You can specify any available size here */ *buffer = bo->Buffer; bo->Buffer += *size; bo->Size -= *size; return LZMA_RESULT_OK; } #endif int LzmaUncompressData(Content *pIn, Content *pOut, unsigned char properties[5], char *rs) { unsigned int outSizeProcessed, lzmaInternalSize; void *lzmaInternalData; int lc, lp, pb; int res; #ifdef _LZMA_IN_CB CBuffer bo; #endif for (pb = 0; properties[0] >= (9 * 5); pb++, properties[0] -= (9 * 5)); for (lp = 0; properties[0] >= 9; lp++, properties[0] -= 9); lc = properties[0]; lzmaInternalSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb); #ifdef _LZMA_OUT_READ lzmaInternalSize += sizeof(LzmaVarState); #endif New(0, pOut->content, pOut->size, char); if (pOut->content == 0) { sprintf(rs + strlen(rs), "can't allocate"); return 1; } New(0, lzmaInternalData, lzmaInternalSize, char); if (lzmaInternalData == 0) { sprintf(rs + strlen(rs), "can't allocate"); return 1; } #ifdef _LZMA_IN_CB bo.InCallback.Read = LzmaReadCompressed; bo.Buffer = (unsigned char *)pIn->content; bo.Size = pIn->size; #endif #ifdef _LZMA_OUT_READ { UInt32 nowPos; unsigned char *dictionary; UInt32 dictionarySize = 0; int i; for (i = 0; i < 4; i++) dictionarySize += (UInt32)(properties[1 + i]) << (i * 8); New(0, dictionary, dictionarySize, char); if (dictionary == 0) { sprintf(rs + strlen(rs), "can't allocate"); Safefree(lzmaInternalData); return 1; } LzmaDecoderInit((unsigned char *)lzmaInternalData, lzmaInternalSize, lc, lp, pb, dictionary, dictionarySize, #ifdef _LZMA_IN_CB &bo.InCallback #else (unsigned char *)pIn->content, pIn->size #endif ); for (nowPos = 0; nowPos < pOut->size;) { UInt32 blockSize = pOut->size - nowPos; UInt32 kBlockSize = 0x10000; if (blockSize > kBlockSize) blockSize = kBlockSize; res = LzmaDecode((unsigned char *)lzmaInternalData, ((unsigned char *)pOut->content) + nowPos, blockSize, &outSizeProcessed); if (res != 0) { sprintf(rs + strlen(rs), "error = %d\n", res); Safefree(lzmaInternalData); return 1; } if (outSizeProcessed == 0) { pOut->size = nowPos; break; } nowPos += outSizeProcessed; } Safefree(dictionary); } #else res = LzmaDecode((unsigned char *)lzmaInternalData, lzmaInternalSize, lc, lp, pb, #ifdef _LZMA_IN_CB &bo.InCallback, #else (unsigned char *)pIn->content, pIn->size, #endif (unsigned char *)pOut->content, pOut->size, &outSizeProcessed); pOut->size = outSizeProcessed; #endif if (res != 0) { sprintf(rs + strlen(rs), "error = %d\n", res); Safefree(lzmaInternalData); return 1; } Safefree(lzmaInternalData); return 0; } int LzmaUncompressFile(char *filename, Content *pOut, char *rs) { FILE *inputHandle; unsigned int length; Content *pIn; unsigned char properties[5]; int ii, ret; inputHandle = fopen(filename, "rb"); if (inputHandle == 0) { sprintf(rs + strlen(rs), "open input file error"); return 1; } fseek(inputHandle, 0, SEEK_END); length = (unsigned int)ftell(inputHandle); fseek(inputHandle, 0, SEEK_SET); if (!MyReadFile(inputHandle, properties, sizeof(properties))) { fclose(inputHandle); return 1; } pOut->size = 0; for (ii = 0; ii < 4; ii++) { unsigned char b; if (!MyReadFile(inputHandle, &b, sizeof(b))) { fclose(inputHandle); return 1; } pOut->size += (b) << (ii * 8); } if (pOut->size == 0xFFFFFFFF) { sprintf(rs + strlen(rs), "stream version is not supported"); fclose(inputHandle); return 1; } for (ii = 0; ii < 4; ii++) { unsigned char b; if (!MyReadFile(inputHandle, &b, sizeof(b))) return 1; if (b != 0) { sprintf(rs + strlen(rs), "too long file"); fclose(inputHandle); return 1; } } New(0, pIn, 1, Content); pIn->size = length - 13; New(0, pIn->content, pIn->size, char); if (pIn->content == 0) { sprintf(rs + strlen(rs), "can't allocate"); Safefree(pIn); fclose(inputHandle); return 1; } if (!MyReadFile(inputHandle, pIn->content, pIn->size)) { sprintf(rs + strlen(rs), "can't read"); Safefree(pIn->content); Safefree(pIn); fclose(inputHandle); return 1; } fclose(inputHandle); if (properties[0] >= (9*5*5)) { sprintf(rs + strlen(rs), "Properties error"); Safefree(pIn->content); Safefree(pIn); return 1; } /* empty file: no need to uncompress data */ if (pOut->size == (unsigned long)0) { Safefree(pIn->content); Safefree(pIn); return 0; } ret = LzmaUncompressData(pIn, pOut, properties, rs); Safefree(pIn->content); Safefree(pIn); return ret; } MODULE = Compress::unLZMA PACKAGE = Compress::unLZMA PROTOTYPES: DISABLE void uncompressdata(content, size, sizeout, properties) char *content unsigned int size unsigned int sizeout unsigned char *properties PPCODE: char sz[800] = { 0 }; Content *pIn, *pOut; int code = 0; SV *errsv; New(0, pIn, 1, Content); pIn->content = content; pIn->size = size; New(0, pOut, 1, Content); pOut->content = NULL; pOut->size = sizeout; code = LzmaUncompressData(pIn, pOut, properties, sz); errsv = get_sv("@", TRUE); /* Error */ if (code) { sv_setpv(errsv, sz); Safefree(pIn->content); Safefree(pIn); Safefree(pOut->content); Safefree(pOut); XSRETURN_UNDEF; } sv_setpv(errsv, ""); XPUSHs(sv_2mortal(newSVpvn(pOut->content, pOut->size))); Safefree(pIn); Safefree(pOut->content); Safefree(pOut); XSRETURN(1); void uncompressfile(filename) char *filename PPCODE: char sz[800] = { 0 }; int code = 0; unsigned int size = 0; Content *pContent; SV *errsv; New(0, pContent, 1, Content); pContent->content = NULL; pContent->size = 0; code = LzmaUncompressFile(filename, pContent, sz); errsv = get_sv("@", TRUE); /* Error */ if (code) { sv_setpv(errsv, sz); Safefree(pContent->content); Safefree(pContent); XSRETURN_UNDEF; } sv_setpv(errsv, ""); if (pContent->size) { XPUSHs(sv_2mortal(newSVpvn(pContent->content, pContent->size))); } else { XPUSHs(sv_2mortal(newSVpvn("", pContent->size))); /* the empty string */ } Safefree(pContent->content); Safefree(pContent); XSRETURN(1);