1 // ==========================================================
2 // ZLib library interface
3 //
4 // Design and implementation by
5 // - Floris van den Berg (flvdberg@wxs.nl)
6 //
7 // This file is part of FreeImage 3
8 //
9 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
10 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
11 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
12 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
13 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
14 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
15 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
16 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
17 // THIS DISCLAIMER.
18 //
19 // Use at your own risk!
20 // ==========================================================
21
22 #include "../ZLib/zlib.h"
23 #include "FreeImage.h"
24 #include "Utilities.h"
25 #include "../ZLib/zutil.h" /* must be the last header because of error C3163 in VS2008 (_vsnprintf defined in stdio.h) */
26
27 /**
28 Compresses a source buffer into a target buffer, using the ZLib library.
29 Upon entry, target_size is the total size of the destination buffer,
30 which must be at least 0.1% larger than source_size plus 12 bytes.
31
32 @param target Destination buffer
33 @param target_size Size of the destination buffer, in bytes
34 @param source Source buffer
35 @param source_size Size of the source buffer, in bytes
36 @return Returns the actual size of the compressed buffer, returns 0 if an error occured
37 @see FreeImage_ZLibUncompress
38 */
39 DWORD DLL_CALLCONV
FreeImage_ZLibCompress(BYTE * target,DWORD target_size,BYTE * source,DWORD source_size)40 FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
41 uLongf dest_len = (uLongf)target_size;
42
43 int zerr = compress(target, &dest_len, source, source_size);
44 switch(zerr) {
45 case Z_MEM_ERROR: // not enough memory
46 case Z_BUF_ERROR: // not enough room in the output buffer
47 FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
48 return 0;
49 case Z_OK:
50 return dest_len;
51 }
52
53 return 0;
54 }
55
56 /**
57 Decompresses a source buffer into a target buffer, using the ZLib library.
58 Upon entry, target_size is the total size of the destination buffer,
59 which must be large enough to hold the entire uncompressed data.
60 The size of the uncompressed data must have been saved previously by the compressor
61 and transmitted to the decompressor by some mechanism outside the scope of this
62 compression library.
63
64 @param target Destination buffer
65 @param target_size Size of the destination buffer, in bytes
66 @param source Source buffer
67 @param source_size Size of the source buffer, in bytes
68 @return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
69 @see FreeImage_ZLibCompress
70 */
71 DWORD DLL_CALLCONV
FreeImage_ZLibUncompress(BYTE * target,DWORD target_size,BYTE * source,DWORD source_size)72 FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
73 uLongf dest_len = (uLongf)target_size;
74
75 int zerr = uncompress(target, &dest_len, source, source_size);
76 switch(zerr) {
77 case Z_MEM_ERROR: // not enough memory
78 case Z_BUF_ERROR: // not enough room in the output buffer
79 case Z_DATA_ERROR: // input data was corrupted
80 FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
81 return 0;
82 case Z_OK:
83 return dest_len;
84 }
85
86 return 0;
87 }
88
89 /**
90 Compresses a source buffer into a target buffer, using the ZLib library.
91 On success, the target buffer contains a GZIP compatible layout.
92 Upon entry, target_size is the total size of the destination buffer,
93 which must be at least 0.1% larger than source_size plus 24 bytes.
94
95 @param target Destination buffer
96 @param target_size Size of the destination buffer, in bytes
97 @param source Source buffer
98 @param source_size Size of the source buffer, in bytes
99 @return Returns the actual size of the compressed buffer, returns 0 if an error occured
100 @see FreeImage_ZLibCompress
101 */
102 DWORD DLL_CALLCONV
FreeImage_ZLibGZip(BYTE * target,DWORD target_size,BYTE * source,DWORD source_size)103 FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
104 uLongf dest_len = (uLongf)target_size - 12;
105 DWORD crc = crc32(0L, NULL, 0);
106
107 // set up header (stolen from zlib/gzio.c)
108 sprintf((char *)target, "%c%c%c%c%c%c%c%c", 0x1f, 0x8b,
109 Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/);
110 int zerr = compress2(target + 8, &dest_len, source, source_size, Z_BEST_COMPRESSION);
111 switch(zerr) {
112 case Z_MEM_ERROR: // not enough memory
113 case Z_BUF_ERROR: // not enough room in the output buffer
114 FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
115 return 0;
116 case Z_OK: {
117 // patch header, setup crc and length (stolen from mod_trace_output)
118 BYTE *p = target + 8; *p++ = 2; *p = OS_CODE; // xflags, os_code
119 crc = crc32(crc, source, source_size);
120 memcpy(target + 4 + dest_len, &crc, 4);
121 memcpy(target + 8 + dest_len, &source_size, 4);
122 return dest_len + 12;
123 }
124 }
125 return 0;
126 }
127
128 /**
129 Decompresses a gzipped source buffer into a target buffer, using the ZLib library.
130 Upon entry, target_size is the total size of the destination buffer,
131 which must be large enough to hold the entire uncompressed data.
132 The size of the uncompressed data must have been saved previously by the compressor
133 and transmitted to the decompressor by some mechanism outside the scope of this
134 compression library.
135
136 @param target Destination buffer
137 @param target_size Size of the destination buffer, in bytes
138 @param source Source buffer
139 @param source_size Size of the source buffer, in bytes
140 @return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
141 @see FreeImage_ZLibGZip
142 */
143
get_byte(z_stream * stream)144 static int get_byte(z_stream *stream) {
145 if (stream->avail_in <= 0) return EOF;
146 stream->avail_in--;
147 return *(stream->next_in)++;
148 }
149
checkheader(z_stream * stream)150 static int checkheader(z_stream *stream) {
151 int flags, c;
152 DWORD len;
153
154 if (get_byte(stream) != 0x1f || get_byte(stream) != 0x8b)
155 return Z_DATA_ERROR;
156 if (get_byte(stream) != Z_DEFLATED || ((flags = get_byte(stream)) & 0xE0) != 0)
157 return Z_DATA_ERROR;
158 for (len = 0; len < 6; len++) (void)get_byte(stream);
159
160 if ((flags & 0x04) != 0) { /* skip the extra field */
161 len = (DWORD)get_byte(stream);
162 len += ((DWORD)get_byte(stream)) << 8;
163 /* len is garbage if EOF but the loop below will quit anyway */
164 while (len-- != 0 && get_byte(stream) != EOF) ;
165 }
166 if ((flags & 0x08) != 0) { /* skip the original file name */
167 while ((c = get_byte(stream)) != 0 && c != EOF) ;
168 }
169 if ((flags & 0x10) != 0) { /* skip the .gz file comment */
170 while ((c = get_byte(stream)) != 0 && c != EOF) ;
171 }
172 if ((flags & 0x02) != 0) { /* skip the header crc */
173 for (len = 0; len < 2; len++) (void)get_byte(stream);
174 }
175 return Z_OK;
176 }
177
178 DWORD DLL_CALLCONV
FreeImage_ZLibGUnzip(BYTE * target,DWORD target_size,BYTE * source,DWORD source_size)179 FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
180 DWORD src_len = source_size;
181 DWORD dest_len = target_size;
182 int zerr = Z_DATA_ERROR;
183
184 if (src_len > 0) {
185 z_stream stream;
186 memset(&stream, 0, sizeof (stream));
187 if ((zerr = inflateInit2(&stream, -MAX_WBITS)) == Z_OK) {
188 stream.next_in = source;
189 stream.avail_in = source_size;
190
191 stream.next_out = target;
192 stream.avail_out = target_size;
193
194 if ((zerr = checkheader(&stream)) == Z_OK) {
195 zerr = inflate (&stream, Z_NO_FLUSH);
196 dest_len = target_size - stream.avail_out;
197
198 if (zerr == Z_OK || zerr == Z_STREAM_END)
199 inflateEnd(&stream);
200 }
201 }
202 }
203 if (zerr != Z_OK && zerr != Z_STREAM_END) {
204 FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
205 return 0;
206 }
207 return dest_len;
208 }
209
210 /**
211 Update a running crc from source and return the updated crc, using the ZLib library.
212 If source is NULL, this function returns the required initial value for the crc.
213
214 @param crc Running crc value
215 @param source Source buffer
216 @param source_size Size of the source buffer, in bytes
217 @return Returns the new crc value
218 */
219 DWORD DLL_CALLCONV
FreeImage_ZLibCRC32(DWORD crc,BYTE * source,DWORD source_size)220 FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size) {
221
222 return crc32(crc, source, source_size);
223 }
224