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