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