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