OLD | NEW |
(Empty) | |
| 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 *inS
tream, |
| 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 file
Size, 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 } |
OLD | NEW |