1 /* LzmaUtil.c -- Test application for LZMA compression 2 2015-11-08 : Igor Pavlov : Public domain */ 3 4 #include "../../Precomp.h" 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #include "../../Alloc.h" 11 #include "../../7zFile.h" 12 #include "../../7zVersion.h" 13 #include "../../LzmaDec.h" 14 #include "../../LzmaEnc.h" 15 16 const char *kCantReadMessage = "Can not read input file"; 17 const char *kCantWriteMessage = "Can not write output file"; 18 const char *kCantAllocateMessage = "Can not allocate memory"; 19 const char *kDataErrorMessage = "Data error"; 20 21 void PrintHelp(char *buffer) 22 { 23 strcat(buffer, "\nLZMA Utility " MY_VERSION_COPYRIGHT_DATE "\n" 24 "\nUsage: lzma <e|d> inputFile outputFile\n" 25 " e: encode file\n" 26 " d: decode file\n"); 27 } 28 29 int PrintError(char *buffer, const char *message) 30 { 31 strcat(buffer, "\nError: "); 32 strcat(buffer, message); 33 strcat(buffer, "\n"); 34 return 1; 35 } 36 37 int PrintErrorNumber(char *buffer, SRes val) 38 { 39 sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val); 40 return 1; 41 } 42 43 int PrintUserError(char *buffer) 44 { 45 return PrintError(buffer, "Incorrect command"); 46 } 47 48 #define IN_BUF_SIZE (1 << 16) 49 #define OUT_BUF_SIZE (1 << 16) 50 51 static SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream, 52 UInt64 unpackSize) 53 { 54 int thereIsSize = (unpackSize != (UInt64)(Int64)-1); 55 Byte inBuf[IN_BUF_SIZE]; 56 Byte outBuf[OUT_BUF_SIZE]; 57 size_t inPos = 0, inSize = 0, outPos = 0; 58 LzmaDec_Init(state); 59 for (;;) 60 { 61 if (inPos == inSize) 62 { 63 inSize = IN_BUF_SIZE; 64 RINOK(inStream->Read(inStream, inBuf, &inSize)); 65 inPos = 0; 66 } 67 { 68 SRes res; 69 SizeT inProcessed = inSize - inPos; 70 SizeT outProcessed = OUT_BUF_SIZE - outPos; 71 ELzmaFinishMode finishMode = LZMA_FINISH_ANY; 72 ELzmaStatus status; 73 if (thereIsSize && outProcessed > unpackSize) 74 { 75 outProcessed = (SizeT)unpackSize; 76 finishMode = LZMA_FINISH_END; 77 } 78 79 res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed, 80 inBuf + inPos, &inProcessed, finishMode, &status); 81 inPos += inProcessed; 82 outPos += outProcessed; 83 unpackSize -= outProcessed; 84 85 if (outStream) 86 if (outStream->Write(outStream, outBuf, outPos) != outPos) 87 return SZ_ERROR_WRITE; 88 89 outPos = 0; 90 91 if (res != SZ_OK || (thereIsSize && unpackSize == 0)) 92 return res; 93 94 if (inProcessed == 0 && outProcessed == 0) 95 { 96 if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK) 97 return SZ_ERROR_DATA; 98 return res; 99 } 100 } 101 } 102 } 103 104 static SRes Decode(ISeqOutStream *outStream, ISeqInStream *inStream) 105 { 106 UInt64 unpackSize; 107 int i; 108 SRes res = 0; 109 110 CLzmaDec state; 111 112 /* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */ 113 unsigned char header[LZMA_PROPS_SIZE + 8]; 114 115 /* Read and parse header */ 116 117 RINOK(SeqInStream_Read(inStream, header, sizeof(header))); 118 119 unpackSize = 0; 120 for (i = 0; i < 8; i++) 121 unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8); 122 123 LzmaDec_Construct(&state); 124 RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc)); 125 res = Decode2(&state, outStream, inStream, unpackSize); 126 LzmaDec_Free(&state, &g_Alloc); 127 return res; 128 } 129 130 static SRes Encode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize, char *rs) 131 { 132 CLzmaEncHandle enc; 133 SRes res; 134 CLzmaEncProps props; 135 136 UNUSED_VAR(rs); 137 138 enc = LzmaEnc_Create(&g_Alloc); 139 if (enc == 0) 140 return SZ_ERROR_MEM; 141 142 LzmaEncProps_Init(&props); 143 res = LzmaEnc_SetProps(enc, &props); 144 145 if (res == SZ_OK) 146 { 147 Byte header[LZMA_PROPS_SIZE + 8]; 148 size_t headerSize = LZMA_PROPS_SIZE; 149 int i; 150 151 res = LzmaEnc_WriteProperties(enc, header, &headerSize); 152 for (i = 0; i < 8; i++) 153 header[headerSize++] = (Byte)(fileSize >> (8 * i)); 154 if (outStream->Write(outStream, header, headerSize) != headerSize) 155 res = SZ_ERROR_WRITE; 156 else 157 { 158 if (res == SZ_OK) 159 res = LzmaEnc_Encode(enc, outStream, inStream, NULL, &g_Alloc, &g_Alloc); 160 } 161 } 162 LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); 163 return res; 164 } 165 166 int main2(int numArgs, const char *args[], char *rs) 167 { 168 CFileSeqInStream inStream; 169 CFileOutStream outStream; 170 char c; 171 int res; 172 int encodeMode; 173 Bool useOutFile = False; 174 175 FileSeqInStream_CreateVTable(&inStream); 176 File_Construct(&inStream.file); 177 178 FileOutStream_CreateVTable(&outStream); 179 File_Construct(&outStream.file); 180 181 if (numArgs == 1) 182 { 183 PrintHelp(rs); 184 return 0; 185 } 186 187 if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1) 188 return PrintUserError(rs); 189 190 c = args[1][0]; 191 encodeMode = (c == 'e' || c == 'E'); 192 if (!encodeMode && c != 'd' && c != 'D') 193 return PrintUserError(rs); 194 195 { 196 size_t t4 = sizeof(UInt32); 197 size_t t8 = sizeof(UInt64); 198 if (t4 != 4 || t8 != 8) 199 return PrintError(rs, "Incorrect UInt32 or UInt64"); 200 } 201 202 if (InFile_Open(&inStream.file, args[2]) != 0) 203 return PrintError(rs, "Can not open input file"); 204 205 if (numArgs > 3) 206 { 207 useOutFile = True; 208 if (OutFile_Open(&outStream.file, args[3]) != 0) 209 return PrintError(rs, "Can not open output file"); 210 } 211 else if (encodeMode) 212 PrintUserError(rs); 213 214 if (encodeMode) 215 { 216 UInt64 fileSize; 217 File_GetLength(&inStream.file, &fileSize); 218 res = Encode(&outStream.s, &inStream.s, fileSize, rs); 219 } 220 else 221 { 222 res = Decode(&outStream.s, useOutFile ? &inStream.s : NULL); 223 } 224 225 if (useOutFile) 226 File_Close(&outStream.file); 227 File_Close(&inStream.file); 228 229 if (res != SZ_OK) 230 { 231 if (res == SZ_ERROR_MEM) 232 return PrintError(rs, kCantAllocateMessage); 233 else if (res == SZ_ERROR_DATA) 234 return PrintError(rs, kDataErrorMessage); 235 else if (res == SZ_ERROR_WRITE) 236 return PrintError(rs, kCantWriteMessage); 237 else if (res == SZ_ERROR_READ) 238 return PrintError(rs, kCantReadMessage); 239 return PrintErrorNumber(rs, res); 240 } 241 return 0; 242 } 243 244 int MY_CDECL main(int numArgs, const char *args[]) 245 { 246 char rs[800] = { 0 }; 247 int res = main2(numArgs, args, rs); 248 fputs(rs, stdout); 249 return res; 250 } 251