/****************************************************************************** ** ** FILE NAME : LzmaWrapper.c ** PROJECT : bootloader ** MODULES : U-boot ** ** DATE : 2 Nov 2006 ** AUTHOR : Lin Mars ** DESCRIPTION : LZMA decoder support for U-boot 1.1.5 ** COPYRIGHT : Copyright (c) 2006 ** Infineon Technologies AG ** Am Campeon 1-12, 85579 Neubiberg, Germany ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** HISTORY ** $Date $Author $Comment ** 2 Nov 2006 Lin Mars init version which derived from LzmaTest.c from ** LZMA v4.43 SDK ** 24 May 2007 Lin Mars Fix issue for multiple lzma_inflate involved *******************************************************************************/ #define LZMA_NO_STDIO #ifndef LZMA_NO_STDIO #include <stdio.h> #include <stdlib.h> #include <string.h> #endif #include <config.h> #include <common.h> #include <linux/types.h> #include <linux/string.h> #include <linux/ctype.h> #include <malloc.h> #ifdef CONFIG_LZMA #include "LzmaDecode.h" #include "LzmaWrapper.h" #if defined(DEBUG_ENABLE_BOOTSTRAP_PRINTF) || !defined(CFG_BOOTSTRAP_CODE) static const char *kCantReadMessage = "Can not read from source buffer"; static const char *kCantAllocateMessage = "Not enough buffer for decompression"; #endif static size_t rpos=0, dpos=0; static int MyReadFileAndCheck(unsigned char *src, void *dest, size_t size) { if (size == 0) return 0; memcpy(dest, src + rpos, size); rpos += size; return 1; } int lzma_inflate(unsigned char *source, int s_len, unsigned char *dest, int *d_len) { /* We use two 32-bit integers to construct 64-bit integer for file size. You can remove outSizeHigh, if you don't need >= 4GB supporting, or you can use UInt64 outSize, if your compiler supports 64-bit integers*/ UInt32 outSize = 0; UInt32 outSizeHigh = 0; SizeT outSizeFull; unsigned char *outStream; int waitEOS = 1; /* waitEOS = 1, if there is no uncompressed size in headers, so decoder will wait EOS (End of Stream Marker) in compressed stream */ SizeT compressedSize; unsigned char *inStream; CLzmaDecoderState state; /* it's about 24-80 bytes structure, if int is 32-bit */ unsigned char properties[LZMA_PROPERTIES_SIZE]; int res; rpos=0; dpos=0; if (sizeof(UInt32) < 4) { #if defined(DEBUG_ENABLE_BOOTSTRAP_PRINTF) || !defined(CFG_BOOTSTRAP_CODE) printf("LZMA decoder needs correct UInt32\n"); #endif return LZMA_RESULT_DATA_ERROR; } { long length=s_len; if ((long)(SizeT)length != length) { #if defined(DEBUG_ENABLE_BOOTSTRAP_PRINTF) || !defined(CFG_BOOTSTRAP_CODE) printf("Too big compressed stream\n"); #endif return LZMA_RESULT_DATA_ERROR; } compressedSize = (SizeT)(length - (LZMA_PROPERTIES_SIZE + 8)); } /* Read LZMA properties for compressed stream */ if (!MyReadFileAndCheck(source, properties, sizeof(properties))) { #if defined(DEBUG_ENABLE_BOOTSTRAP_PRINTF) || !defined(CFG_BOOTSTRAP_CODE) printf("%s\n", kCantReadMessage); #endif return LZMA_RESULT_DATA_ERROR; } /* Read uncompressed size */ { int i; for (i = 0; i < 8; i++) { unsigned char b; if (!MyReadFileAndCheck(source, &b, 1)) { #if defined(DEBUG_ENABLE_BOOTSTRAP_PRINTF) || !defined(CFG_BOOTSTRAP_CODE) printf("%s\n", kCantReadMessage); #endif return LZMA_RESULT_DATA_ERROR; } if (b != 0xFF) waitEOS = 0; if (i < 4) outSize += (UInt32)(b) << (i * 8); else outSizeHigh += (UInt32)(b) << ((i - 4) * 8); } if (waitEOS) { #if defined(DEBUG_ENABLE_BOOTSTRAP_PRINTF) || !defined(CFG_BOOTSTRAP_CODE) printf("Stream with EOS marker is not supported"); #endif return LZMA_RESULT_DATA_ERROR; } outSizeFull = (SizeT)outSize; if (sizeof(SizeT) >= 8) outSizeFull |= (((SizeT)outSizeHigh << 16) << 16); else if (outSizeHigh != 0 || (UInt32)(SizeT)outSize != outSize) { #if defined(DEBUG_ENABLE_BOOTSTRAP_PRINTF) || !defined(CFG_BOOTSTRAP_CODE) printf("Too big uncompressed stream"); #endif return LZMA_RESULT_DATA_ERROR; } } /* Decode LZMA properties and allocate memory */ if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK) { #if defined(DEBUG_ENABLE_BOOTSTRAP_PRINTF) || !defined(CFG_BOOTSTRAP_CODE) printf("Incorrect stream properties"); #endif return LZMA_RESULT_DATA_ERROR; } state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); if (outSizeFull == 0) outStream = 0; else { if (outSizeFull > d_len) outStream = 0; else outStream = dest; } if (compressedSize == 0) inStream = 0; else { if ((compressedSize+rpos) > s_len ) inStream = 0; else inStream = source + rpos; } if (state.Probs == 0 || (outStream == 0 && outSizeFull != 0) || (inStream == 0 && compressedSize != 0) ) { free(state.Probs); #if defined(DEBUG_ENABLE_BOOTSTRAP_PRINTF) || !defined(CFG_BOOTSTRAP_CODE) printf("%s\n", kCantAllocateMessage); #endif return LZMA_RESULT_DATA_ERROR; } /* Decompress */ { SizeT inProcessed; SizeT outProcessed; res = LzmaDecode(&state, inStream, compressedSize, &inProcessed, outStream, outSizeFull, &outProcessed); if (res != 0) { #if defined(DEBUG_ENABLE_BOOTSTRAP_PRINTF) || !defined(CFG_BOOTSTRAP_CODE) printf("\nDecoding error = %d\n", res); #endif res = 1; } else { *d_len = outProcessed; } } free(state.Probs); return res; } #endif /* CONFIG_LZMA */