| 26 |
26 |
| 27 #include <stdlib.h> |
27 #include <stdlib.h> |
| 28 #include <string.h> |
28 #include <string.h> |
| 29 |
29 |
| 30 #include "libgadu.h" |
30 #include "libgadu.h" |
| |
31 #include "internal.h" |
| 31 #include "deflate.h" |
32 #include "deflate.h" |
| 32 |
33 |
| 33 #ifdef GG_CONFIG_HAVE_ZLIB |
34 #ifdef GG_CONFIG_HAVE_ZLIB |
| 34 #include <zlib.h> |
35 #include <zlib.h> |
| 35 #endif |
36 #endif |
| 36 |
37 |
| 37 /** |
38 /** |
| 38 * \internal Kompresuje dane wejściowe algorytmem Deflate z najwyższym |
39 * \internal Kompresuje dane wejściowe algorytmem Deflate z najwyższym |
| 39 * stopniem kompresji, tak samo jak oryginalny klient. |
40 * stopniem kompresji, tak samo jak oryginalny klient. |
| 40 * |
41 * |
| 41 * Wynik funkcji należy zwolnić za pomocą \c free. |
42 * Wynik funkcji należy zwolnić za pomocą \c free. |
| 42 * |
43 * |
| 43 * \param in Ciąg znaków do skompresowania, zakończony \c \\0 |
44 * \param in Ciąg znaków do skompresowania, zakończony \c \\0 |
| 44 * \param out_lenp Wskaźnik na zmienną, do której zostanie zapisana |
45 * \param out_lenp Wskaźnik na zmienną, do której zostanie zapisana |
| 45 * długość bufora wynikowego |
46 * długość bufora wynikowego |
| 71 |
72 |
| 72 out_len = deflateBound(&strm, strm.avail_in); |
73 out_len = deflateBound(&strm, strm.avail_in); |
| 73 out = malloc(out_len); |
74 out = malloc(out_len); |
| 74 |
75 |
| 75 if (out == NULL) { |
76 if (out == NULL) { |
| 76 gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for output data (%d)\n", out_len); |
77 gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for " |
| |
78 "output data (%" GG_SIZE_FMT ")\n", out_len); |
| 77 goto fail; |
79 goto fail; |
| 78 } |
80 } |
| 79 |
81 |
| 80 strm.avail_out = out_len; |
82 strm.avail_out = out_len; |
| 81 strm.next_out = out; |
83 strm.next_out = out; |
| 82 |
84 |
| 83 for (;;) { |
85 for (;;) { |
| 84 ret = deflate(&strm, Z_FINISH); |
86 ret = deflate(&strm, Z_FINISH); |
| 85 |
87 |
| 86 if (ret == Z_STREAM_END) |
88 if (ret == Z_STREAM_END) |
| 87 break; |
89 break; |
| 88 |
90 |
| 89 /* raczej nie powinno się zdarzyć przy Z_FINISH i out_len == deflateBound(), |
91 /* raczej nie powinno się zdarzyć przy Z_FINISH i out_len == deflateBound(), |
| 90 * ale dokumentacja zlib nie wyklucza takiej możliwości */ |
92 * ale dokumentacja zlib nie wyklucza takiej możliwości */ |
| 91 if (ret == Z_OK) { |
93 if (ret == Z_OK) { |
| 92 out_len *= 2; |
94 out_len *= 2; |
| 93 out2 = realloc(out, out_len); |
95 out2 = realloc(out, out_len); |
| 94 |
96 |
| 95 if (out2 == NULL) { |
97 if (out2 == NULL) { |
| 96 gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for output data (%d)\n", out_len); |
98 gg_debug(GG_DEBUG_MISC, "// gg_deflate() not " |
| |
99 "enough memory for output data (%" |
| |
100 GG_SIZE_FMT ")\n", out_len); |
| 97 goto fail; |
101 goto fail; |
| 98 } |
102 } |
| 99 |
103 |
| 100 out = out2; |
104 out = out2; |
| 101 |
105 |
| 102 strm.avail_out = out_len / 2; |
106 strm.avail_out = out_len / 2; |
| 103 strm.next_out = out + out_len / 2; |
107 strm.next_out = out + out_len / 2; |
| 104 } else { |
108 } else { |
| 105 gg_debug(GG_DEBUG_MISC, "// gg_deflate() deflate() failed (ret=%d, msg=%s)\n", ret, strm.msg != NULL ? strm.msg : "no error message provided"); |
109 gg_debug(GG_DEBUG_MISC, "// gg_deflate() deflate() " |
| |
110 "failed (ret=%d, msg=%s)\n", ret, |
| |
111 strm.msg != NULL ? strm.msg : |
| |
112 "no error message provided"); |
| 106 goto fail; |
113 goto fail; |
| 107 } |
114 } |
| 108 } |
115 } |
| 109 |
116 |
| 110 out_len = strm.total_out; |
117 out_len = strm.total_out; |
| 111 out2 = realloc(out, out_len); |
118 out2 = realloc(out, out_len); |
| 112 |
119 |
| 113 if (out2 == NULL) { |
120 if (out2 == NULL) { |
| 114 gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for output data (%d)\n", out_len); |
121 gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for " |
| |
122 "output data (%" GG_SIZE_FMT ")\n", out_len); |
| 115 goto fail; |
123 goto fail; |
| 116 } |
124 } |
| 117 |
125 |
| 118 *out_lenp = out_len; |
126 *out_lenp = out_len; |
| 119 deflateEnd(&strm); |
127 deflateEnd(&strm); |
| 166 } |
174 } |
| 167 |
175 |
| 168 do { |
176 do { |
| 169 out_len *= 2; |
177 out_len *= 2; |
| 170 out2 = realloc(out, out_len); |
178 out2 = realloc(out, out_len); |
| 171 |
179 |
| 172 if (out2 == NULL) { |
180 if (out2 == NULL) { |
| 173 gg_debug(GG_DEBUG_MISC, "// gg_inflate() not enough memory for output data (%d)\n", out_len); |
181 gg_debug(GG_DEBUG_MISC, "// gg_inflate() not enough " |
| |
182 "memory for output data (%" GG_SIZE_FMT ")\n", out_len); |
| 174 goto fail; |
183 goto fail; |
| 175 } |
184 } |
| 176 |
185 |
| 177 out = out2; |
186 out = out2; |
| 178 |
187 |
| 179 if (first) { |
188 if (first) { |
| 180 strm.avail_out = out_len; |
189 strm.avail_out = out_len; |
| 181 strm.next_out = (unsigned char*) out; |
190 strm.next_out = (unsigned char*) out; |
| 182 } else { |
191 } else { |
| 183 strm.avail_out = out_len / 2; |
192 strm.avail_out = out_len / 2; |
| 184 strm.next_out = (unsigned char*) out + out_len / 2; |
193 strm.next_out = (unsigned char*) out + out_len / 2; |
| 185 } |
194 } |
| 186 |
195 |
| 187 ret = inflate(&strm, Z_NO_FLUSH); |
196 ret = inflate(&strm, Z_NO_FLUSH); |
| 188 |
197 |
| 189 if (ret != Z_OK && ret != Z_STREAM_END) { |
198 if (ret != Z_OK && ret != Z_STREAM_END) { |
| 190 gg_debug(GG_DEBUG_MISC, "// gg_inflate() inflate() failed (ret=%d, msg=%s)\n", ret, strm.msg != NULL ? strm.msg : "no error message provided"); |
199 gg_debug(GG_DEBUG_MISC, "// gg_inflate() inflate() " |
| |
200 "failed (ret=%d, msg=%s)\n", ret, |
| |
201 strm.msg != NULL ? strm.msg : |
| |
202 "no error message provided"); |
| 191 goto fail; |
203 goto fail; |
| 192 } |
204 } |
| 193 |
205 |
| 194 first = 0; |
206 first = 0; |
| 195 } while (ret != Z_STREAM_END); |
207 } while (ret != Z_STREAM_END); |
| 196 |
208 |
| 197 /* rezerwujemy ostatni znak na NULL-a */ |
209 /* rezerwujemy ostatni znak na NULL-a */ |
| 198 out_len = strm.total_out + 1; |
210 out_len = strm.total_out + 1; |
| 199 out2 = realloc(out, out_len); |
211 out2 = realloc(out, out_len); |
| 200 |
212 |
| 201 if (out2 == NULL) { |
213 if (out2 == NULL) { |
| 202 gg_debug(GG_DEBUG_MISC, "// gg_inflate() not enough memory for output data (%d)\n", out_len); |
214 gg_debug(GG_DEBUG_MISC, "// gg_inflate() not enough memory for " |
| |
215 "output data (%" GG_SIZE_FMT ")\n", out_len); |
| 203 goto fail; |
216 goto fail; |
| 204 } |
217 } |
| 205 |
218 |
| 206 out = out2; |
219 out = out2; |
| 207 out[out_len - 1] = '\0'; |
220 out[out_len - 1] = '\0'; |