Branch data Line data Source code
1 : : /* GLib testing framework examples and tests
2 : : * Copyright (C) 2009 Red Hat, Inc.
3 : : * Authors: Alexander Larsson <alexl@redhat.com>
4 : : *
5 : : * SPDX-License-Identifier: LicenseRef-old-glib-tests
6 : : *
7 : : * This work is provided "as is"; redistribution and modification
8 : : * in whole or in part, in any medium, physical or electronic is
9 : : * permitted without restriction.
10 : : *
11 : : * This work is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 : : *
15 : : * In no event shall the authors or contributors be liable for any
16 : : * direct, indirect, incidental, special, exemplary, or consequential
17 : : * damages (including, but not limited to, procurement of substitute
18 : : * goods or services; loss of use, data, or profits; or business
19 : : * interruption) however caused and on any theory of liability, whether
20 : : * in contract, strict liability, or tort (including negligence or
21 : : * otherwise) arising in any way out of the use of this software, even
22 : : * if advised of the possibility of such damage.
23 : : */
24 : :
25 : : #include <glib/glib.h>
26 : : #include <gio/gio.h>
27 : : #include <stdlib.h>
28 : : #include <string.h>
29 : :
30 : : #define G_TYPE_EXPANDER_CONVERTER (g_expander_converter_get_type ())
31 : : #define G_EXPANDER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_EXPANDER_CONVERTER, GExpanderConverter))
32 : : #define G_EXPANDER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_EXPANDER_CONVERTER, GExpanderConverterClass))
33 : : #define G_IS_EXPANDER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_EXPANDER_CONVERTER))
34 : : #define G_IS_EXPANDER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_EXPANDER_CONVERTER))
35 : : #define G_EXPANDER_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_EXPANDER_CONVERTER, GExpanderConverterClass))
36 : :
37 : : typedef struct _GExpanderConverter GExpanderConverter;
38 : : typedef struct _GExpanderConverterClass GExpanderConverterClass;
39 : :
40 : : struct _GExpanderConverterClass
41 : : {
42 : : GObjectClass parent_class;
43 : : };
44 : :
45 : : GType g_expander_converter_get_type (void);
46 : : GConverter *g_expander_converter_new (void);
47 : :
48 : :
49 : :
50 : : static void g_expander_converter_iface_init (GConverterIface *iface);
51 : :
52 : : struct _GExpanderConverter
53 : : {
54 : : GObject parent_instance;
55 : : };
56 : :
57 : 11 : G_DEFINE_TYPE_WITH_CODE (GExpanderConverter, g_expander_converter, G_TYPE_OBJECT,
58 : 1 : G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
59 : : g_expander_converter_iface_init))
60 : :
61 : : static void
62 : 2 : g_expander_converter_class_init (GExpanderConverterClass *klass)
63 : : {
64 : 2 : }
65 : :
66 : : static void
67 : 6 : g_expander_converter_init (GExpanderConverter *local)
68 : : {
69 : 6 : }
70 : :
71 : : GConverter *
72 : 6 : g_expander_converter_new (void)
73 : : {
74 : : GConverter *conv;
75 : :
76 : 6 : conv = g_object_new (G_TYPE_EXPANDER_CONVERTER, NULL);
77 : :
78 : 6 : return conv;
79 : : }
80 : :
81 : : static void
82 : 4 : g_expander_converter_reset (GConverter *converter)
83 : : {
84 : 4 : }
85 : :
86 : : static GConverterResult
87 : 68 : g_expander_converter_convert (GConverter *converter,
88 : : const void *inbuf,
89 : : gsize inbuf_size,
90 : : void *outbuf,
91 : : gsize outbuf_size,
92 : : GConverterFlags flags,
93 : : gsize *bytes_read,
94 : : gsize *bytes_written,
95 : : GError **error)
96 : : {
97 : : const guint8 *in, *in_end;
98 : : guint8 v, *out;
99 : : gsize i;
100 : : gsize block_size;
101 : :
102 : : /* An empty input buffer may be passed as NULL, which must not be offset. */
103 : 68 : if (inbuf == NULL || inbuf_size == 0)
104 : : {
105 : 4 : if (flags & G_CONVERTER_INPUT_AT_END)
106 : 4 : return G_CONVERTER_FINISHED;
107 : 0 : return G_CONVERTER_CONVERTED;
108 : : }
109 : :
110 : 64 : in = inbuf;
111 : 64 : out = outbuf;
112 : 64 : in_end = in + inbuf_size;
113 : :
114 : 174 : while (in < in_end)
115 : : {
116 : 144 : v = *in;
117 : :
118 : 144 : if (v == 0)
119 : 32 : block_size = 10;
120 : : else
121 : 112 : block_size = v * 1000;
122 : :
123 : 144 : if (outbuf_size < block_size)
124 : : {
125 : 34 : if (*bytes_read > 0)
126 : 12 : return G_CONVERTER_CONVERTED;
127 : :
128 : 22 : g_set_error_literal (error, G_IO_ERROR,
129 : : G_IO_ERROR_NO_SPACE,
130 : : "No space in dest");
131 : 22 : return G_CONVERTER_ERROR;
132 : : }
133 : :
134 : 110 : in++;
135 : 110 : *bytes_read += 1;
136 : 110 : *bytes_written += block_size;
137 : 110 : outbuf_size -= block_size;
138 : 410410 : for (i = 0; i < block_size; i++)
139 : 410300 : *out++ = v;
140 : : }
141 : :
142 : 30 : if (in == in_end && (flags & G_CONVERTER_INPUT_AT_END))
143 : 6 : return G_CONVERTER_FINISHED;
144 : 24 : return G_CONVERTER_CONVERTED;
145 : 34 : }
146 : :
147 : : static void
148 : 2 : g_expander_converter_iface_init (GConverterIface *iface)
149 : : {
150 : 2 : iface->convert = g_expander_converter_convert;
151 : 2 : iface->reset = g_expander_converter_reset;
152 : 2 : }
153 : :
154 : : #define G_TYPE_COMPRESSOR_CONVERTER (g_compressor_converter_get_type ())
155 : : #define G_COMPRESSOR_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverter))
156 : : #define G_COMPRESSOR_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverterClass))
157 : : #define G_IS_COMPRESSOR_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_COMPRESSOR_CONVERTER))
158 : : #define G_IS_COMPRESSOR_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_COMPRESSOR_CONVERTER))
159 : : #define G_COMPRESSOR_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverterClass))
160 : :
161 : : typedef struct _GCompressorConverter GCompressorConverter;
162 : : typedef struct _GCompressorConverterClass GCompressorConverterClass;
163 : :
164 : : struct _GCompressorConverterClass
165 : : {
166 : : GObjectClass parent_class;
167 : : };
168 : :
169 : : GType g_compressor_converter_get_type (void);
170 : : GConverter *g_compressor_converter_new (void);
171 : :
172 : :
173 : :
174 : : static void g_compressor_converter_iface_init (GConverterIface *iface);
175 : :
176 : : struct _GCompressorConverter
177 : : {
178 : : GObject parent_instance;
179 : : };
180 : :
181 : 9 : G_DEFINE_TYPE_WITH_CODE (GCompressorConverter, g_compressor_converter, G_TYPE_OBJECT,
182 : 1 : G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
183 : : g_compressor_converter_iface_init))
184 : :
185 : : static void
186 : 2 : g_compressor_converter_class_init (GCompressorConverterClass *klass)
187 : : {
188 : 2 : }
189 : :
190 : : static void
191 : 4 : g_compressor_converter_init (GCompressorConverter *local)
192 : : {
193 : 4 : }
194 : :
195 : : GConverter *
196 : 4 : g_compressor_converter_new (void)
197 : : {
198 : : GConverter *conv;
199 : :
200 : 4 : conv = g_object_new (G_TYPE_COMPRESSOR_CONVERTER, NULL);
201 : :
202 : 4 : return conv;
203 : : }
204 : :
205 : : static void
206 : 8 : g_compressor_converter_reset (GConverter *converter)
207 : : {
208 : 8 : }
209 : :
210 : : static GConverterResult
211 : 164450 : g_compressor_converter_convert (GConverter *converter,
212 : : const void *inbuf,
213 : : gsize inbuf_size,
214 : : void *outbuf,
215 : : gsize outbuf_size,
216 : : GConverterFlags flags,
217 : : gsize *bytes_read,
218 : : gsize *bytes_written,
219 : : GError **error)
220 : : {
221 : : const guint8 *in, *in_end;
222 : : guint8 v, *out;
223 : : gsize i;
224 : : gsize block_size;
225 : :
226 : : /* An empty input buffer may be passed as NULL, which must not be offset. */
227 : 164450 : if (inbuf == NULL || inbuf_size == 0)
228 : : {
229 : 4 : if (flags & G_CONVERTER_INPUT_AT_END)
230 : 4 : return G_CONVERTER_FINISHED;
231 : 0 : return G_CONVERTER_CONVERTED;
232 : : }
233 : :
234 : 164446 : in = inbuf;
235 : 164446 : out = outbuf;
236 : 164446 : in_end = in + inbuf_size;
237 : :
238 : 164534 : while (in < in_end)
239 : : {
240 : 164490 : v = *in;
241 : :
242 : 164490 : if (v == 0)
243 : : {
244 : 148 : block_size = 0;
245 : 1688 : while (in+block_size < in_end && *(in+block_size) == 0)
246 : 1540 : block_size ++;
247 : 74 : }
248 : : else
249 : 164342 : block_size = v * 1000;
250 : :
251 : : /* Not enough data */
252 : 164490 : if ((gsize) (in_end - in) < block_size)
253 : : {
254 : 164270 : if (*bytes_read > 0)
255 : 32 : break;
256 : 164238 : g_set_error_literal (error, G_IO_ERROR,
257 : : G_IO_ERROR_PARTIAL_INPUT,
258 : : "Need more data");
259 : 164238 : return G_CONVERTER_ERROR;
260 : : }
261 : :
262 : 369760 : for (i = 0; i < block_size; i++)
263 : : {
264 : 369540 : if (*(in + i) != v)
265 : : {
266 : 0 : if (*bytes_read > 0)
267 : 0 : break;
268 : 0 : g_set_error_literal (error, G_IO_ERROR,
269 : : G_IO_ERROR_INVALID_DATA,
270 : : "invalid data");
271 : 0 : return G_CONVERTER_ERROR;
272 : : }
273 : 184770 : }
274 : :
275 : 220 : if (v == 0 && (gsize) (in_end - in) == block_size && (flags & G_CONVERTER_INPUT_AT_END) == 0)
276 : : {
277 : 132 : if (*bytes_read > 0)
278 : 4 : break;
279 : 128 : g_set_error_literal (error, G_IO_ERROR,
280 : : G_IO_ERROR_PARTIAL_INPUT,
281 : : "Need more data");
282 : 128 : return G_CONVERTER_ERROR;
283 : : }
284 : :
285 : 88 : in += block_size;
286 : 88 : *out++ = v;
287 : 88 : *bytes_read += block_size;
288 : 88 : *bytes_written += 1;
289 : : }
290 : :
291 : 80 : if (in == in_end && (flags & G_CONVERTER_INPUT_AT_END))
292 : 8 : return G_CONVERTER_FINISHED;
293 : 72 : return G_CONVERTER_CONVERTED;
294 : 82225 : }
295 : :
296 : : static void
297 : 2 : g_compressor_converter_iface_init (GConverterIface *iface)
298 : : {
299 : 2 : iface->convert = g_compressor_converter_convert;
300 : 2 : iface->reset = g_compressor_converter_reset;
301 : 2 : }
302 : :
303 : : guint8 unexpanded_data[] = { 0,1,3,4,5,6,7,3,12,0,0};
304 : :
305 : : static void
306 : 2 : test_expander (void)
307 : : {
308 : : guint8 *converted1, *converted2, *ptr;
309 : : gsize n_read, n_written;
310 : : gsize total_read;
311 : : gssize res;
312 : : GConverterResult cres;
313 : : GInputStream *mem, *cstream;
314 : : GOutputStream *mem_out, *cstream_out;
315 : : GConverter *expander;
316 : : GConverter *converter;
317 : : GError *error;
318 : : gsize i;
319 : :
320 : 2 : expander = g_expander_converter_new ();
321 : :
322 : 2 : converted1 = g_malloc (100*1000); /* Large enough */
323 : 2 : converted2 = g_malloc (100*1000); /* Large enough */
324 : :
325 : 3 : cres = g_converter_convert (expander,
326 : : unexpanded_data, sizeof(unexpanded_data),
327 : 1 : converted1, 100*1000,
328 : : G_CONVERTER_INPUT_AT_END,
329 : : &n_read, &n_written, NULL);
330 : :
331 : 2 : g_assert_cmpint (cres, ==, G_CONVERTER_FINISHED);
332 : 2 : g_assert_cmpuint (n_read, ==, 11);
333 : 2 : g_assert_cmpuint (n_written, ==, 41030);
334 : :
335 : 2 : g_converter_reset (expander);
336 : :
337 : 2 : mem = g_memory_input_stream_new_from_data (unexpanded_data,
338 : : sizeof (unexpanded_data),
339 : : NULL);
340 : 2 : cstream = g_converter_input_stream_new (mem, expander);
341 : 2 : g_assert_true (g_converter_input_stream_get_converter (G_CONVERTER_INPUT_STREAM (cstream)) == expander);
342 : 2 : g_object_get (cstream, "converter", &converter, NULL);
343 : 2 : g_assert_true (converter == expander);
344 : 2 : g_object_unref (converter);
345 : 2 : g_object_unref (mem);
346 : :
347 : 2 : total_read = 0;
348 : 2 : ptr = converted2;
349 : 41031 : while (TRUE)
350 : : {
351 : 82062 : error = NULL;
352 : 123093 : res = g_input_stream_read (cstream,
353 : 41031 : ptr, 1,
354 : : NULL, &error);
355 : 82062 : g_assert_cmpint (res, !=, -1);
356 : 82062 : if (res == 0)
357 : 2 : break;
358 : 82060 : ptr += res;
359 : 82060 : total_read += res;
360 : : }
361 : :
362 : 3 : g_assert_cmpmem (converted1, n_written, converted2, total_read);
363 : :
364 : 2 : g_converter_reset (expander);
365 : :
366 : 2 : mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
367 : 2 : cstream_out = g_converter_output_stream_new (mem_out, expander);
368 : 2 : g_assert_true (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (cstream_out)) == expander);
369 : 2 : g_object_get (cstream_out, "converter", &converter, NULL);
370 : 2 : g_assert_true (converter == expander);
371 : 2 : g_object_unref (converter);
372 : 2 : g_object_unref (mem_out);
373 : :
374 : 24 : for (i = 0; i < sizeof(unexpanded_data); i++)
375 : : {
376 : 22 : error = NULL;
377 : 33 : res = g_output_stream_write (cstream_out,
378 : 11 : unexpanded_data + i, 1,
379 : : NULL, &error);
380 : 22 : g_assert_cmpint (res, !=, -1);
381 : 22 : if (res == 0)
382 : : {
383 : 0 : g_assert_cmpuint (i, ==, sizeof(unexpanded_data) -1);
384 : 0 : break;
385 : : }
386 : 22 : g_assert_cmpint (res, ==, 1);
387 : 11 : }
388 : :
389 : 2 : g_output_stream_close (cstream_out, NULL, NULL);
390 : :
391 : 3 : g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
392 : 1 : g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)),
393 : 2 : converted1, n_written);
394 : :
395 : 2 : g_free (converted1);
396 : 2 : g_free (converted2);
397 : 2 : g_object_unref (cstream);
398 : 2 : g_object_unref (cstream_out);
399 : 2 : g_object_unref (expander);
400 : 2 : }
401 : :
402 : : static void
403 : 2 : test_compressor (void)
404 : : {
405 : : guint8 *converted, *expanded, *ptr;
406 : : gsize n_read, expanded_size;
407 : : gsize total_read;
408 : : gssize res;
409 : : GConverterResult cres;
410 : : GInputStream *mem, *cstream;
411 : : GOutputStream *mem_out, *cstream_out;
412 : : GConverter *expander, *compressor;
413 : : GError *error;
414 : : gsize i;
415 : :
416 : 2 : expander = g_expander_converter_new ();
417 : 2 : expanded = g_malloc (100*1000); /* Large enough */
418 : 3 : cres = g_converter_convert (expander,
419 : : unexpanded_data, sizeof(unexpanded_data),
420 : 1 : expanded, 100*1000,
421 : : G_CONVERTER_INPUT_AT_END,
422 : : &n_read, &expanded_size, NULL);
423 : 2 : g_assert_cmpint (cres, ==, G_CONVERTER_FINISHED);
424 : 2 : g_assert_cmpuint (n_read, ==, 11);
425 : 2 : g_assert_cmpuint (expanded_size, ==, 41030);
426 : :
427 : 2 : compressor = g_compressor_converter_new ();
428 : :
429 : 2 : converted = g_malloc (100*1000); /* Large enough */
430 : :
431 : 3 : mem = g_memory_input_stream_new_from_data (expanded,
432 : 1 : expanded_size,
433 : : NULL);
434 : 2 : cstream = g_converter_input_stream_new (mem, compressor);
435 : 2 : g_object_unref (mem);
436 : :
437 : 2 : total_read = 0;
438 : 2 : ptr = converted;
439 : 9 : while (TRUE)
440 : : {
441 : 18 : error = NULL;
442 : 27 : res = g_input_stream_read (cstream,
443 : 9 : ptr, 1,
444 : : NULL, &error);
445 : 18 : g_assert_cmpint (res, !=, -1);
446 : 18 : if (res == 0)
447 : 2 : break;
448 : 16 : ptr += res;
449 : 16 : total_read += res;
450 : : }
451 : :
452 : : /* "n_read - 1" because last 2 zeros are combined */
453 : 3 : g_assert_cmpmem (unexpanded_data, n_read - 1, converted, total_read);
454 : :
455 : 2 : g_object_unref (cstream);
456 : :
457 : 2 : g_converter_reset (compressor);
458 : :
459 : 2 : mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
460 : 2 : cstream_out = g_converter_output_stream_new (mem_out, compressor);
461 : 2 : g_object_unref (mem_out);
462 : :
463 : 82062 : for (i = 0; i < expanded_size; i++)
464 : : {
465 : 82060 : error = NULL;
466 : 123090 : res = g_output_stream_write (cstream_out,
467 : 82060 : expanded + i, 1,
468 : : NULL, &error);
469 : 82060 : g_assert_cmpint (res, !=, -1);
470 : 82060 : if (res == 0)
471 : : {
472 : 0 : g_assert_cmpuint (i, ==, expanded_size -1);
473 : 0 : break;
474 : : }
475 : 82060 : g_assert_cmpint (res, ==, 1);
476 : 41030 : }
477 : :
478 : 2 : g_output_stream_close (cstream_out, NULL, NULL);
479 : :
480 : : /* "n_read - 1" because last 2 zeros are combined */
481 : 3 : g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
482 : 1 : g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)),
483 : : unexpanded_data,
484 : 1 : n_read - 1);
485 : :
486 : 2 : g_object_unref (cstream_out);
487 : :
488 : 2 : g_converter_reset (compressor);
489 : :
490 : 2 : memset (expanded, 5, 5*1000*2);
491 : :
492 : 2 : mem = g_memory_input_stream_new_from_data (expanded,
493 : : 5*1000,
494 : : NULL);
495 : 2 : cstream = g_converter_input_stream_new (mem, compressor);
496 : 2 : g_object_unref (mem);
497 : :
498 : 2 : total_read = 0;
499 : 2 : ptr = converted;
500 : 2 : while (TRUE)
501 : : {
502 : 4 : error = NULL;
503 : 6 : res = g_input_stream_read (cstream,
504 : 2 : ptr, 1,
505 : : NULL, &error);
506 : 4 : g_assert_cmpint (res, !=, -1);
507 : 4 : if (res == 0)
508 : 2 : break;
509 : 2 : ptr += res;
510 : 2 : total_read += res;
511 : : }
512 : :
513 : 2 : g_assert_cmpuint (total_read, ==, 1);
514 : 2 : g_assert_cmpuint (*converted, ==, 5);
515 : :
516 : 2 : g_object_unref (cstream);
517 : :
518 : 2 : mem = g_memory_input_stream_new_from_data (expanded,
519 : : 5*1000 * 2,
520 : : NULL);
521 : 2 : cstream = g_converter_input_stream_new (mem, compressor);
522 : 2 : g_object_unref (mem);
523 : :
524 : 2 : total_read = 0;
525 : 2 : ptr = converted;
526 : 3 : while (TRUE)
527 : : {
528 : 6 : error = NULL;
529 : 9 : res = g_input_stream_read (cstream,
530 : 3 : ptr, 1,
531 : : NULL, &error);
532 : 6 : g_assert_cmpint (res, !=, -1);
533 : 6 : if (res == 0)
534 : 2 : break;
535 : 4 : ptr += res;
536 : 4 : total_read += res;
537 : : }
538 : :
539 : 2 : g_assert_cmpuint (total_read, ==, 2);
540 : 2 : g_assert_cmpuint (converted[0], ==, 5);
541 : 2 : g_assert_cmpuint (converted[1], ==, 5);
542 : :
543 : 2 : g_object_unref (cstream);
544 : :
545 : 2 : g_converter_reset (compressor);
546 : :
547 : 2 : mem = g_memory_input_stream_new_from_data (expanded,
548 : : 5*1000 * 2 - 1,
549 : : NULL);
550 : 2 : cstream = g_converter_input_stream_new (mem, compressor);
551 : 2 : g_object_unref (mem);
552 : :
553 : 2 : total_read = 0;
554 : 2 : ptr = converted;
555 : 2 : while (TRUE)
556 : : {
557 : 4 : error = NULL;
558 : 6 : res = g_input_stream_read (cstream,
559 : 2 : ptr, 1,
560 : : NULL, &error);
561 : 4 : if (res == -1)
562 : : {
563 : 2 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT);
564 : 2 : g_error_free (error);
565 : 2 : break;
566 : : }
567 : :
568 : 2 : g_assert_cmpint (res, !=, 0);
569 : 2 : ptr += res;
570 : 2 : total_read += res;
571 : : }
572 : :
573 : 2 : g_assert_cmpuint (total_read, ==, 1);
574 : 2 : g_assert_cmpuint (converted[0], ==, 5);
575 : :
576 : 2 : g_object_unref (cstream);
577 : :
578 : 2 : g_free (expanded);
579 : 2 : g_free (converted);
580 : 2 : g_object_unref (expander);
581 : 2 : g_object_unref (compressor);
582 : 2 : }
583 : :
584 : : #define LEFTOVER_SHORT_READ_SIZE 512
585 : :
586 : : #define G_TYPE_LEFTOVER_CONVERTER (g_leftover_converter_get_type ())
587 : : #define G_LEFTOVER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverter))
588 : : #define G_LEFTOVER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverterClass))
589 : : #define G_IS_LEFTOVER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_LEFTOVER_CONVERTER))
590 : : #define G_IS_LEFTOVER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_LEFTOVER_CONVERTER))
591 : : #define G_LEFTOVER_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverterClass))
592 : :
593 : : typedef struct _GLeftoverConverter GLeftoverConverter;
594 : : typedef struct _GLeftoverConverterClass GLeftoverConverterClass;
595 : :
596 : : struct _GLeftoverConverterClass
597 : : {
598 : : GObjectClass parent_class;
599 : : };
600 : :
601 : : GType g_leftover_converter_get_type (void);
602 : : GConverter *g_leftover_converter_new (void);
603 : :
604 : :
605 : :
606 : : static void g_leftover_converter_iface_init (GConverterIface *iface);
607 : :
608 : : struct _GLeftoverConverter
609 : : {
610 : : GObject parent_instance;
611 : : };
612 : :
613 : 7 : G_DEFINE_TYPE_WITH_CODE (GLeftoverConverter, g_leftover_converter, G_TYPE_OBJECT,
614 : 1 : G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
615 : : g_leftover_converter_iface_init))
616 : :
617 : : static void
618 : 2 : g_leftover_converter_class_init (GLeftoverConverterClass *klass)
619 : : {
620 : 2 : }
621 : :
622 : : static void
623 : 2 : g_leftover_converter_init (GLeftoverConverter *local)
624 : : {
625 : 2 : }
626 : :
627 : : GConverter *
628 : 2 : g_leftover_converter_new (void)
629 : : {
630 : : GConverter *conv;
631 : :
632 : 2 : conv = g_object_new (G_TYPE_LEFTOVER_CONVERTER, NULL);
633 : :
634 : 2 : return conv;
635 : : }
636 : :
637 : : static void
638 : 0 : g_leftover_converter_reset (GConverter *converter)
639 : : {
640 : 0 : }
641 : :
642 : : static GConverterResult
643 : 10 : g_leftover_converter_convert (GConverter *converter,
644 : : const void *inbuf,
645 : : gsize inbuf_size,
646 : : void *outbuf,
647 : : gsize outbuf_size,
648 : : GConverterFlags flags,
649 : : gsize *bytes_read,
650 : : gsize *bytes_written,
651 : : GError **error)
652 : : {
653 : 10 : if (outbuf_size == LEFTOVER_SHORT_READ_SIZE)
654 : : {
655 : 3 : g_set_error_literal (error,
656 : 1 : G_IO_ERROR,
657 : : G_IO_ERROR_PARTIAL_INPUT,
658 : : "partial input");
659 : 2 : return G_CONVERTER_ERROR;
660 : : }
661 : :
662 : 8 : if (inbuf_size < 100)
663 : 4 : *bytes_read = *bytes_written = MIN (inbuf_size, outbuf_size);
664 : : else
665 : 4 : *bytes_read = *bytes_written = MIN (inbuf_size - 10, outbuf_size);
666 : 8 : memcpy (outbuf, inbuf, *bytes_written);
667 : :
668 : 8 : if (*bytes_read == inbuf_size && (flags & G_CONVERTER_INPUT_AT_END))
669 : 0 : return G_CONVERTER_FINISHED;
670 : 8 : return G_CONVERTER_CONVERTED;
671 : 5 : }
672 : :
673 : : static void
674 : 2 : g_leftover_converter_iface_init (GConverterIface *iface)
675 : : {
676 : 2 : iface->convert = g_leftover_converter_convert;
677 : 2 : iface->reset = g_leftover_converter_reset;
678 : 2 : }
679 : :
680 : : #define LEFTOVER_BUFSIZE 8192
681 : : #define INTERNAL_BUFSIZE 4096
682 : :
683 : : static void
684 : 2 : test_converter_leftover (void)
685 : : {
686 : : gchar *orig, *converted;
687 : : gsize total_read;
688 : : gssize res;
689 : : goffset offset;
690 : : GInputStream *mem, *cstream;
691 : : GConverter *converter;
692 : : GError *error;
693 : : int i;
694 : :
695 : 2 : converter = g_leftover_converter_new ();
696 : :
697 : 2 : orig = g_malloc (LEFTOVER_BUFSIZE);
698 : 2 : converted = g_malloc (LEFTOVER_BUFSIZE);
699 : 16386 : for (i = 0; i < LEFTOVER_BUFSIZE; i++)
700 : 16384 : orig[i] = i % 64 + 32;
701 : :
702 : 2 : mem = g_memory_input_stream_new_from_data (orig, LEFTOVER_BUFSIZE, NULL);
703 : 2 : cstream = g_converter_input_stream_new (mem, G_CONVERTER (converter));
704 : 2 : g_object_unref (mem);
705 : :
706 : 2 : total_read = 0;
707 : :
708 : 2 : error = NULL;
709 : 3 : res = g_input_stream_read (cstream,
710 : 1 : converted, LEFTOVER_SHORT_READ_SIZE,
711 : : NULL, &error);
712 : 2 : g_assert_cmpint (res, ==, LEFTOVER_SHORT_READ_SIZE);
713 : 2 : total_read += res;
714 : :
715 : 2 : offset = g_seekable_tell (G_SEEKABLE (mem));
716 : 2 : g_assert_cmpint (offset, >, LEFTOVER_SHORT_READ_SIZE);
717 : 2 : g_assert_cmpint (offset, <, LEFTOVER_BUFSIZE);
718 : :
719 : : /* At this point, @cstream has both a non-empty input_buffer
720 : : * and a non-empty converted_buffer, which is the case
721 : : * we want to test.
722 : : */
723 : :
724 : 4 : while (TRUE)
725 : : {
726 : 8 : error = NULL;
727 : 12 : res = g_input_stream_read (cstream,
728 : 8 : converted + total_read,
729 : 4 : LEFTOVER_BUFSIZE - total_read,
730 : : NULL, &error);
731 : 8 : g_assert_cmpint (res, >=, 0);
732 : 8 : if (res == 0)
733 : 2 : break;
734 : 6 : total_read += res;
735 : : }
736 : :
737 : 3 : g_assert_cmpmem (orig, LEFTOVER_BUFSIZE, converted, total_read);
738 : :
739 : 2 : g_object_unref (cstream);
740 : 2 : g_free (orig);
741 : 2 : g_free (converted);
742 : 2 : g_object_unref (converter);
743 : 2 : }
744 : :
745 : : #define DATA_LENGTH 1000000
746 : :
747 : : typedef struct {
748 : : const gchar *path;
749 : : GZlibCompressorFormat format;
750 : : gint level;
751 : : } CompressorTest;
752 : :
753 : : static void
754 : 12 : test_roundtrip (gconstpointer data)
755 : : {
756 : 12 : const CompressorTest *test = data;
757 : 12 : GError *error = NULL;
758 : : guint32 *data0, *data1;
759 : : gsize data1_size;
760 : : gint i;
761 : : GInputStream *istream0, *istream1, *cistream1;
762 : : GOutputStream *ostream1, *ostream2, *costream1;
763 : : GConverter *compressor, *decompressor;
764 : : GZlibCompressorFormat fmt;
765 : : gint lvl;
766 : : GFileInfo *info;
767 : : GFileInfo *info2;
768 : :
769 : 12 : g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=619945");
770 : :
771 : 12 : data0 = g_malloc (DATA_LENGTH * sizeof (guint32));
772 : 12000012 : for (i = 0; i < DATA_LENGTH; i++)
773 : 12000000 : data0[i] = g_random_int ();
774 : :
775 : 12 : istream0 = g_memory_input_stream_new_from_data (data0,
776 : : DATA_LENGTH * sizeof (guint32), NULL);
777 : :
778 : 12 : ostream1 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
779 : 12 : compressor = G_CONVERTER (g_zlib_compressor_new (test->format, test->level));
780 : 12 : info = g_file_info_new ();
781 : 12 : g_file_info_set_name (info, "foo");
782 : 12 : g_object_set (compressor, "file-info", info, NULL);
783 : 12 : info2 = g_zlib_compressor_get_file_info (G_ZLIB_COMPRESSOR (compressor));
784 : 12 : g_assert_true (info == info2);
785 : 12 : g_object_unref (info);
786 : 12 : costream1 = g_converter_output_stream_new (ostream1, compressor);
787 : 12 : g_assert_true (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor);
788 : :
789 : 12 : g_output_stream_splice (costream1, istream0, 0, NULL, &error);
790 : 12 : g_assert_no_error (error);
791 : :
792 : 12 : g_object_unref (costream1);
793 : :
794 : 12 : g_converter_reset (compressor);
795 : 12 : g_object_get (compressor, "format", &fmt, "level", &lvl, NULL);
796 : 12 : g_assert_cmpint (fmt, ==, test->format);
797 : 12 : g_assert_cmpint (lvl, ==, test->level);
798 : 12 : g_object_unref (compressor);
799 : 12 : data1 = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (ostream1));
800 : 12 : data1_size = g_memory_output_stream_get_data_size (
801 : 12 : G_MEMORY_OUTPUT_STREAM (ostream1));
802 : 12 : g_object_unref (ostream1);
803 : 12 : g_object_unref (istream0);
804 : :
805 : 12 : istream1 = g_memory_input_stream_new_from_data (data1, data1_size, g_free);
806 : 12 : decompressor = G_CONVERTER (g_zlib_decompressor_new (test->format));
807 : 12 : cistream1 = g_converter_input_stream_new (istream1, decompressor);
808 : :
809 : 12 : ostream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
810 : :
811 : 12 : g_output_stream_splice (ostream2, cistream1, 0, NULL, &error);
812 : 12 : g_assert_no_error (error);
813 : :
814 : 18 : g_assert_cmpmem (data0, DATA_LENGTH * sizeof (guint32),
815 : 6 : g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (ostream2)),
816 : 6 : g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (ostream2)));
817 : 12 : g_object_unref (istream1);
818 : 12 : g_converter_reset (decompressor);
819 : 12 : g_object_get (decompressor, "format", &fmt, NULL);
820 : 12 : g_assert_cmpint (fmt, ==, test->format);
821 : 12 : g_object_unref (decompressor);
822 : 12 : g_object_unref (cistream1);
823 : 12 : g_object_unref (ostream2);
824 : 12 : g_free (data0);
825 : 12 : }
826 : :
827 : : typedef struct {
828 : : const gchar *path;
829 : : const gchar *charset_in;
830 : : const gchar *text_in;
831 : : const gchar *charset_out;
832 : : const gchar *text_out;
833 : : gint n_fallbacks;
834 : : } CharsetTest;
835 : :
836 : : static void
837 : 6 : test_charset (gconstpointer data)
838 : : {
839 : 6 : const CharsetTest *test = data;
840 : : GInputStream *in, *in2;
841 : : GConverter *conv;
842 : : gchar *buffer;
843 : : gsize count;
844 : : gsize bytes_read;
845 : : GError *error;
846 : : gboolean fallback;
847 : :
848 : 6 : conv = (GConverter *)g_charset_converter_new (test->charset_out, test->charset_in, NULL);
849 : 6 : g_object_get (conv, "use-fallback", &fallback, NULL);
850 : 6 : g_assert_false (fallback);
851 : :
852 : 6 : in = g_memory_input_stream_new_from_data (test->text_in, -1, NULL);
853 : 6 : in2 = g_converter_input_stream_new (in, conv);
854 : :
855 : 6 : count = 2 * strlen (test->text_out);
856 : 6 : buffer = g_malloc0 (count);
857 : 6 : error = NULL;
858 : 6 : g_input_stream_read_all (in2, buffer, count, &bytes_read, NULL, &error);
859 : 6 : if (test->n_fallbacks == 0)
860 : : {
861 : 4 : g_assert_no_error (error);
862 : 4 : g_assert_cmpint (bytes_read, ==, strlen (test->text_out));
863 : 4 : g_assert_cmpstr (buffer, ==, test->text_out);
864 : 2 : }
865 : : else
866 : : {
867 : 2 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
868 : 2 : g_error_free (error);
869 : : }
870 : :
871 : 6 : g_free (buffer);
872 : 6 : g_object_unref (in2);
873 : 6 : g_object_unref (in);
874 : :
875 : 6 : if (test->n_fallbacks == 0)
876 : : {
877 : 4 : g_object_unref (conv);
878 : 4 : return;
879 : : }
880 : :
881 : 2 : g_converter_reset (conv);
882 : :
883 : 2 : g_assert_false (g_charset_converter_get_use_fallback (G_CHARSET_CONVERTER (conv)));
884 : 2 : g_charset_converter_set_use_fallback (G_CHARSET_CONVERTER (conv), TRUE);
885 : :
886 : 2 : in = g_memory_input_stream_new_from_data (test->text_in, -1, NULL);
887 : 2 : in2 = g_converter_input_stream_new (in, conv);
888 : :
889 : 2 : count = 2 * strlen (test->text_out);
890 : 2 : buffer = g_malloc0 (count);
891 : 2 : error = NULL;
892 : 2 : g_input_stream_read_all (in2, buffer, count, &bytes_read, NULL, &error);
893 : 2 : g_assert_no_error (error);
894 : 2 : g_assert_cmpstr (buffer, ==, test->text_out);
895 : 2 : g_assert_cmpint (bytes_read, ==, strlen (test->text_out));
896 : 2 : g_assert_cmpint (test->n_fallbacks, ==, g_charset_converter_get_num_fallbacks (G_CHARSET_CONVERTER (conv)));
897 : :
898 : 2 : g_free (buffer);
899 : 2 : g_object_unref (in2);
900 : 2 : g_object_unref (in);
901 : :
902 : 2 : g_object_unref (conv);
903 : 3 : }
904 : :
905 : :
906 : : static void
907 : 2 : client_connected (GObject *source,
908 : : GAsyncResult *result,
909 : : gpointer user_data)
910 : : {
911 : 2 : GSocketClient *client = G_SOCKET_CLIENT (source);
912 : 2 : GSocketConnection **conn = user_data;
913 : 2 : GError *error = NULL;
914 : :
915 : 2 : *conn = g_socket_client_connect_finish (client, result, &error);
916 : 2 : g_assert_no_error (error);
917 : 2 : }
918 : :
919 : : static void
920 : 2 : server_connected (GObject *source,
921 : : GAsyncResult *result,
922 : : gpointer user_data)
923 : : {
924 : 2 : GSocketListener *listener = G_SOCKET_LISTENER (source);
925 : 2 : GSocketConnection **conn = user_data;
926 : 2 : GError *error = NULL;
927 : :
928 : 2 : *conn = g_socket_listener_accept_finish (listener, result, NULL, &error);
929 : 2 : g_assert_no_error (error);
930 : 2 : }
931 : :
932 : : static void
933 : 2 : make_socketpair (GIOStream **left,
934 : : GIOStream **right)
935 : : {
936 : : GInetAddress *iaddr;
937 : : GSocketAddress *saddr, *effective_address;
938 : : GSocketListener *listener;
939 : : GSocketClient *client;
940 : 2 : GError *error = NULL;
941 : 2 : GSocketConnection *client_conn = NULL, *server_conn = NULL;
942 : :
943 : 2 : iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
944 : 2 : saddr = g_inet_socket_address_new (iaddr, 0);
945 : 2 : g_object_unref (iaddr);
946 : :
947 : 2 : listener = g_socket_listener_new ();
948 : 2 : g_socket_listener_add_address (listener, saddr,
949 : : G_SOCKET_TYPE_STREAM,
950 : : G_SOCKET_PROTOCOL_TCP,
951 : : NULL,
952 : : &effective_address,
953 : : &error);
954 : 2 : g_assert_no_error (error);
955 : 2 : g_object_unref (saddr);
956 : :
957 : 2 : client = g_socket_client_new ();
958 : :
959 : 3 : g_socket_client_connect_async (client,
960 : 2 : G_SOCKET_CONNECTABLE (effective_address),
961 : : NULL, client_connected, &client_conn);
962 : 2 : g_socket_listener_accept_async (listener, NULL,
963 : : server_connected, &server_conn);
964 : :
965 : 8 : while (!client_conn || !server_conn)
966 : 6 : g_main_context_iteration (NULL, TRUE);
967 : :
968 : 2 : g_object_unref (client);
969 : 2 : g_object_unref (listener);
970 : 2 : g_object_unref (effective_address);
971 : :
972 : 2 : *left = G_IO_STREAM (client_conn);
973 : 2 : *right = G_IO_STREAM (server_conn);
974 : 2 : }
975 : :
976 : : static void
977 : 2 : test_converter_pollable (void)
978 : : {
979 : : GIOStream *left, *right;
980 : : guint8 *converted, *inptr;
981 : : guint8 *expanded, *outptr, *expanded_end;
982 : : gsize n_read, expanded_size;
983 : : gsize total_read;
984 : : gssize res;
985 : : gboolean is_readable;
986 : : GConverterResult cres;
987 : : GInputStream *cstream;
988 : : GPollableInputStream *pollable_in;
989 : : GOutputStream *socket_out, *mem_out, *cstream_out;
990 : : GPollableOutputStream *pollable_out;
991 : : GConverter *expander, *compressor;
992 : : GError *error;
993 : : gsize i;
994 : :
995 : 2 : expander = g_expander_converter_new ();
996 : 2 : expanded = g_malloc (100*1000); /* Large enough */
997 : 3 : cres = g_converter_convert (expander,
998 : : unexpanded_data, sizeof(unexpanded_data),
999 : 1 : expanded, 100*1000,
1000 : : G_CONVERTER_INPUT_AT_END,
1001 : : &n_read, &expanded_size, NULL);
1002 : 2 : g_assert_cmpint (cres, ==, G_CONVERTER_FINISHED);
1003 : 2 : g_assert_cmpuint (n_read, ==, 11);
1004 : 2 : g_assert_cmpuint (expanded_size, ==, 41030);
1005 : 2 : expanded_end = expanded + expanded_size;
1006 : :
1007 : 2 : make_socketpair (&left, &right);
1008 : :
1009 : 2 : compressor = g_compressor_converter_new ();
1010 : :
1011 : 2 : converted = g_malloc (100*1000); /* Large enough */
1012 : :
1013 : 3 : cstream = g_converter_input_stream_new (g_io_stream_get_input_stream (left),
1014 : 1 : compressor);
1015 : 2 : pollable_in = G_POLLABLE_INPUT_STREAM (cstream);
1016 : 2 : g_assert_true (g_pollable_input_stream_can_poll (pollable_in));
1017 : :
1018 : 2 : socket_out = g_io_stream_get_output_stream (right);
1019 : :
1020 : 2 : total_read = 0;
1021 : 2 : outptr = expanded;
1022 : 2 : inptr = converted;
1023 : 11 : while (TRUE)
1024 : : {
1025 : 88 : error = NULL;
1026 : :
1027 : 88 : if (outptr < expanded_end)
1028 : : {
1029 : 126 : res = g_output_stream_write (socket_out,
1030 : 42 : outptr,
1031 : 84 : MIN (1000, (expanded_end - outptr)),
1032 : : NULL, &error);
1033 : 84 : g_assert_cmpint (res, >, 0);
1034 : 84 : outptr += res;
1035 : 42 : }
1036 : 4 : else if (socket_out)
1037 : : {
1038 : 2 : g_output_stream_close (socket_out, NULL, NULL);
1039 : 2 : g_object_unref (right);
1040 : 2 : socket_out = NULL;
1041 : 1 : }
1042 : :
1043 : : /* Wait a few ticks to check for the pipe to propagate the
1044 : : * write. We can’t wait on a GSource as that might affect the stream under
1045 : : * test, so just poll. */
1046 : 88 : while (!g_pollable_input_stream_is_readable (pollable_in))
1047 : 0 : g_usleep (80L);
1048 : :
1049 : 88 : is_readable = g_pollable_input_stream_is_readable (pollable_in);
1050 : 132 : res = g_pollable_input_stream_read_nonblocking (pollable_in,
1051 : 44 : inptr, 1,
1052 : : NULL, &error);
1053 : :
1054 : : /* is_readable can be a false positive, but not a false negative */
1055 : 88 : if (!is_readable)
1056 : 0 : g_assert_cmpint (res, ==, -1);
1057 : :
1058 : : /* Even after closing the write end, we can get WOULD_BLOCK (particularly
1059 : : * on FreeBSD), so we can’t make any assertions based on `!socket_out`.
1060 : : * This is because the FIN packets may still be in the out buffer of one
1061 : : * half of the socket pair, while the in buffer of the other half has some
1062 : : * data, but not enough for a full block for the converter to consume. */
1063 : :
1064 : 88 : if (res == -1)
1065 : : {
1066 : 66 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
1067 : 66 : g_error_free (error);
1068 : :
1069 : 66 : continue;
1070 : : }
1071 : :
1072 : 22 : if (res == 0)
1073 : 2 : break;
1074 : 20 : inptr += res;
1075 : 20 : total_read += res;
1076 : : }
1077 : :
1078 : : /* "n_read - 1" because last 2 zeros are combined */
1079 : 3 : g_assert_cmpmem (unexpanded_data, n_read - 1, converted, total_read);
1080 : :
1081 : 2 : g_object_unref (cstream);
1082 : 2 : g_object_unref (left);
1083 : :
1084 : 2 : g_converter_reset (compressor);
1085 : :
1086 : : /* This doesn't actually test the behavior on
1087 : : * G_IO_ERROR_WOULD_BLOCK; to do that we'd need to implement a
1088 : : * custom GOutputStream that we could control blocking on.
1089 : : */
1090 : :
1091 : 2 : mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
1092 : 2 : cstream_out = g_converter_output_stream_new (mem_out, compressor);
1093 : 2 : g_object_unref (mem_out);
1094 : 2 : pollable_out = G_POLLABLE_OUTPUT_STREAM (cstream_out);
1095 : 2 : g_assert_true (g_pollable_output_stream_can_poll (pollable_out));
1096 : 2 : g_assert_true (g_pollable_output_stream_is_writable (pollable_out));
1097 : :
1098 : 82062 : for (i = 0; i < expanded_size; i++)
1099 : : {
1100 : 82060 : error = NULL;
1101 : 123090 : res = g_pollable_output_stream_write_nonblocking (pollable_out,
1102 : 82060 : expanded + i, 1,
1103 : : NULL, &error);
1104 : 82060 : g_assert_cmpint (res, !=, -1);
1105 : 82060 : if (res == 0)
1106 : : {
1107 : 0 : g_assert_cmpuint (i, ==, expanded_size -1);
1108 : 0 : break;
1109 : : }
1110 : 82060 : g_assert_cmpint (res, ==, 1);
1111 : 41030 : }
1112 : :
1113 : 2 : g_output_stream_close (cstream_out, NULL, NULL);
1114 : :
1115 : : /* "n_read - 1" because last 2 zeros are combined */
1116 : 3 : g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
1117 : 1 : g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)),
1118 : : unexpanded_data,
1119 : 1 : n_read - 1);
1120 : :
1121 : 2 : g_object_unref (cstream_out);
1122 : :
1123 : 2 : g_free (expanded);
1124 : 2 : g_free (converted);
1125 : 2 : g_object_unref (expander);
1126 : 2 : g_object_unref (compressor);
1127 : 2 : }
1128 : :
1129 : : static void
1130 : 6 : test_truncation (gconstpointer data)
1131 : : {
1132 : 6 : const CompressorTest *test = data;
1133 : 6 : GError *error = NULL;
1134 : : guint32 *data0, *data1;
1135 : : gsize data1_size;
1136 : : gint i;
1137 : : GInputStream *istream0, *istream1, *cistream1;
1138 : : GOutputStream *ostream1, *ostream2, *costream1;
1139 : : GConverter *compressor, *decompressor;
1140 : :
1141 : 6 : data0 = g_malloc (DATA_LENGTH * sizeof (guint32));
1142 : 6000006 : for (i = 0; i < DATA_LENGTH; i++)
1143 : 6000000 : data0[i] = g_random_int ();
1144 : :
1145 : 6 : istream0 = g_memory_input_stream_new_from_data (data0,
1146 : : DATA_LENGTH * sizeof (guint32), NULL);
1147 : :
1148 : 6 : ostream1 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
1149 : 6 : compressor = G_CONVERTER (g_zlib_compressor_new (test->format, -1));
1150 : 6 : costream1 = g_converter_output_stream_new (ostream1, compressor);
1151 : 6 : g_assert_true (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor);
1152 : :
1153 : 6 : g_output_stream_splice (costream1, istream0, 0, NULL, &error);
1154 : 6 : g_assert_no_error (error);
1155 : :
1156 : 6 : g_object_unref (costream1);
1157 : 6 : g_object_unref (compressor);
1158 : :
1159 : 6 : data1 = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (ostream1));
1160 : 6 : data1_size = g_memory_output_stream_get_data_size (
1161 : 6 : G_MEMORY_OUTPUT_STREAM (ostream1));
1162 : 6 : g_object_unref (ostream1);
1163 : 6 : g_object_unref (istream0);
1164 : :
1165 : : /* truncate */
1166 : 6 : data1_size /= 2;
1167 : :
1168 : 6 : istream1 = g_memory_input_stream_new_from_data (data1, data1_size, g_free);
1169 : 6 : decompressor = G_CONVERTER (g_zlib_decompressor_new (test->format));
1170 : 6 : cistream1 = g_converter_input_stream_new (istream1, decompressor);
1171 : :
1172 : 6 : ostream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
1173 : :
1174 : 6 : g_output_stream_splice (ostream2, cistream1, 0, NULL, &error);
1175 : 6 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT);
1176 : 6 : g_error_free (error);
1177 : :
1178 : 6 : g_object_unref (istream1);
1179 : 6 : g_object_unref (decompressor);
1180 : 6 : g_object_unref (cistream1);
1181 : 6 : g_object_unref (ostream2);
1182 : 6 : g_free (data0);
1183 : 6 : }
1184 : :
1185 : : static void
1186 : 2 : test_converter_basics (void)
1187 : : {
1188 : : GConverter *converter;
1189 : 2 : GError *error = NULL;
1190 : : gchar *to;
1191 : : gchar *from;
1192 : :
1193 : 2 : converter = (GConverter *)g_charset_converter_new ("utf-8", "latin1", &error);
1194 : 2 : g_assert_no_error (error);
1195 : 2 : g_object_get (converter,
1196 : : "to-charset", &to,
1197 : : "from-charset", &from,
1198 : : NULL);
1199 : :
1200 : 2 : g_assert_cmpstr (to, ==, "utf-8");
1201 : 2 : g_assert_cmpstr (from, ==, "latin1");
1202 : :
1203 : 2 : g_free (to);
1204 : 2 : g_free (from);
1205 : 2 : g_object_unref (converter);
1206 : 2 : }
1207 : :
1208 : : int
1209 : 2 : main (int argc,
1210 : : char *argv[])
1211 : : {
1212 : 2 : CompressorTest compressor_tests[] = {
1213 : : { "/converter-output-stream/roundtrip/zlib-0", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 0 },
1214 : : { "/converter-output-stream/roundtrip/zlib-9", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 9 },
1215 : : { "/converter-output-stream/roundtrip/gzip-0", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 0 },
1216 : : { "/converter-output-stream/roundtrip/gzip-9", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 9 },
1217 : : { "/converter-output-stream/roundtrip/raw-0", G_ZLIB_COMPRESSOR_FORMAT_RAW, 0 },
1218 : : { "/converter-output-stream/roundtrip/raw-9", G_ZLIB_COMPRESSOR_FORMAT_RAW, 9 },
1219 : : };
1220 : 2 : CompressorTest truncation_tests[] = {
1221 : : { "/converter-input-stream/truncation/zlib", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 0 },
1222 : : { "/converter-input-stream/truncation/gzip", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 0 },
1223 : : { "/converter-input-stream/truncation/raw", G_ZLIB_COMPRESSOR_FORMAT_RAW, 0 },
1224 : : };
1225 : 2 : CharsetTest charset_tests[] = {
1226 : : { "/converter-input-stream/charset/utf8->latin1", "UTF-8", "\303\205rr Sant\303\251", "ISO-8859-1", "\305rr Sant\351", 0 },
1227 : : { "/converter-input-stream/charset/latin1->utf8", "ISO-8859-1", "\305rr Sant\351", "UTF-8", "\303\205rr Sant\303\251", 0 },
1228 : : { "/converter-input-stream/charset/fallbacks", "UTF-8", "Some characters just don't fit into latin1: πא", "ISO-8859-1", "Some characters just don't fit into latin1: \\CF\\80\\D7\\90", 4 },
1229 : : };
1230 : :
1231 : : gsize i;
1232 : :
1233 : 2 : g_test_init (&argc, &argv, NULL);
1234 : :
1235 : 2 : g_test_add_func ("/converter/basics", test_converter_basics);
1236 : 2 : g_test_add_func ("/converter-input-stream/expander", test_expander);
1237 : 2 : g_test_add_func ("/converter-input-stream/compressor", test_compressor);
1238 : :
1239 : 14 : for (i = 0; i < G_N_ELEMENTS (compressor_tests); i++)
1240 : 12 : g_test_add_data_func (compressor_tests[i].path, &compressor_tests[i], test_roundtrip);
1241 : :
1242 : 8 : for (i = 0; i < G_N_ELEMENTS (truncation_tests); i++)
1243 : 6 : g_test_add_data_func (truncation_tests[i].path, &truncation_tests[i], test_truncation);
1244 : :
1245 : 8 : for (i = 0; i < G_N_ELEMENTS (charset_tests); i++)
1246 : 6 : g_test_add_data_func (charset_tests[i].path, &charset_tests[i], test_charset);
1247 : :
1248 : 2 : g_test_add_func ("/converter-stream/pollable", test_converter_pollable);
1249 : 2 : g_test_add_func ("/converter-stream/leftover", test_converter_leftover);
1250 : :
1251 : 2 : return g_test_run();
1252 : : }
|