"Initial commit to Gerrit"
[profile/ivi/libgsf.git] / gsf / gsf-utils.c
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * gsf-utils.c: 
4  *
5  * Copyright (C) 2002-2006 Jody Goldberg (jody@gnome.org)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 2.1 of the GNU Lesser General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program 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.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
19  * USA
20  */
21
22 #include <gsf-config.h>
23 #include <gsf/gsf-utils.h>
24 #include <gsf/gsf-input.h>
25 #include <gsf/gsf-doc-meta-data.h>
26 #include <gsf/gsf-docprop-vector.h>
27 #include <gsf/gsf-impl-utils.h>
28
29 #include <gsf/gsf-infile.h>
30 #include <gsf/gsf-infile-msole.h>
31 #include <gsf/gsf-infile-msvba.h>
32 #include <gsf/gsf-infile-stdio.h>
33 #include <gsf/gsf-infile-zip.h>
34
35 #include <gsf/gsf-input.h>
36 #include <gsf/gsf-input-gzip.h>
37 #include <gsf/gsf-input-http.h>
38 #include <gsf/gsf-input-memory.h>
39 #include <gsf/gsf-input-proxy.h>
40 #include <gsf/gsf-input-stdio.h>
41 #include <gsf/gsf-input-textline.h>
42
43 #include <gsf/gsf-output.h>
44 #include <gsf/gsf-output-bzip.h>
45 #include <gsf/gsf-output-csv.h>
46 #include <gsf/gsf-output-gzip.h>
47 #include <gsf/gsf-output-iconv.h>
48 #include <gsf/gsf-output-iochannel.h>
49 #include <gsf/gsf-output-memory.h>
50 #include <gsf/gsf-output-stdio.h>
51
52 #include <gsf/gsf-outfile.h>
53 #include <gsf/gsf-outfile-msole.h>
54 #include <gsf/gsf-outfile-stdio.h>
55 #include <gsf/gsf-outfile-zip.h>
56
57 #include <gsf/gsf-libxml.h>
58 #include <gsf/gsf-blob.h>
59 #include <gsf/gsf-structured-blob.h>
60 #include <gsf/gsf-shared-memory.h>
61 #include <gsf/gsf-clip-data.h>
62 #include <gsf/gsf-open-pkg-utils.h>
63
64 #include <gobject/gvaluecollector.h>
65 #include <glib/gi18n-lib.h>
66
67 #include <ctype.h>
68 #include <stdio.h>
69 #include <string.h>
70
71 /*
72  * Glib gets this wrong, really.  ARM's floating point format is a weird
73  * mixture.
74  */
75 #define G_ARMFLOAT_ENDIAN 56781234
76 #if defined(__arm__) && !defined(__ARM_EABI__) && (G_BYTE_ORDER == G_LITTLE_ENDIAN)
77 #define G_FLOAT_BYTE_ORDER G_ARMFLOAT_ENDIAN
78 #else
79 #define G_FLOAT_BYTE_ORDER G_BYTE_ORDER
80 #endif
81
82 gboolean
83 gsf_debug_flag (const char *flag)
84 {
85         GDebugKey key;
86         key.key = (char *)flag;
87         key.value = 1;
88
89         return g_parse_debug_string (g_getenv ("GSF_DEBUG"), &key, 1) != 0;
90 }
91
92
93 #ifndef HAVE_G_BASE64_ENCODE
94 static void base64_init (void);
95 #endif
96
97 #ifdef _GSF_GTYPE_THREADING_FIXED
98 typedef GTypeModule      GsfDummyTypeModule;
99 typedef GTypeModuleClass GsfDummyTypeModuleClass;
100 static gboolean
101 gsf_dummy_type_module_load (GTypeModule *module)
102 {
103         gsf_init_dynamic (module);
104         return TRUE;
105 }
106 static void
107 gsf_dummy_type_module_class_init (GTypeModuleClass *gtm_class)
108 {
109         gtm_class->load = gsf_dummy_type_module_load;
110 }
111 static GSF_CLASS (GsfDummyTypeModule, gsf_dummy_type_module,
112                   gsf_dummy_type_module_class_init, NULL,
113                   G_TYPE_TYPE_MODULE)
114
115 static GTypeModule *static_type_module = NULL;
116 #endif
117
118 #ifdef G_OS_WIN32
119 #include <windows.h>
120 static HMODULE gsf_dll_hmodule;
121 BOOL WINAPI
122 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
123 BOOL WINAPI
124 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, G_GNUC_UNUSED LPVOID lpvReserved)
125 {
126         if (fdwReason == DLL_PROCESS_ATTACH) gsf_dll_hmodule = hinstDLL;
127         return TRUE;
128 }
129 #endif
130
131 /**
132  * gsf_init :
133  *
134  * Initializes the GSF library
135  **/
136 void
137 gsf_init (void)
138 {
139         static gboolean libgsf_initialized = FALSE;
140         if (libgsf_initialized)
141                 return;
142
143 #ifdef ENABLE_NLS
144 #ifdef G_OS_WIN32
145         {
146                 char *pkg_dir     = g_win32_get_package_installation_directory_of_module (gsf_dll_hmodule);
147                 gchar *locale_dir = g_build_filename (pkg_dir, "lib/locale", NULL);
148                 bindtextdomain (GETTEXT_PACKAGE, locale_dir);
149                 g_free (locale_dir);
150                 g_free (pkg_dir);
151         }
152 #else
153         bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
154 #endif
155         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
156 #endif
157
158         g_type_init ();
159 #ifndef HAVE_G_BASE64_ENCODE
160         base64_init ();
161 #endif
162
163 #ifdef _GSF_GTYPE_THREADING_FIXED
164         if (NULL == static_type_module) {
165                 static_type_module = g_object_new (gsf_dummy_type_module_get_type(), NULL);
166                 g_assert (static_type_module != NULL);
167                 g_type_module_use (static_type_module);
168                 g_type_module_set_name (static_type_module, "libgsf-builtin");
169         }
170 #else
171         gsf_init_dynamic (NULL);
172 #endif
173
174         {
175                 /* Little-endian representation of M_PI.  */
176                 static guint8 pibytes[8] = {
177                         0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40
178                 };
179
180                 /*
181                  * If this fails, see
182                  *   http://bugzilla.gnome.org/show_bug.cgi?id=350973
183                  */
184                 double pi = gsf_le_get_double (pibytes);
185                 if (!(pi > 3.14 && pi < 3.15))
186                         g_error ("Compilation trouble with endianess.");
187         }
188 }
189
190 /**
191  * gsf_shutdown:
192  * 
193  * De-intializes the GSF library
194  * Currently does nothing.
195  **/
196 void
197 gsf_shutdown (void)
198 {
199 }
200
201 #ifdef _GSF_GTYPE_THREADING_FIXED
202 #define REGISTER(prefix)                                                \
203         do {                                                            \
204                 prefix ## _register_type (module);                      \
205                 types = g_slist_prepend (types,                         \
206                         g_type_class_ref (prefix ## _get_type()));      \
207         } while (0)
208 #else
209 /* Assign the value to avoid compiler warnings */
210 #define REGISTER(prefix)        t = prefix ## _get_type()
211 #endif
212
213 /**
214  * gsf_init_dynamic :
215  * @module : #GTypeModule.
216  *
217  * Initializes the GSF library and associates it with a type module @mod.
218  **/
219 void
220 gsf_init_dynamic (GTypeModule *module)
221 {
222 #ifndef _GSF_GTYPE_THREADING_FIXED
223         GType t;
224         if (NULL != module) {
225                 g_warning ("glib's support of dynamic types is not thread safe.\n"
226                            "Support for gsf_init_dynamic has been disabled until that is fixed");
227         }
228 #endif
229         REGISTER (gsf_input);
230         REGISTER (gsf_input_gzip);
231         REGISTER (gsf_input_http);
232         REGISTER (gsf_input_memory);
233         REGISTER (gsf_input_proxy);
234         REGISTER (gsf_input_stdio);
235         REGISTER (gsf_input_textline);
236
237         REGISTER (gsf_infile);
238         REGISTER (gsf_infile_msole);
239         REGISTER (gsf_infile_msvba);
240         REGISTER (gsf_infile_stdio);
241         REGISTER (gsf_infile_zip);
242
243         REGISTER (gsf_output);
244         REGISTER (gsf_output_bzip);
245         REGISTER (gsf_output_csv_quoting_mode);
246         REGISTER (gsf_output_csv);
247         REGISTER (gsf_output_gzip);
248         REGISTER (gsf_output_iconv);
249         REGISTER (gsf_output_iochannel);
250         REGISTER (gsf_output_memory);
251         REGISTER (gsf_output_stdio);
252
253         REGISTER (gsf_outfile);
254         REGISTER (gsf_outfile_msole);
255         REGISTER (gsf_outfile_stdio);
256         REGISTER (gsf_outfile_zip);
257         REGISTER (gsf_outfile_open_pkg);
258
259         REGISTER (gsf_shared_memory);
260         REGISTER (gsf_structured_blob);
261         REGISTER (gsf_xml_out);
262         REGISTER (gsf_blob);
263         REGISTER (gsf_clip_data);
264         REGISTER (gsf_doc_meta_data);
265         REGISTER (gsf_docprop_vector);
266 }
267
268 /**
269  * gsf_shutdown:
270  * 
271  * De-intializes the GSF library from a type module.
272  * Currently does nothing.
273  **/
274 void
275 gsf_shutdown_dynamic (G_GNUC_UNUSED GTypeModule *module)
276 {
277 }
278
279 static void
280 gsf_mem_dump_full (guint8 const *ptr, size_t len, gsf_off_t offset)
281 {
282         static const char hexdigit[16] = "0123456789abcdef";
283
284         while (len > 0) {
285                 char hexpart[3 * 16 + 1], *phex = hexpart;
286                 char pic[17];
287                 size_t j;
288                 for (j = 0; j < 16; j++) {
289                         if (len > 0) {
290                                 *phex++ = hexdigit[*ptr >> 4];
291                                 *phex++ = hexdigit[*ptr & 0xf];
292                                 pic[j] = (*ptr >= '!' && *ptr < 127 ? *ptr : '.');
293                                 len--;
294                                 ptr++;
295                         } else {
296                                 *phex++ = 'X';
297                                 *phex++ = 'X';
298                                 pic[j] = '*';
299                         }
300                         *phex++ = ' ';
301                 }
302                 hexpart[3 * 16] = 0;
303                 pic[16] = 0 ;
304
305                 g_print ("%8lx | %s| %s\n", (long)offset, hexpart, pic);
306                 offset += 16;
307         }
308 }
309
310 /**
311  * gsf_mem_dump :
312  * @ptr: memory area to be dumped.
313  * @len: how many bytes will be dumped.
314  *
315  * Dump @len bytes from the memory location given by @ptr.
316  **/
317 void
318 gsf_mem_dump (guint8 const *ptr, size_t len)
319 {
320         gsf_mem_dump_full (ptr, len, 0);
321 }
322
323 /**
324  * gsf_input_dump :
325  * @input: a #GsfInput
326  * @dump_as_hex: If %TRUE, dump in hexidecmal format
327  *
328  * Dumps @input's contents to STDOUT, optionally in hex format.
329  */
330 void
331 gsf_input_dump (GsfInput *input, gboolean dump_as_hex)
332 {
333         gsf_off_t offset = 0;
334         size_t size, count;
335         guint8 const *data;
336
337         /* read in small blocks to excercise things */
338         size = gsf_input_size (GSF_INPUT (input));
339         while (size > 0) {
340                 count = size;
341                 if (count > 0x100)
342                         count = 0x100;
343                 data = gsf_input_read (GSF_INPUT (input), count, NULL);
344                 g_return_if_fail (data != NULL);
345                 if (dump_as_hex)
346                         gsf_mem_dump_full (data, count, offset);
347                 else
348                         fwrite (data, 1, count, stdout);
349                 size -= count;
350                 offset += count;
351         }
352         if (!dump_as_hex)
353                 fflush (stdout);
354 }
355
356 /**
357  * gsf_le_get_guint64
358  * @p: pointer to storage
359  *
360  * Interpret binary data as a guint64 (8 byte unsigned integer type) in little
361  * endian order.
362  *
363  * Returns: interpreted data
364  */
365 guint64
366 gsf_le_get_guint64 (void const *p)
367 {
368 #if G_BYTE_ORDER == G_BIG_ENDIAN
369         if (sizeof (guint64) == 8) {
370                 guint64 li;
371                 int     i;
372                 guint8 *t  = (guint8 *)&li;
373                 guint8 *p2 = (guint8 *)p;
374                 int     sd = sizeof (li);
375
376                 for (i = 0; i < sd; i++)
377                         t[i] = p2[sd - 1 - i];
378
379                 return li;
380         } else {
381                 g_error ("Big endian machine, but weird size of guint64");
382         }
383 #elif G_BYTE_ORDER == G_LITTLE_ENDIAN
384         if (sizeof (guint64) == 8) {
385                 /*
386                  * On i86, we could access directly, but Alphas require
387                  * aligned access.
388                  */
389                 guint64 data;
390                 memcpy (&data, p, sizeof (data));
391                 return data;
392         } else {
393                 g_error ("Little endian machine, but weird size of guint64");
394         }
395 #else
396 #error "Byte order not recognised -- out of luck"
397 #endif
398 }
399
400 /**
401  * gsf_le_get_float :
402  * @p: pointer to storage
403  *
404  * Interpret binary data as a float in little endian order.
405  *
406  *
407  * Returns: interpreted data
408  */
409 float
410 gsf_le_get_float (void const *p)
411 {
412 #if G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
413         if (sizeof (float) == 4) {
414                 float   f;
415                 int     i;
416                 guint8 *t  = (guint8 *)&f;
417                 guint8 *p2 = (guint8 *)p;
418                 int     sd = sizeof (f);
419
420                 for (i = 0; i < sd; i++)
421                         t[i] = p2[sd - 1 - i];
422
423                 return f;
424         } else {
425                 g_error ("Big endian machine, but weird size of floats");
426         }
427 #elif (G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN) || (G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN)
428         if (sizeof (float) == 4) {
429                 /*
430                  * On i86, we could access directly, but Alphas require
431                  * aligned access.
432                  */
433                 float data;
434                 memcpy (&data, p, sizeof (data));
435                 return data;
436         } else {
437                 g_error ("Little endian machine, but weird size of floats");
438         }
439 #else
440 #error "Floating-point byte order not recognised -- out of luck"
441 #endif
442 }
443
444 /**
445  * gsf_le_set_float :
446  * @p: pointer to storage
447  * @f: float to be stored
448  *
449  * Store a value of type float in memory in little endian order.
450  */
451 void
452 gsf_le_set_float (void *p, float f)
453 {
454 #if G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
455         if (sizeof (float) == 4) {
456                 int     i;
457                 guint8 *t  = (guint8 *)&f;
458                 guint8 *p2 = (guint8 *)p;
459                 int     sd = sizeof (f);
460
461                 for (i = 0; i < sd; i++)
462                         p2[sd - 1 - i] = t[i];
463         } else {
464                 g_error ("Big endian machine, but weird size of floats");
465         }
466 #elif (G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN) || (G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN)
467         if (sizeof (float) == 4) {
468                 /*
469                  * On i86, we could access directly, but Alphas require
470                  * aligned access.
471                  */
472                 memcpy (p, &f, sizeof (f));
473         } else {
474                 g_error ("Little endian machine, but weird size of floats");
475         }
476 #else
477 #error "Floating-point byte order not recognised -- out of luck"
478 #endif
479 }
480
481 /**
482  * gsf_le_get_double :
483  * @p: pointer to storage
484  *
485  * Interpret binary data as a double in little endian order.
486  *
487  * Returns: interpreted data
488  */
489 double
490 gsf_le_get_double (void const *p)
491 {
492 #if G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN
493         double data;
494         memcpy ((char *)&data + 4, p, 4);
495         memcpy ((char *)&data, (char const *)p + 4, 4);
496         return data;
497 #elif G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
498         if (sizeof (double) == 8) {
499                 double  d;
500                 int     i;
501                 guint8 *t  = (guint8 *)&d;
502                 guint8 *p2 = (guint8 *)p;
503                 int     sd = sizeof (d);
504
505                 for (i = 0; i < sd; i++)
506                         t[i] = p2[sd - 1 - i];
507
508                 return d;
509         } else {
510                 g_error ("Big endian machine, but weird size of doubles");
511         }
512 #elif G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN
513         if (sizeof (double) == 8) {
514                 /*
515                  * On i86, we could access directly, but Alphas require
516                  * aligned access.
517                  */
518                 double data;
519                 memcpy (&data, p, sizeof (data));
520                 return data;
521         } else {
522                 g_error ("Little endian machine, but weird size of doubles");
523         }
524 #else
525 #error "Floating-point byte order not recognised -- out of luck"
526 #endif
527 }
528
529 /**
530  * gsf_le_set_double :
531  * @p: pointer to storage
532  * @d: double to be stored
533  *
534  * Store a value of type double in memory in little endian order
535  */
536 void
537 gsf_le_set_double (void *p, double d)
538 {
539 #if G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN
540         memcpy (p, (char const *)&d + 4, 4);
541         memcpy ((char *)p + 4, &d, 4);
542 #elif G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
543         if (sizeof (double) == 8) {
544                 int     i;
545                 guint8 *t  = (guint8 *)&d;
546                 guint8 *p2 = (guint8 *)p;
547                 int     sd = sizeof (d);
548
549                 for (i = 0; i < sd; i++)
550                         p2[sd - 1 - i] = t[i];
551         } else {
552                 g_error ("Big endian machine, but weird size of doubles");
553         }
554 #elif G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN
555         if (sizeof (double) == 8) {
556                 /*
557                  * On i86, we could access directly, but Alphas require
558                  * aligned access.
559                  */
560                 memcpy (p, &d, sizeof (d));
561         } else {
562                 g_error ("Little endian machine, but weird size of doubles");
563         }
564 #else
565 #error "Floating-point byte order not recognised -- out of luck"
566 #endif
567 }
568
569 /**
570  * gsf_extension_pointer:
571  * @path: A filename or file path.
572  *
573  * Extracts the extension from the end of a filename (the part after the final
574  * '.' in the filename).
575  *
576  * Returns: A pointer to the extension part of the filename, or a
577  * pointer to the end of the string if the filename does not
578  * have an extension.
579  */
580 char const *
581 gsf_extension_pointer (char const *path)
582 {
583         char const *s, *end;
584         
585         g_return_val_if_fail (path != NULL, NULL);
586
587         end = path + strlen (path);
588         for (s = end; s > path; ) {
589                 s--;
590                 if (G_IS_DIR_SEPARATOR (*s))
591                         break;
592                 if (*s == '.')
593                         return s + 1;
594         }
595
596         return end;
597 }
598
599 /**
600  * gsf_iconv_close :
601  * @handle : handle to be closed.
602  *
603  * A utility wrapper to safely close an iconv handle.
604  **/
605 void
606 gsf_iconv_close (GIConv handle)
607 {
608         if (handle != NULL && handle != ((GIConv)-1))
609                 g_iconv_close (handle);
610 }
611
612 /**
613  * gsf_filename_to_utf8:
614  * @filename: file name suitable for open(2).
615  * @quoted: if %TRUE, the resulting utf8 file name will be quoted
616  *    (unless it is invalid).
617  *
618  * A utility wrapper to make sure filenames are valid utf8.
619  * Caller must g_free the result.
620  *
621  * Returns: @filename using utf-8 encoding for display
622  **/
623 char *
624 gsf_filename_to_utf8 (char const *filename, gboolean quoted)
625 {
626         char *dname = g_filename_display_name (filename);
627         char *result;
628
629         if (quoted) {
630                 result = g_strconcat ("\"", dname, "\"", NULL);
631                 g_free (dname);
632         } else
633                 result = dname;
634
635         return result;
636 }
637
638 #ifndef HAVE_G_BASE64_ENCODE
639 /***************************************************************************/
640 /* some code taken from evolution/camel/camel-mime-utils.c */
641
642 /*
643  *  Copyright (C) 2000 Ximian Inc.
644  *
645  *  Authors: Michael Zucchi <notzed@ximian.com>
646  *           Jeffrey Stedfast <fejj@ximian.com>
647  *
648  * This program is free software; you can redistribute it and/or
649  * modify it under the terms of version 2 of the GNU Lesser General Public
650  * License as published by the Free Software Foundation.
651  *
652  * This program is distributed in the hope that it will be useful,
653  * but WITHOUT ANY WARRANTY; without even the implied warranty of
654  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
655  * General Public License for more details.
656  *
657  * You should have received a copy of the GNU General Public
658  * License along with this program; if not, write to the
659  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
660  * Boston, MA  02110-1301  USA
661  */
662
663 /* dont touch this file without my permission - Michael */
664 static guint8 camel_mime_base64_rank[256];
665 static char const *base64_alphabet =
666 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
667
668 #define d(x)
669
670 /* Line length for base64 encoding.  Must be a multiple of 4. */
671 enum { BASE64_LINE_LEN = 76 };
672
673 static void
674 base64_init(void)
675 {
676         int i;
677
678         memset(camel_mime_base64_rank, 0xff, sizeof(camel_mime_base64_rank));
679         for (i=0;i<64;i++) {
680                 camel_mime_base64_rank[(unsigned int)base64_alphabet[i]] = i;
681         }
682         camel_mime_base64_rank['='] = 0;
683 }
684 #endif
685
686 /**
687  * gsf_base64_encode_close :
688  * @in : Data to be encoded
689  * @inlen : Length of data to be encoded
690  * @break_lines : Whether to use line breaks
691  * @out : Encoded data.
692  * @state: holds the number of bits that are stored in @save
693  * @save: leftover bits that have not yet been decoded
694  *
695  * This funcion should be called to when finished encoding everything, to
696  * flush off the last little bit.
697  *
698  * Returns: a count of the number of bytes in the final block.
699  **/
700 size_t
701 gsf_base64_encode_close (guint8 const *in, size_t inlen,
702                          gboolean break_lines, guint8 *out, int *state, unsigned int *save)
703 {
704         guint8 *outptr = out;
705 #ifdef HAVE_G_BASE64_ENCODE
706         if (inlen > 0)
707                 outptr += gsf_base64_encode_step (in, inlen, break_lines,
708                                                   outptr, state, save);
709         outptr += g_base64_encode_close (break_lines, outptr, state, save);
710 #else
711         int c1, c2;
712
713         if (inlen>0)
714                 outptr += gsf_base64_encode_step(in, inlen, break_lines, outptr, state, save);
715
716         c1 = ((guint8 *)save)[1];
717         c2 = ((guint8 *)save)[2];
718         
719         d(printf("mode = %d\nc1 = %c\nc2 = %c\n",
720                  (int)((char *)save)[0],
721                  (int)((char *)save)[1],
722                  (int)((char *)save)[2]));
723
724         switch (((char *)save)[0]) {
725         case 2:
726                 outptr[2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
727                 g_assert(outptr[2] != 0);
728                 goto skip;
729         case 1:
730                 outptr[2] = '=';
731         skip:
732                 outptr[0] = base64_alphabet[ c1 >> 2 ];
733                 outptr[1] = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 )];
734                 outptr[3] = '=';
735                 outptr += 4;
736                 ++*state;
737                 break;
738         }
739         if (break_lines && *state > 0)
740                 *outptr++ = '\n';
741
742         *save = 0;
743         *state = 0;
744
745 #endif
746         return outptr-out;
747 }
748
749 /**
750  * gsf_base64_encode_step :
751  * @in : input stream
752  * @len : max length of data to decode
753  * @break_lines : Whether to use line breaks
754  * @out : output stream
755  * @state : holds the number of bits that are stored in @save
756  * @save : leftover bits that have not yet been decoded
757  *
758  * Performs an 'encode step', only encodes blocks of 3 characters from @in into
759  * the output @out at a time, saves left-over state in @state and @save
760  * (initialise to 0 on first invocation).
761  *
762  * Returns: the number of bytes encoded
763  */
764 size_t
765 gsf_base64_encode_step (guint8 const *in, size_t len,
766                         gboolean break_lines, guint8 *out, int *state, unsigned int *save)
767 {
768 #ifdef HAVE_G_BASE64_ENCODE
769         return g_base64_encode_step (in, len, break_lines, out, state, save);
770 #else
771         register guint8 const *inptr;
772         register guint8 *outptr;
773
774         if (len<=0)
775                 return 0;
776
777         inptr = in;
778         outptr = out;
779
780         d(printf("we have %d chars, and %d saved chars\n", len, ((char *)save)[0]));
781
782         if (len + ((char *)save)[0] > 2) {
783                 guint8 const *inend = in+len-2;
784                 register int c1, c2, c3;
785                 register int already;
786
787                 already = *state;
788
789                 switch (((char *)save)[0]) {
790                 case 1: c1 = ((guint8 *)save)[1]; goto skip1;
791                 case 2: c1 = ((guint8 *)save)[1];
792                         c2 = ((guint8 *)save)[2]; goto skip2;
793                 }
794                 
795                 /* yes, we jump into the loop, no i'm not going to change it, it's beautiful! */
796                 while (inptr < inend) {
797                         c1 = *inptr++;
798                 skip1:
799                         c2 = *inptr++;
800                 skip2:
801                         c3 = *inptr++;
802                         *outptr++ = base64_alphabet[ c1 >> 2 ];
803                         *outptr++ = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 ) ];
804                         *outptr++ = base64_alphabet[ ( (c2 &0x0f) << 2 ) | (c3 >> 6) ];
805                         *outptr++ = base64_alphabet[ c3 & 0x3f ];
806                         /* this is a bit ugly ... */
807                         if (break_lines && (++already) * 4 >= BASE64_LINE_LEN) {
808                                 *outptr++='\n';
809                                 already = 0;
810                         }
811                 }
812
813                 ((char *)save)[0] = 0;
814                 len = 2-(inptr-inend);
815                 *state = already;
816         }
817
818         d(printf("state = %d, len = %d\n",
819                  (int)((char *)save)[0],
820                  len));
821
822         if (len>0) {
823                 register char *saveout;
824
825                 /* points to the slot for the next char to save */
826                 saveout = & (((char *)save)[1]) + ((char *)save)[0];
827
828                 /* len can only be 0 1 or 2 */
829                 switch(len) {
830                 case 2: *saveout++ = *inptr++;
831                 case 1: *saveout++ = *inptr++;
832                 }
833                 ((char *)save)[0]+=len;
834         }
835
836         d(printf("mode = %d\nc1 = %c\nc2 = %c\n",
837                  (int)((char *)save)[0],
838                  (int)((char *)save)[1],
839                  (int)((char *)save)[2]));
840
841         return outptr-out;
842 #endif
843 }
844
845
846 /**
847  * gsf_base64_decode_step:
848  * @in: input stream
849  * @len: max length of data to decode
850  * @out: output stream
851  * @state: holds the number of bits that are stored in @save
852  * @save: leftover bits that have not yet been decoded
853  *
854  * Decodes a chunk of base64 encoded data
855  *
856  * Returns: the number of bytes converted
857  **/
858 size_t
859 gsf_base64_decode_step (guint8 const *in, size_t len, guint8 *out,
860                         int *state, guint *save)
861 {
862 #ifdef HAVE_G_BASE64_ENCODE
863         return g_base64_decode_step (in, len, out, state, save);
864 #else
865         register guint8 const *inptr;
866         register guint8 *outptr, c;
867         register unsigned int v;
868         guint8 const *inend;
869         int i;
870
871         inend = in+len;
872         outptr = out;
873
874         /* convert 4 base64 bytes to 3 normal bytes */
875         v=*save;
876         i=*state;
877         inptr = in;
878         while (inptr<inend) {
879                 c = camel_mime_base64_rank[*inptr++];
880                 if (c != 0xff) {
881                         v = (v<<6) | c;
882                         i++;
883                         if (i==4) {
884                                 *outptr++ = v>>16;
885                                 *outptr++ = v>>8;
886                                 *outptr++ = v;
887                                 i=0;
888                         }
889                 }
890         }
891
892         *save = v;
893         *state = i;
894
895         /* quick scan back for '=' on the end somewhere */
896         /* fortunately we can drop 1 output char for each trailing = (upto 2) */
897         i=2;
898         while (inptr>in && i) {
899                 inptr--;
900                 if (camel_mime_base64_rank[*inptr] != 0xff) {
901                         if (*inptr == '=' && outptr>out)
902                                 outptr--;
903                         i--;
904                 }
905         }
906
907         /* if i!= 0 then there is a truncation error! */
908         return outptr-out;
909 #endif
910 }
911
912 /**
913  * gsf_base64_encode_simple :
914  * @data : data stream
915  * @len : max length of data to encode
916  *
917  * Encodes data from @data back into @data using base64 encoding.
918  *
919  * Returns: the number of bytes encoded
920  */
921 guint8 *
922 gsf_base64_encode_simple (guint8 const *data, size_t len)
923 {
924         guint8 *out;
925         int state = 0;
926         guint save = 0;
927         gboolean break_lines = TRUE;  /* This differs from g_base64_encode */
928         size_t outlen = len * 4 / 3 + 5;
929
930         if (break_lines)
931                 outlen += outlen / 72 + 1;
932         out = g_new (guint8, outlen);
933         outlen = gsf_base64_encode_close (data, len, break_lines,
934                                           out, &state, &save);
935         out[outlen] = '\0';
936         return out;
937 }
938
939 /**
940  * gsf_base64_decode_simple :
941  * @data : data stream
942  * @len : max length of data to decode
943  *
944  * Decodes a chunk of base64 encoded data from @data back into @data.
945  *
946  * Returns: the number of bytes converted
947  */
948 size_t
949 gsf_base64_decode_simple (guint8 *data, size_t len)
950 {
951         int state = 0;
952         guint save = 0;
953         return gsf_base64_decode_step (data, len, data, &state, &save);
954 }
955
956
957 /* Largely a copy of g_object_new_valist.  */
958 /**
959  * gsf_property_settings_collect_valist:
960  * @object_type: the GType for which the properties are being set.
961  * @p_n_params: a pointer to the number of properties collected.  (Used for
962  *   both input and output.)
963  * @p_params: a pointer to the GParameter array that holds the properties.
964  *   (Used for both input and output.  This may point to a %NULL pointer if
965  *   there are no properties collected yet.)
966  * @first_property_name: the name of the first property being set, or NULL.
967  * @var_args: a va_list holding the remainder of the property names and
968  *   values, terminated by a %NULL.
969  *
970  * This function builds a GParameter array suitable for g_object_newv.
971  **/
972 void
973 gsf_property_settings_collect_valist (GType object_type,
974                                       GParameter **p_params,
975                                       size_t *p_n_params,
976                                       const gchar *first_property_name,
977                                       va_list var_args)
978 {
979   GObjectClass *class;
980   GParameter *params = *p_params;
981   const gchar *name;
982   size_t n_params = *p_n_params;
983   size_t n_alloced_params = n_params;  /* We might have more.  */
984
985   g_return_if_fail (G_TYPE_IS_OBJECT (object_type));
986
987   class = g_type_class_ref (object_type);
988
989   name = first_property_name;
990   while (name)
991     {
992       gchar *error = NULL;
993       GParamSpec *pspec = g_object_class_find_property (class, name);
994       if (!pspec)
995         {
996           g_warning ("%s: object class `%s' has no property named `%s'",
997                      G_STRFUNC,
998                      g_type_name (object_type),
999                      name);
1000           break;
1001         }
1002
1003       if (n_params >= n_alloced_params)
1004         {
1005           n_alloced_params += 16;
1006           params = g_renew (GParameter, params, n_alloced_params);
1007         }
1008       params[n_params].name = name;
1009       params[n_params].value.g_type = 0;
1010       g_value_init (&params[n_params].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1011       G_VALUE_COLLECT (&params[n_params].value, var_args, 0, &error);
1012       if (error)
1013         {
1014           g_warning ("%s: %s", G_STRFUNC, error);
1015           g_free (error);
1016           g_value_unset (&params[n_params].value);
1017           break;
1018         }
1019       n_params++;
1020       name = va_arg (var_args, gchar*);
1021     }
1022
1023   g_type_class_unref (class);
1024
1025   *p_params = params;
1026   *p_n_params = n_params;
1027 }
1028
1029 /* This is a vararg version of gsf_property_settings_collect_valist.  */
1030 void
1031 gsf_property_settings_collect (GType object_type,
1032                                GParameter **p_params,
1033                                size_t *p_n_params,
1034                                const gchar *first_property_name,
1035                                ...)
1036 {
1037   va_list var_args;
1038   va_start (var_args, first_property_name);
1039   gsf_property_settings_collect_valist (object_type, p_params, p_n_params, first_property_name, var_args);
1040   va_end (var_args);
1041 }
1042
1043 void
1044 gsf_property_settings_free (GParameter *params,
1045                             size_t n_params)
1046 {
1047         while (n_params--)
1048                 g_value_unset (&params[n_params].value);
1049         g_free (params);
1050 }
1051
1052 \f
1053
1054 /* Errors */
1055
1056 /**
1057  * gsf_error_quark:
1058  *
1059  * Returns:  the #GQuark used to identify libgsf errors in #GError structures.
1060  *      Specific error codes come from the #GsfError enumeration.
1061  **/
1062 GQuark
1063 gsf_error_quark (void)
1064 {
1065         static GQuark quark;
1066
1067         if (quark == 0)
1068                 quark = g_quark_from_static_string ("gsf-error-quark");
1069
1070         return quark;
1071 }