1/* 2LzmaTest.c 3Test application for LZMA Decoder 4 5This file written and distributed to public domain by Igor Pavlov. 6This file is part of LZMA SDK 4.26 (2005-08-05) 7*/ 8 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12 13#include "LzmaDecode.h" 14 15const char *kCantReadMessage = "Can not read input file"; 16const char *kCantWriteMessage = "Can not write output file"; 17const char *kCantAllocateMessage = "Can not allocate memory"; 18 19size_t MyReadFile(FILE *file, void *data, size_t size) 20{ 21 if (size == 0) 22 return 0; 23 return fread(data, 1, size, file); 24} 25 26int MyReadFileAndCheck(FILE *file, void *data, size_t size) 27 { return (MyReadFile(file, data, size) == size);} 28 29size_t MyWriteFile(FILE *file, const void *data, size_t size) 30{ 31 if (size == 0) 32 return 0; 33 return fwrite(data, 1, size, file); 34} 35 36int MyWriteFileAndCheck(FILE *file, const void *data, size_t size) 37 { return (MyWriteFile(file, data, size) == size); } 38 39#ifdef _LZMA_IN_CB 40#define kInBufferSize (1 << 15) 41typedef struct _CBuffer 42{ 43 ILzmaInCallback InCallback; 44 FILE *File; 45 unsigned char Buffer[kInBufferSize]; 46} CBuffer; 47 48int LzmaReadCompressed(void *object, const unsigned char **buffer, SizeT *size) 49{ 50 CBuffer *b = (CBuffer *)object; 51 *buffer = b->Buffer; 52 *size = (SizeT)MyReadFile(b->File, b->Buffer, kInBufferSize); 53 return LZMA_RESULT_OK; 54} 55CBuffer g_InBuffer; 56 57#endif 58 59#ifdef _LZMA_OUT_READ 60#define kOutBufferSize (1 << 15) 61unsigned char g_OutBuffer[kOutBufferSize]; 62#endif 63 64int PrintError(char *buffer, const char *message) 65{ 66 sprintf(buffer + strlen(buffer), "\nError: "); 67 sprintf(buffer + strlen(buffer), message); 68 return 1; 69} 70 71int main3(FILE *inFile, FILE *outFile, char *rs) 72{ 73 /* We use two 32-bit integers to construct 64-bit integer for file size. 74 You can remove outSizeHigh, if you don't need >= 4GB supporting, 75 or you can use UInt64 outSize, if your compiler supports 64-bit integers*/ 76 UInt32 outSize = 0; 77 UInt32 outSizeHigh = 0; 78 #ifndef _LZMA_OUT_READ 79 SizeT outSizeFull; 80 unsigned char *outStream; 81 #endif 82 83 int waitEOS = 1; 84 /* waitEOS = 1, if there is no uncompressed size in headers, 85 so decoder will wait EOS (End of Stream Marker) in compressed stream */ 86 87 #ifndef _LZMA_IN_CB 88 SizeT compressedSize; 89 unsigned char *inStream; 90 #endif 91 92 CLzmaDecoderState state; /* it's about 24-80 bytes structure, if int is 32-bit */ 93 unsigned char properties[LZMA_PROPERTIES_SIZE]; 94 95 int res; 96 97 #ifdef _LZMA_IN_CB 98 g_InBuffer.File = inFile; 99 #endif 100 101 if (sizeof(UInt32) < 4) 102 return PrintError(rs, "LZMA decoder needs correct UInt32"); 103 104 #ifndef _LZMA_IN_CB 105 { 106 long length; 107 fseek(inFile, 0, SEEK_END); 108 length = ftell(inFile); 109 fseek(inFile, 0, SEEK_SET); 110 if ((long)(SizeT)length != length) 111 return PrintError(rs, "Too big compressed stream"); 112 compressedSize = (SizeT)(length - (LZMA_PROPERTIES_SIZE + 8)); 113 } 114 #endif 115 116 /* Read LZMA properties for compressed stream */ 117 118 if (!MyReadFileAndCheck(inFile, properties, sizeof(properties))) 119 return PrintError(rs, kCantReadMessage); 120 121 /* Read uncompressed size */ 122 123 { 124 int i; 125 for (i = 0; i < 8; i++) 126 { 127 unsigned char b; 128 if (!MyReadFileAndCheck(inFile, &b, 1)) 129 return PrintError(rs, kCantReadMessage); 130 if (b != 0xFF) 131 waitEOS = 0; 132 if (i < 4) 133 outSize += (UInt32)(b) << (i * 8); 134 else 135 outSizeHigh += (UInt32)(b) << ((i - 4) * 8); 136 } 137 138 #ifndef _LZMA_OUT_READ 139 if (waitEOS) 140 return PrintError(rs, "Stream with EOS marker is not supported"); 141 outSizeFull = (SizeT)outSize; 142 if (sizeof(SizeT) >= 8) 143 outSizeFull |= (((SizeT)outSizeHigh << 16) << 16); 144 else if (outSizeHigh != 0 || (UInt32)(SizeT)outSize != outSize) 145 return PrintError(rs, "Too big uncompressed stream"); 146 #endif 147 } 148 149 /* Decode LZMA properties and allocate memory */ 150 151 if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK) 152 return PrintError(rs, "Incorrect stream properties"); 153 state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); 154 155 #ifdef _LZMA_OUT_READ 156 if (state.Properties.DictionarySize == 0) 157 state.Dictionary = 0; 158 else 159 state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize); 160 #else 161 if (outSizeFull == 0) 162 outStream = 0; 163 else 164 outStream = (unsigned char *)malloc(outSizeFull); 165 #endif 166 167 #ifndef _LZMA_IN_CB 168 if (compressedSize == 0) 169 inStream = 0; 170 else 171 inStream = (unsigned char *)malloc(compressedSize); 172 #endif 173 174 if (state.Probs == 0 175 #ifdef _LZMA_OUT_READ 176 || (state.Dictionary == 0 && state.Properties.DictionarySize != 0) 177 #else 178 || (outStream == 0 && outSizeFull != 0) 179 #endif 180 #ifndef _LZMA_IN_CB 181 || (inStream == 0 && compressedSize != 0) 182 #endif 183 ) 184 { 185 free(state.Probs); 186 #ifdef _LZMA_OUT_READ 187 free(state.Dictionary); 188 #else 189 free(outStream); 190 #endif 191 #ifndef _LZMA_IN_CB 192 free(inStream); 193 #endif 194 return PrintError(rs, kCantAllocateMessage); 195 } 196 197 /* Decompress */ 198 199 #ifdef _LZMA_IN_CB 200 g_InBuffer.InCallback.Read = LzmaReadCompressed; 201 #else 202 if (!MyReadFileAndCheck(inFile, inStream, compressedSize)) 203 return PrintError(rs, kCantReadMessage); 204 #endif 205 206 #ifdef _LZMA_OUT_READ 207 { 208 #ifndef _LZMA_IN_CB 209 SizeT inAvail = compressedSize; 210 const unsigned char *inBuffer = inStream; 211 #endif 212 LzmaDecoderInit(&state); 213 do 214 { 215 #ifndef _LZMA_IN_CB 216 SizeT inProcessed; 217 #endif 218 SizeT outProcessed; 219 SizeT outAvail = kOutBufferSize; 220 if (!waitEOS && outSizeHigh == 0 && outAvail > outSize) 221 outAvail = (SizeT)outSize; 222 res = LzmaDecode(&state, 223 #ifdef _LZMA_IN_CB 224 &g_InBuffer.InCallback, 225 #else 226 inBuffer, inAvail, &inProcessed, 227 #endif 228 g_OutBuffer, outAvail, &outProcessed); 229 if (res != 0) 230 { 231 sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res); 232 res = 1; 233 break; 234 } 235 #ifndef _LZMA_IN_CB 236 inAvail -= inProcessed; 237 inBuffer += inProcessed; 238 #endif 239 240 if (outFile != 0) 241 if (!MyWriteFileAndCheck(outFile, g_OutBuffer, (size_t)outProcessed)) 242 { 243 PrintError(rs, kCantWriteMessage); 244 res = 1; 245 break; 246 } 247 248 if (outSize < outProcessed) 249 outSizeHigh--; 250 outSize -= (UInt32)outProcessed; 251 outSize &= 0xFFFFFFFF; 252 253 if (outProcessed == 0) 254 { 255 if (!waitEOS && (outSize != 0 || outSizeHigh != 0)) 256 res = 1; 257 break; 258 } 259 } 260 while ((outSize != 0 && outSizeHigh == 0) || outSizeHigh != 0 || waitEOS); 261 } 262 263 #else 264 { 265 #ifndef _LZMA_IN_CB 266 SizeT inProcessed; 267 #endif 268 SizeT outProcessed; 269 res = LzmaDecode(&state, 270 #ifdef _LZMA_IN_CB 271 &g_InBuffer.InCallback, 272 #else 273 inStream, compressedSize, &inProcessed, 274 #endif 275 outStream, outSizeFull, &outProcessed); 276 if (res != 0) 277 { 278 sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res); 279 res = 1; 280 } 281 else if (outFile != 0) 282 { 283 if (!MyWriteFileAndCheck(outFile, outStream, (size_t)outProcessed)) 284 { 285 PrintError(rs, kCantWriteMessage); 286 res = 1; 287 } 288 } 289 } 290 #endif 291 292 free(state.Probs); 293 #ifdef _LZMA_OUT_READ 294 free(state.Dictionary); 295 #else 296 free(outStream); 297 #endif 298 #ifndef _LZMA_IN_CB 299 free(inStream); 300 #endif 301 return res; 302} 303 304int main2(int numArgs, const char *args[], char *rs) 305{ 306 FILE *inFile = 0; 307 FILE *outFile = 0; 308 int res; 309 310 sprintf(rs + strlen(rs), "\nLZMA Decoder 4.26 Copyright (c) 1999-2005 Igor Pavlov 2005-08-05\n"); 311 if (numArgs < 2 || numArgs > 3) 312 { 313 sprintf(rs + strlen(rs), "\nUsage: lzmadec file.lzma [outFile]\n"); 314 return 1; 315 } 316 317 inFile = fopen(args[1], "rb"); 318 if (inFile == 0) 319 return PrintError(rs, "Can not open input file"); 320 321 if (numArgs > 2) 322 { 323 outFile = fopen(args[2], "wb+"); 324 if (outFile == 0) 325 return PrintError(rs, "Can not open output file"); 326 } 327 328 res = main3(inFile, outFile, rs); 329 330 if (outFile != 0) 331 fclose(outFile); 332 fclose(inFile); 333 return res; 334} 335 336int main(int numArgs, const char *args[]) 337{ 338 char rs[800] = { 0 }; 339 int res = main2(numArgs, args, rs); 340 printf(rs); 341 return res; 342} 343