1 /** @file 2 LZMA Compress/Decompress tool (LzmaCompress) 3 4 Based on LZMA SDK 16.04: 5 LzmaUtil.c -- Test application for LZMA compression 6 2016-10-04 : Igor Pavlov : Public domain 7 8 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> 9 This program and the accompanying materials 10 are licensed and made available under the terms and conditions of the BSD License 11 which accompanies this distribution. The full text of the license may be found at 12 http://opensource.org/licenses/bsd-license.php 13 14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 16 17 **/ 18 19 #define _CRT_SECURE_NO_WARNINGS 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include "Sdk/C/Alloc.h" 26 #include "Sdk/C/7zFile.h" 27 #include "Sdk/C/7zVersion.h" 28 #include "Sdk/C/LzmaDec.h" 29 #include "Sdk/C/LzmaEnc.h" 30 #include "Sdk/C/Bra.h" 31 #include "CommonLib.h" 32 33 #define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8) 34 35 typedef enum { 36 NoConverter, 37 X86Converter, 38 MaxConverter 39 } CONVERTER_TYPE; 40 41 const char *kCantReadMessage = "Can not read input file"; 42 const char *kCantWriteMessage = "Can not write output file"; 43 const char *kCantAllocateMessage = "Can not allocate memory"; 44 const char *kDataErrorMessage = "Data error"; 45 46 static Bool mQuietMode = False; 47 static CONVERTER_TYPE mConType = NoConverter; 48 49 #define UTILITY_NAME "LzmaCompress" 50 #define UTILITY_MAJOR_VERSION 0 51 #define UTILITY_MINOR_VERSION 2 52 #define INTEL_COPYRIGHT \ 53 "Copyright (c) 2009-2016, Intel Corporation. All rights reserved." 54 void PrintHelp(char *buffer) 55 { 56 strcat(buffer, 57 "\n" UTILITY_NAME " - " INTEL_COPYRIGHT "\n" 58 "Based on LZMA Utility " MY_VERSION_COPYRIGHT_DATE "\n" 59 "\nUsage: LzmaCompress -e|-d [options] <inputFile>\n" 60 " -e: encode file\n" 61 " -d: decode file\n" 62 " -o FileName, --output FileName: specify the output filename\n" 63 " --f86: enable converter for x86 code\n" 64 " -v, --verbose: increase output messages\n" 65 " -q, --quiet: reduce output messages\n" 66 " --debug [0-9]: set debug level\n" 67 " --version: display the program version and exit\n" 68 " -h, --help: display this help text\n" 69 ); 70 } 71 72 int PrintError(char *buffer, const char *message) 73 { 74 strcat(buffer, "\nError: "); 75 strcat(buffer, message); 76 strcat(buffer, "\n"); 77 return 1; 78 } 79 80 int PrintErrorNumber(char *buffer, SRes val) 81 { 82 sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val); 83 return 1; 84 } 85 86 int PrintUserError(char *buffer) 87 { 88 return PrintError(buffer, "Incorrect command"); 89 } 90 91 void PrintVersion(char *buffer) 92 { 93 sprintf (buffer, "%s Version %d.%d %s ", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION); 94 } 95 96 static SRes Encode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize) 97 { 98 SRes res; 99 size_t inSize = (size_t)fileSize; 100 Byte *inBuffer = 0; 101 Byte *outBuffer = 0; 102 Byte *filteredStream = 0; 103 size_t outSize; 104 CLzmaEncProps props; 105 106 LzmaEncProps_Init(&props); 107 LzmaEncProps_Normalize(&props); 108 109 if (inSize != 0) { 110 inBuffer = (Byte *)MyAlloc(inSize); 111 if (inBuffer == 0) 112 return SZ_ERROR_MEM; 113 } else { 114 return SZ_ERROR_INPUT_EOF; 115 } 116 117 if (SeqInStream_Read(inStream, inBuffer, inSize) != SZ_OK) { 118 res = SZ_ERROR_READ; 119 goto Done; 120 } 121 122 // we allocate 105% of original size + 64KB for output buffer 123 outSize = (size_t)fileSize / 20 * 21 + (1 << 16); 124 outBuffer = (Byte *)MyAlloc(outSize); 125 if (outBuffer == 0) { 126 res = SZ_ERROR_MEM; 127 goto Done; 128 } 129 130 { 131 int i; 132 for (i = 0; i < 8; i++) 133 outBuffer[i + LZMA_PROPS_SIZE] = (Byte)(fileSize >> (8 * i)); 134 } 135 136 if (mConType != NoConverter) 137 { 138 filteredStream = (Byte *)MyAlloc(inSize); 139 if (filteredStream == 0) { 140 res = SZ_ERROR_MEM; 141 goto Done; 142 } 143 memcpy(filteredStream, inBuffer, inSize); 144 145 if (mConType == X86Converter) { 146 { 147 UInt32 x86State; 148 x86_Convert_Init(x86State); 149 x86_Convert(filteredStream, (SizeT) inSize, 0, &x86State, 1); 150 } 151 } 152 } 153 154 { 155 size_t outSizeProcessed = outSize - LZMA_HEADER_SIZE; 156 size_t outPropsSize = LZMA_PROPS_SIZE; 157 158 res = LzmaEncode(outBuffer + LZMA_HEADER_SIZE, &outSizeProcessed, 159 mConType != NoConverter ? filteredStream : inBuffer, inSize, 160 &props, outBuffer, &outPropsSize, 0, 161 NULL, &g_Alloc, &g_Alloc); 162 163 if (res != SZ_OK) 164 goto Done; 165 166 outSize = LZMA_HEADER_SIZE + outSizeProcessed; 167 } 168 169 if (outStream->Write(outStream, outBuffer, outSize) != outSize) 170 res = SZ_ERROR_WRITE; 171 172 Done: 173 MyFree(outBuffer); 174 MyFree(inBuffer); 175 MyFree(filteredStream); 176 177 return res; 178 } 179 180 static SRes Decode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize) 181 { 182 SRes res; 183 size_t inSize = (size_t)fileSize; 184 Byte *inBuffer = 0; 185 Byte *outBuffer = 0; 186 size_t outSize = 0; 187 size_t inSizePure; 188 ELzmaStatus status; 189 UInt64 outSize64 = 0; 190 191 int i; 192 193 if (inSize < LZMA_HEADER_SIZE) 194 return SZ_ERROR_INPUT_EOF; 195 196 inBuffer = (Byte *)MyAlloc(inSize); 197 if (inBuffer == 0) 198 return SZ_ERROR_MEM; 199 200 if (SeqInStream_Read(inStream, inBuffer, inSize) != SZ_OK) { 201 res = SZ_ERROR_READ; 202 goto Done; 203 } 204 205 for (i = 0; i < 8; i++) 206 outSize64 += ((UInt64)inBuffer[LZMA_PROPS_SIZE + i]) << (i * 8); 207 208 outSize = (size_t)outSize64; 209 if (outSize != 0) { 210 outBuffer = (Byte *)MyAlloc(outSize); 211 if (outBuffer == 0) { 212 res = SZ_ERROR_MEM; 213 goto Done; 214 } 215 } else { 216 res = SZ_OK; 217 goto Done; 218 } 219 220 inSizePure = inSize - LZMA_HEADER_SIZE; 221 res = LzmaDecode(outBuffer, &outSize, inBuffer + LZMA_HEADER_SIZE, &inSizePure, 222 inBuffer, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc); 223 224 if (res != SZ_OK) 225 goto Done; 226 227 if (mConType == X86Converter) 228 { 229 UInt32 x86State; 230 x86_Convert_Init(x86State); 231 x86_Convert(outBuffer, (SizeT) outSize, 0, &x86State, 0); 232 } 233 234 if (outStream->Write(outStream, outBuffer, outSize) != outSize) 235 res = SZ_ERROR_WRITE; 236 237 Done: 238 MyFree(outBuffer); 239 MyFree(inBuffer); 240 241 return res; 242 } 243 244 int main2(int numArgs, const char *args[], char *rs) 245 { 246 CFileSeqInStream inStream; 247 CFileOutStream outStream; 248 int res; 249 int encodeMode = 0; 250 Bool modeWasSet = False; 251 const char *inputFile = NULL; 252 const char *outputFile = "file.tmp"; 253 int param; 254 UInt64 fileSize; 255 256 FileSeqInStream_CreateVTable(&inStream); 257 File_Construct(&inStream.file); 258 259 FileOutStream_CreateVTable(&outStream); 260 File_Construct(&outStream.file); 261 262 if (numArgs == 1) 263 { 264 PrintHelp(rs); 265 return 0; 266 } 267 268 for (param = 1; param < numArgs; param++) { 269 if (strcmp(args[param], "-e") == 0 || strcmp(args[param], "-d") == 0) { 270 encodeMode = (args[param][1] == 'e'); 271 modeWasSet = True; 272 } else if (strcmp(args[param], "--f86") == 0) { 273 mConType = X86Converter; 274 } else if (strcmp(args[param], "-o") == 0 || 275 strcmp(args[param], "--output") == 0) { 276 if (numArgs < (param + 2)) { 277 return PrintUserError(rs); 278 } 279 outputFile = args[++param]; 280 } else if (strcmp(args[param], "--debug") == 0) { 281 if (numArgs < (param + 2)) { 282 return PrintUserError(rs); 283 } 284 // 285 // For now we silently ignore this parameter to achieve command line 286 // parameter compatibility with other build tools. 287 // 288 param++; 289 } else if ( 290 strcmp(args[param], "-h") == 0 || 291 strcmp(args[param], "--help") == 0 292 ) { 293 PrintHelp(rs); 294 return 0; 295 } else if ( 296 strcmp(args[param], "-v") == 0 || 297 strcmp(args[param], "--verbose") == 0 298 ) { 299 // 300 // For now we silently ignore this parameter to achieve command line 301 // parameter compatibility with other build tools. 302 // 303 } else if ( 304 strcmp(args[param], "-q") == 0 || 305 strcmp(args[param], "--quiet") == 0 306 ) { 307 mQuietMode = True; 308 } else if (strcmp(args[param], "--version") == 0) { 309 PrintVersion(rs); 310 return 0; 311 } else if (inputFile == NULL) { 312 inputFile = args[param]; 313 } else { 314 return PrintUserError(rs); 315 } 316 } 317 318 if ((inputFile == NULL) || !modeWasSet) { 319 return PrintUserError(rs); 320 } 321 322 { 323 size_t t4 = sizeof(UInt32); 324 size_t t8 = sizeof(UInt64); 325 if (t4 != 4 || t8 != 8) 326 return PrintError(rs, "Incorrect UInt32 or UInt64"); 327 } 328 329 if (InFile_Open(&inStream.file, inputFile) != 0) 330 return PrintError(rs, "Can not open input file"); 331 332 if (OutFile_Open(&outStream.file, outputFile) != 0) { 333 File_Close(&inStream.file); 334 return PrintError(rs, "Can not open output file"); 335 } 336 337 File_GetLength(&inStream.file, &fileSize); 338 339 if (encodeMode) 340 { 341 if (!mQuietMode) { 342 printf("Encoding\n"); 343 } 344 res = Encode(&outStream.s, &inStream.s, fileSize); 345 } 346 else 347 { 348 if (!mQuietMode) { 349 printf("Decoding\n"); 350 } 351 res = Decode(&outStream.s, &inStream.s, fileSize); 352 } 353 354 File_Close(&outStream.file); 355 File_Close(&inStream.file); 356 357 if (res != SZ_OK) 358 { 359 if (res == SZ_ERROR_MEM) 360 return PrintError(rs, kCantAllocateMessage); 361 else if (res == SZ_ERROR_DATA) 362 return PrintError(rs, kDataErrorMessage); 363 else if (res == SZ_ERROR_WRITE) 364 return PrintError(rs, kCantWriteMessage); 365 else if (res == SZ_ERROR_READ) 366 return PrintError(rs, kCantReadMessage); 367 return PrintErrorNumber(rs, res); 368 } 369 return 0; 370 } 371 372 int MY_CDECL main(int numArgs, const char *args[]) 373 { 374 char rs[2000] = { 0 }; 375 int res = main2(numArgs, args, rs); 376 if (strlen(rs) > 0) { 377 puts(rs); 378 } 379 return res; 380 } 381