Skip to content

Commit 2ee26ef

Browse files
author
Alex Ionescu
committed
minlzdec: First figure out how big the uncompressed file will be, then decompress it.
minlzlib: Add support to Lz2DecodeStream for just getting the uncompressed size without doing any decoding. The implementation only adds 5 lines of code, so it was worth it. minlzlib: Properly re-initialize LZMA decoder state on subsequent calls, instead of relying on the .bss section (which only works once). This adds 2 more lines of code.
1 parent 2df7adf commit 2ee26ef

5 files changed

Lines changed: 134 additions & 110 deletions

File tree

minlzdec/minlzdec.c

Lines changed: 117 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -11,114 +11,124 @@
1111

1212
int32_t
1313
main (
14-
int32_t ArgumentCount,
15-
char* Arguments[]
16-
)
14+
int32_t ArgumentCount,
15+
char* Arguments[]
16+
)
1717
{
18-
FILE* inputFile;
19-
FILE* outputFile;
20-
size_t fileSize;
21-
size_t sizeRead;
22-
uint32_t size;
23-
uint8_t* inputBuffer;
24-
uint8_t* outputBuffer;
25-
struct stat stat;
26-
bool decodeResult;
27-
28-
inputFile = NULL;
29-
outputFile = NULL;
30-
inputBuffer = NULL;
31-
outputBuffer = NULL;
32-
33-
printf("minlzdec v.1.0.0 -- http://ionescu007.github.io/minlzma\n");
34-
printf("Copyright(c) 2020 Alex Ionescu (@aionescu)\n\n");
35-
if (ArgumentCount != 3)
36-
{
37-
printf("Usage: minlzdec [INPUT FILE] [OUTPUT FILE]\n");
38-
printf("Decompress INPUT FILE in the .xz format into OUTPUT FILE.\n");
39-
errno = EINVAL;
40-
goto Cleanup;
41-
}
42-
43-
inputFile = fopen(Arguments[1], "rb");
44-
if (inputFile == 0)
45-
{
46-
printf("Failed to open input file: %s\n", Arguments[1]);
47-
goto Cleanup;
48-
}
49-
50-
fstat(fileno(inputFile), &stat);
51-
fileSize = stat.st_size;
52-
printf("Input file size: %zd\n", fileSize);
53-
54-
inputBuffer = malloc(fileSize);
55-
if (inputBuffer == NULL)
56-
{
57-
printf("Out of memory for allocating input buffer\n");
58-
goto Cleanup;
59-
}
60-
61-
sizeRead = fread(inputBuffer, 1, fileSize, inputFile);
62-
if (sizeRead != fileSize)
63-
{
64-
printf("File read failed (%zd vs %zd bytes\n", sizeRead, fileSize);
65-
goto Cleanup;
66-
}
67-
68-
size = (uint32_t)fileSize * 16;
69-
70-
outputBuffer = malloc(size);
71-
if (outputBuffer == NULL)
72-
{
73-
printf("Out of memory for allocating output buffer\n");
74-
goto Cleanup;
75-
}
76-
77-
decodeResult = XzDecode(inputBuffer, size, outputBuffer, &size);
78-
if (decodeResult == false)
79-
{
80-
printf("Decoding failed after %d bytes\n", size);
81-
errno = ENOTSUP;
82-
goto Cleanup;
83-
}
84-
85-
printf("Decompressed %d bytes\n", size);
86-
87-
outputFile = fopen(Arguments[2], "wb");
88-
if (outputFile == 0)
89-
{
90-
printf("Failed to open output file: %s\n", Arguments[1]);
91-
goto Cleanup;
92-
}
93-
94-
fileSize = fwrite(outputBuffer, 1, size, outputFile);
95-
if (fileSize != size)
96-
{
97-
printf("File write failed (%zd vs %d bytes\n", fileSize, size);
98-
goto Cleanup;
99-
}
100-
errno = 0;
18+
FILE* inputFile;
19+
FILE* outputFile;
20+
size_t fileSize;
21+
size_t sizeRead;
22+
uint32_t inputSize, outputSize;
23+
uint8_t* inputBuffer;
24+
uint8_t* outputBuffer;
25+
struct stat stat;
26+
bool decodeResult;
27+
28+
inputFile = NULL;
29+
outputFile = NULL;
30+
inputBuffer = NULL;
31+
outputBuffer = NULL;
32+
33+
printf("minlzdec v.1.0.5 -- http://ionescu007.github.io/minlzma\n");
34+
printf("Copyright(c) 2020 Alex Ionescu (@aionescu)\n\n");
35+
if (ArgumentCount != 3)
36+
{
37+
printf("Usage: minlzdec [INPUT FILE] [OUTPUT FILE]\n");
38+
printf("Decompress INPUT FILE in the .xz format into OUTPUT FILE.\n");
39+
errno = EINVAL;
40+
goto Cleanup;
41+
}
42+
43+
inputFile = fopen(Arguments[1], "rb");
44+
if (inputFile == 0)
45+
{
46+
printf("Failed to open input file: %s\n", Arguments[1]);
47+
goto Cleanup;
48+
}
49+
50+
fstat(fileno(inputFile), &stat);
51+
fileSize = stat.st_size;
52+
printf("Input file size: %zd\n", fileSize);
53+
54+
inputBuffer = malloc(fileSize);
55+
if (inputBuffer == NULL)
56+
{
57+
printf("Out of memory for allocating input buffer\n");
58+
goto Cleanup;
59+
}
60+
61+
sizeRead = fread(inputBuffer, 1, fileSize, inputFile);
62+
if (sizeRead != fileSize)
63+
{
64+
printf("File read failed (%zd vs %zd bytes\n", sizeRead, fileSize);
65+
goto Cleanup;
66+
}
67+
68+
inputSize = (uint32_t)fileSize;
69+
decodeResult = XzDecode(inputBuffer, inputSize, outputBuffer, &outputSize);
70+
if (decodeResult == false)
71+
{
72+
printf("Decoding failed after %d bytes\n", outputSize);
73+
errno = ENOTSUP;
74+
goto Cleanup;
75+
}
76+
77+
printf("Decompressed file will be %d bytes (%f%% ratio)\n",
78+
outputSize, (double)inputSize / (double)outputSize);
79+
80+
outputBuffer = malloc(outputSize);
81+
if (outputBuffer == NULL)
82+
{
83+
printf("Out of memory for allocating output buffer\n");
84+
goto Cleanup;
85+
}
86+
87+
decodeResult = XzDecode(inputBuffer, inputSize, outputBuffer, &outputSize);
88+
if (decodeResult == false)
89+
{
90+
printf("Decoding failed after %d bytes\n", outputSize);
91+
errno = ENOTSUP;
92+
goto Cleanup;
93+
}
94+
95+
printf("Decompressed %d bytes\n", outputSize);
96+
97+
outputFile = fopen(Arguments[2], "wb");
98+
if (outputFile == 0)
99+
{
100+
printf("Failed to open output file: %s\n", Arguments[1]);
101+
goto Cleanup;
102+
}
103+
104+
fileSize = fwrite(outputBuffer, 1, outputSize, outputFile);
105+
if (fileSize != outputSize)
106+
{
107+
printf("File write failed (%zd vs %d bytes)\n", fileSize, outputSize);
108+
goto Cleanup;
109+
}
110+
errno = 0;
101111

102112
Cleanup:
103-
if (outputBuffer != NULL)
104-
{
105-
free(outputBuffer);
106-
}
107-
if (inputBuffer != NULL)
108-
{
109-
free(inputBuffer);
110-
}
111-
112-
if (outputFile != 0)
113-
{
114-
fflush(outputFile);
115-
fclose(outputFile);
116-
}
117-
118-
if (inputFile != 0)
119-
{
120-
fclose(inputFile);
121-
}
122-
123-
return errno;
113+
if (outputBuffer != NULL)
114+
{
115+
free(outputBuffer);
116+
}
117+
if (inputBuffer != NULL)
118+
{
119+
free(inputBuffer);
120+
}
121+
122+
if (outputFile != 0)
123+
{
124+
fflush(outputFile);
125+
fclose(outputFile);
126+
}
127+
128+
if (inputFile != 0)
129+
{
130+
fclose(inputFile);
131+
}
132+
133+
return errno;
124134
}

minlzlib/lzma2dec.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ Lz2DecodeChunk (
8989

9090
bool
9191
Lz2DecodeStream (
92-
uint32_t* BytesProcessed
92+
uint32_t* BytesProcessed,
93+
bool GetSizeOnly
9394
)
9495
{
9596
uint8_t (*pInfoBytes)[4];
@@ -165,6 +166,16 @@ Lz2DecodeStream (
165166
break;
166167
}
167168

169+
//
170+
// Don't do any decompression if the caller only wants to know the size
171+
//
172+
if (GetSizeOnly != false)
173+
{
174+
*BytesProcessed += ChunkState.UncompressedSize;
175+
BfSeek(ChunkState.CompressedSize, (uint8_t**)&pInfoBytes);
176+
continue;
177+
}
178+
168179
//
169180
// Read the initial range and code bytes to initialize the arithmetic
170181
// coding decoder, and let it know how much input data exists. We've

minlzlib/lzmadec.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,10 +602,13 @@ LzInitialize (
602602
}
603603

604604
//
605+
// Initialize decoder to default state in case we're called more than once.
605606
// The LZMA "Bit Model" is an adaptive arithmetic-coded probability-based
606607
// bit tree which encodes either a "0" or a "1". By default, we initialize
607608
// the probabilities to 0.5 (50% chance).
608609
//
610+
Decoder.Sequence = LzmaLitLitLitState;
611+
Decoder.Rep1 = Decoder.Rep2 = Decoder.Rep3 = 0;
609612
static_assert((LZMA_BIT_MODEL_SLOTS * 2) == sizeof(Decoder.u.BitModel),
610613
"Invalid size");
611614
for (int i = 0; i < LZMA_BIT_MODEL_SLOTS; i++)

minlzlib/minlzlib.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ bool LzInitialize(uint8_t Properties);
7373
//
7474
// LZMA2 Decoder
7575
//
76-
bool Lz2DecodeStream(uint32_t* BytesProcessed);
76+
bool Lz2DecodeStream(uint32_t* BytesProcessed, bool GetSizeOnly);
7777
#ifdef MINLZ_INTEGRITY_CHECKS
7878
//
7979
// Checksum Management

minlzlib/xzstream.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ XzDecodeBlock (
257257
#ifdef MINLZ_META_CHECKS
258258
BfSeek(0, &inputStart);
259259
#endif
260-
if (!Lz2DecodeStream(BlockSize))
260+
if (!Lz2DecodeStream(BlockSize, OutputBuffer == NULL))
261261
{
262262
return false;
263263
}

0 commit comments

Comments
 (0)