259 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			259 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /* LzmaUtil.c -- Test application for LZMA compression
 | ||
|  | 2017-04-27 : Igor Pavlov : Public domain */ | ||
|  | 
 | ||
|  | #include "Precomp.h"
 | ||
|  | 
 | ||
|  | #include <stdio.h>
 | ||
|  | #include <stdlib.h>
 | ||
|  | #include <string.h>
 | ||
|  | 
 | ||
|  | #include "CpuArch.h"
 | ||
|  | 
 | ||
|  | #include "Alloc.h"
 | ||
|  | #include "7zFile.h"
 | ||
|  | #include "7zVersion.h"
 | ||
|  | #include "LzmaDec.h"
 | ||
|  | #include "LzmaEnc.h"
 | ||
|  | 
 | ||
|  | static const char * const kCantReadMessage = "Can not read input file"; | ||
|  | static const char * const kCantWriteMessage = "Can not write output file"; | ||
|  | static const char * const kCantAllocateMessage = "Can not allocate memory"; | ||
|  | static const char * const kDataErrorMessage = "Data error"; | ||
|  | 
 | ||
|  | static void PrintHelp(char *buffer) | ||
|  | { | ||
|  |   strcat(buffer, | ||
|  |     "\nLZMA-C " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n" | ||
|  |     "Usage:  lzma <e|d> inputFile outputFile\n" | ||
|  |     "  e: encode file\n" | ||
|  |     "  d: decode file\n"); | ||
|  | } | ||
|  | 
 | ||
|  | static int PrintError(char *buffer, const char *message) | ||
|  | { | ||
|  |   strcat(buffer, "\nError: "); | ||
|  |   strcat(buffer, message); | ||
|  |   strcat(buffer, "\n"); | ||
|  |   return 1; | ||
|  | } | ||
|  | 
 | ||
|  | static int PrintErrorNumber(char *buffer, SRes val) | ||
|  | { | ||
|  |   sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val); | ||
|  |   return 1; | ||
|  | } | ||
|  | 
 | ||
|  | static int PrintUserError(char *buffer) | ||
|  | { | ||
|  |   return PrintError(buffer, "Incorrect command"); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | #define IN_BUF_SIZE  (1 << 14)//(1 << 16)
 | ||
|  | #define OUT_BUF_SIZE (1 << 14)//(1 << 16)
 | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream, | ||
|  |     UInt64 unpackSize) | ||
|  | { | ||
|  |   int thereIsSize = (unpackSize != (UInt64)(Int64)-1); | ||
|  |   Byte inBuf[IN_BUF_SIZE]; | ||
|  |   Byte outBuf[OUT_BUF_SIZE]; | ||
|  |   size_t inPos = 0, inSize = 0, outPos = 0; | ||
|  |   LzmaDec_Init(state); | ||
|  |   for (;;) | ||
|  |   { | ||
|  |     if (inPos == inSize) | ||
|  |     { | ||
|  |       inSize = IN_BUF_SIZE; | ||
|  |       RINOK(inStream->Read(inStream, inBuf, &inSize)); | ||
|  |       inPos = 0; | ||
|  |     } | ||
|  |     { | ||
|  |       SRes res; | ||
|  |       SizeT inProcessed = inSize - inPos; | ||
|  |       SizeT outProcessed = OUT_BUF_SIZE - outPos; | ||
|  |       ELzmaFinishMode finishMode = LZMA_FINISH_ANY; | ||
|  |       ELzmaStatus status; | ||
|  |       if (thereIsSize && outProcessed > unpackSize) | ||
|  |       { | ||
|  |         outProcessed = (SizeT)unpackSize; | ||
|  |         finishMode = LZMA_FINISH_END; | ||
|  |       } | ||
|  |        | ||
|  |       res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed, | ||
|  |         inBuf + inPos, &inProcessed, finishMode, &status); | ||
|  |       inPos += inProcessed; | ||
|  |       outPos += outProcessed; | ||
|  |       unpackSize -= outProcessed; | ||
|  |        | ||
|  |       if (outStream) | ||
|  |         if (outStream->Write(outStream, outBuf, outPos) != outPos) | ||
|  |           return SZ_ERROR_WRITE; | ||
|  |          | ||
|  |       outPos = 0; | ||
|  |        | ||
|  |       if (res != SZ_OK || (thereIsSize && unpackSize == 0)) | ||
|  |         return res; | ||
|  |        | ||
|  |       if (inProcessed == 0 && outProcessed == 0) | ||
|  |       { | ||
|  |         if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK) | ||
|  |           return SZ_ERROR_DATA; | ||
|  |         return res; | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes Decode(ISeqOutStream *outStream, ISeqInStream *inStream) | ||
|  | { | ||
|  |   UInt64 unpackSize; | ||
|  |   int i; | ||
|  |   SRes res = 0; | ||
|  | 
 | ||
|  |   CLzmaDec state; | ||
|  | 
 | ||
|  |   /* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */ | ||
|  |   unsigned char header[LZMA_PROPS_SIZE + 8]; | ||
|  | 
 | ||
|  |   /* Read and parse header */ | ||
|  | 
 | ||
|  |   RINOK(SeqInStream_Read(inStream, header, sizeof(header))); | ||
|  | 
 | ||
|  |   unpackSize = 0; | ||
|  |   for (i = 0; i < 8; i++) | ||
|  |     unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8); | ||
|  | 
 | ||
|  |   LzmaDec_Construct(&state); | ||
|  |   RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc)); | ||
|  |   res = Decode2(&state, outStream, inStream, unpackSize); | ||
|  |   LzmaDec_Free(&state, &g_Alloc); | ||
|  |   return res; | ||
|  | } | ||
|  | 
 | ||
|  | static SRes Encode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize, char *rs) | ||
|  | { | ||
|  |   CLzmaEncHandle enc; | ||
|  |   SRes res; | ||
|  |   CLzmaEncProps props; | ||
|  | 
 | ||
|  |   UNUSED_VAR(rs); | ||
|  | 
 | ||
|  |   enc = LzmaEnc_Create(&g_Alloc); | ||
|  |   if (enc == 0) | ||
|  |     return SZ_ERROR_MEM; | ||
|  | 
 | ||
|  |   LzmaEncProps_Init(&props); | ||
|  |   res = LzmaEnc_SetProps(enc, &props); | ||
|  | 
 | ||
|  |   if (res == SZ_OK) | ||
|  |   { | ||
|  |     Byte header[LZMA_PROPS_SIZE + 8]; | ||
|  |     size_t headerSize = LZMA_PROPS_SIZE; | ||
|  |     int i; | ||
|  | 
 | ||
|  |     res = LzmaEnc_WriteProperties(enc, header, &headerSize); | ||
|  |     for (i = 0; i < 8; i++) | ||
|  |       header[headerSize++] = (Byte)(fileSize >> (8 * i)); | ||
|  |     if (outStream->Write(outStream, header, headerSize) != headerSize) | ||
|  |       res = SZ_ERROR_WRITE; | ||
|  |     else | ||
|  |     { | ||
|  |       if (res == SZ_OK) | ||
|  |         res = LzmaEnc_Encode(enc, outStream, inStream, NULL, &g_Alloc, &g_Alloc); | ||
|  |     } | ||
|  |   } | ||
|  |   LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); | ||
|  |   return res; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static int main2(int numArgs, const char *args[], char *rs) | ||
|  | { | ||
|  |   CFileSeqInStream inStream; | ||
|  |   CFileOutStream outStream; | ||
|  |   char c; | ||
|  |   int res; | ||
|  |   int encodeMode; | ||
|  |   Bool useOutFile = False; | ||
|  | 
 | ||
|  |   FileSeqInStream_CreateVTable(&inStream); | ||
|  |   File_Construct(&inStream.file); | ||
|  | 
 | ||
|  |   FileOutStream_CreateVTable(&outStream); | ||
|  |   File_Construct(&outStream.file); | ||
|  | 
 | ||
|  |   if (numArgs == 1) | ||
|  |   { | ||
|  |     PrintHelp(rs); | ||
|  |     return 0; | ||
|  |   } | ||
|  | 
 | ||
|  |   if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1) | ||
|  |     return PrintUserError(rs); | ||
|  | 
 | ||
|  |   c = args[1][0]; | ||
|  |   encodeMode = (c == 'e' || c == 'E'); | ||
|  |   if (!encodeMode && c != 'd' && c != 'D') | ||
|  |     return PrintUserError(rs); | ||
|  | 
 | ||
|  |   { | ||
|  |     size_t t4 = sizeof(UInt32); | ||
|  |     size_t t8 = sizeof(UInt64); | ||
|  |     if (t4 != 4 || t8 != 8) | ||
|  |       return PrintError(rs, "Incorrect UInt32 or UInt64"); | ||
|  |   } | ||
|  | 
 | ||
|  |   if (InFile_Open(&inStream.file, args[2]) != 0) | ||
|  |     return PrintError(rs, "Can not open input file"); | ||
|  | 
 | ||
|  |   if (numArgs > 3) | ||
|  |   { | ||
|  |     useOutFile = True; | ||
|  |     if (OutFile_Open(&outStream.file, args[3]) != 0) | ||
|  |       return PrintError(rs, "Can not open output file"); | ||
|  |   } | ||
|  |   else if (encodeMode) | ||
|  |     PrintUserError(rs); | ||
|  | 
 | ||
|  |   if (encodeMode) | ||
|  |   { | ||
|  |     UInt64 fileSize; | ||
|  |     File_GetLength(&inStream.file, &fileSize); | ||
|  |     res = Encode(&outStream.vt, &inStream.vt, fileSize, rs); | ||
|  |   } | ||
|  |   else | ||
|  |   { | ||
|  |     res = Decode(&outStream.vt, useOutFile ? &inStream.vt : NULL); | ||
|  |   } | ||
|  | 
 | ||
|  |   if (useOutFile) | ||
|  |     File_Close(&outStream.file); | ||
|  |   File_Close(&inStream.file); | ||
|  | 
 | ||
|  |   if (res != SZ_OK) | ||
|  |   { | ||
|  |     if (res == SZ_ERROR_MEM) | ||
|  |       return PrintError(rs, kCantAllocateMessage); | ||
|  |     else if (res == SZ_ERROR_DATA) | ||
|  |       return PrintError(rs, kDataErrorMessage); | ||
|  |     else if (res == SZ_ERROR_WRITE) | ||
|  |       return PrintError(rs, kCantWriteMessage); | ||
|  |     else if (res == SZ_ERROR_READ) | ||
|  |       return PrintError(rs, kCantReadMessage); | ||
|  |     return PrintErrorNumber(rs, res); | ||
|  |   } | ||
|  |   return 0; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | int MY_CDECL main(int numArgs, const char *args[]) | ||
|  | { | ||
|  |   char rs[800] = { 0 }; | ||
|  |   int res = main2(numArgs, args, rs); | ||
|  |   fputs(rs, stdout); | ||
|  |   return res; | ||
|  | } |