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