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.h>
25
26 #include <gobject/gvaluecollector.h>
27 #include <glib/gi18n-lib.h>
28
29 #include <ctype.h>
30 #include <string.h>
31
32 /*
33 * Glib gets this wrong, really. ARM's floating point format is a weird
34 * mixture.
35 */
36 #define G_ARMFLOAT_ENDIAN 56781234
37 #if defined(__arm__) && !defined(__ARM_EABI__) && (G_BYTE_ORDER == G_LITTLE_ENDIAN)
38 #define G_FLOAT_BYTE_ORDER G_ARMFLOAT_ENDIAN
39 #else
40 #define G_FLOAT_BYTE_ORDER G_BYTE_ORDER
41 #endif
42
43 gboolean
gsf_debug_flag(const char * flag)44 gsf_debug_flag (const char *flag)
45 {
46 GDebugKey key;
47 key.key = (char *)flag;
48 key.value = 1;
49
50 return g_parse_debug_string (g_getenv ("GSF_DEBUG"), &key, 1) != 0;
51 }
52
53
54 #ifdef _GSF_GTYPE_THREADING_FIXED
55 typedef GTypeModule GsfDummyTypeModule;
56 typedef GTypeModuleClass GsfDummyTypeModuleClass;
57 static gboolean
gsf_dummy_type_module_load(GTypeModule * module)58 gsf_dummy_type_module_load (GTypeModule *module)
59 {
60 gsf_init_dynamic (module);
61 return TRUE;
62 }
63 static void
gsf_dummy_type_module_class_init(GTypeModuleClass * gtm_class)64 gsf_dummy_type_module_class_init (GTypeModuleClass *gtm_class)
65 {
66 gtm_class->load = gsf_dummy_type_module_load;
67 }
68 static GSF_CLASS (GsfDummyTypeModule, gsf_dummy_type_module,
69 gsf_dummy_type_module_class_init, NULL,
70 G_TYPE_TYPE_MODULE)
71
72 static GTypeModule *static_type_module = NULL;
73 #endif
74
75 #ifdef G_OS_WIN32
76 #include <windows.h>
77 static HMODULE gsf_dll_hmodule;
78 BOOL WINAPI
79 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
80 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,G_GNUC_UNUSED LPVOID lpvReserved)81 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, G_GNUC_UNUSED LPVOID lpvReserved)
82 {
83 if (fdwReason == DLL_PROCESS_ATTACH) gsf_dll_hmodule = hinstDLL;
84 return TRUE;
85 }
86 #endif
87
88 /**
89 * gsf_init:
90 *
91 * Initializes the GSF library
92 **/
93 void
gsf_init(void)94 gsf_init (void)
95 {
96 static gboolean libgsf_initialized = FALSE;
97 if (libgsf_initialized)
98 return;
99
100 #ifdef ENABLE_NLS
101 #ifdef G_OS_WIN32
102 {
103 char *pkg_dir = g_win32_get_package_installation_directory_of_module (gsf_dll_hmodule);
104 gchar *locale_dir = g_build_filename (pkg_dir, "lib/locale", NULL);
105 bindtextdomain (GETTEXT_PACKAGE, locale_dir);
106 g_free (locale_dir);
107 g_free (pkg_dir);
108 }
109 #else
110 bindtextdomain (GETTEXT_PACKAGE, GSFLOCALEDIR);
111 #endif
112 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
113 #endif
114
115 #ifdef _GSF_GTYPE_THREADING_FIXED
116 if (NULL == static_type_module) {
117 static_type_module = g_object_new (gsf_dummy_type_module_get_type(), NULL);
118 g_assert (static_type_module != NULL);
119 g_type_module_use (static_type_module);
120 g_type_module_set_name (static_type_module, "libgsf-builtin");
121 }
122 #else
123 gsf_init_dynamic (NULL);
124 #endif
125
126 {
127 /* Little-endian representation of M_PI. */
128 static const guint8 pibytes[8] = {
129 0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40
130 };
131
132 /*
133 * If this fails, see
134 * http://bugzilla.gnome.org/show_bug.cgi?id=350973
135 */
136 double pi = gsf_le_get_double (pibytes);
137 if (!(pi > 3.14 && pi < 3.15))
138 g_error ("Compilation trouble with endianess.");
139 }
140 }
141
142 /**
143 * gsf_shutdown:
144 *
145 * De-intializes the GSF library
146 * Currently does nothing.
147 **/
148 void
gsf_shutdown(void)149 gsf_shutdown (void)
150 {
151 }
152
153 #ifdef _GSF_GTYPE_THREADING_FIXED
154 #define REGISTER(prefix) \
155 do { \
156 prefix ## _register_type (module); \
157 types = g_slist_prepend (types, \
158 g_type_class_ref (prefix ## _get_type())); \
159 } while (0)
160 #else
161 /* Assign the value to avoid compiler warnings */
162 #define REGISTER(prefix) g_type_ensure (prefix ## _get_type())
163 #endif
164
165 /**
166 * gsf_init_dynamic:
167 * @module: #GTypeModule.
168 *
169 * Initializes the GSF library and associates it with a type module @mod.
170 **/
171 void
gsf_init_dynamic(GTypeModule * module)172 gsf_init_dynamic (GTypeModule *module)
173 {
174 #ifndef _GSF_GTYPE_THREADING_FIXED
175 if (NULL != module) {
176 g_warning ("glib's support of dynamic types is not thread safe.\n"
177 "Support for gsf_init_dynamic has been disabled until that is fixed");
178 }
179 #endif
180 REGISTER (gsf_input);
181 /* REGISTER (gsf_input_bzip); */
182 REGISTER (gsf_input_gzip);
183 REGISTER (gsf_input_http);
184 /* REGISTER (gsf_input_iochannel); */
185 REGISTER (gsf_input_memory);
186 REGISTER (gsf_input_proxy);
187 REGISTER (gsf_input_stdio);
188 REGISTER (gsf_input_textline);
189
190 REGISTER (gsf_infile);
191 REGISTER (gsf_infile_msole);
192 REGISTER (gsf_infile_msvba);
193 REGISTER (gsf_infile_stdio);
194 REGISTER (gsf_infile_tar);
195 REGISTER (gsf_infile_zip);
196
197 REGISTER (gsf_output);
198 REGISTER (gsf_output_bzip);
199 REGISTER (gsf_output_csv_quoting_mode);
200 REGISTER (gsf_output_csv);
201 REGISTER (gsf_output_gzip);
202 REGISTER (gsf_output_iconv);
203 REGISTER (gsf_output_iochannel);
204 REGISTER (gsf_output_memory);
205 REGISTER (gsf_output_stdio);
206
207 REGISTER (gsf_outfile);
208 REGISTER (gsf_outfile_msole);
209 REGISTER (gsf_outfile_stdio);
210 REGISTER (gsf_outfile_zip);
211 REGISTER (gsf_outfile_open_pkg);
212
213 REGISTER (gsf_shared_memory);
214 REGISTER (gsf_structured_blob);
215 REGISTER (gsf_xml_out);
216 REGISTER (gsf_blob);
217 REGISTER (gsf_clip_data);
218 REGISTER (gsf_doc_meta_data);
219 REGISTER (gsf_docprop_vector);
220 }
221
222 /**
223 * gsf_shutdown_dynamic:
224 * @module: currently unused
225 *
226 * De-intializes the GSF library from a type module.
227 * Currently does nothing.
228 **/
229 void
gsf_shutdown_dynamic(G_GNUC_UNUSED GTypeModule * module)230 gsf_shutdown_dynamic (G_GNUC_UNUSED GTypeModule *module)
231 {
232 }
233
234 static void
gsf_mem_dump_full(guint8 const * ptr,size_t len,gsf_off_t offset)235 gsf_mem_dump_full (guint8 const *ptr, size_t len, gsf_off_t offset)
236 {
237 static const char hexdigit[16] = "0123456789abcdef";
238
239 while (len > 0) {
240 char hexpart[3 * 16 + 1], *phex = hexpart;
241 char pic[17];
242 size_t j;
243 for (j = 0; j < 16; j++) {
244 if (len > 0) {
245 *phex++ = hexdigit[*ptr >> 4];
246 *phex++ = hexdigit[*ptr & 0xf];
247 pic[j] = (*ptr >= '!' && *ptr < 127 ? *ptr : '.');
248 len--;
249 ptr++;
250 } else {
251 *phex++ = 'X';
252 *phex++ = 'X';
253 pic[j] = '*';
254 }
255 *phex++ = ' ';
256 }
257 hexpart[3 * 16] = 0;
258 pic[16] = 0 ;
259
260 g_print ("%8lx | %s| %s\n", (long)offset, hexpart, pic);
261 offset += 16;
262 }
263 }
264
265 /**
266 * gsf_mem_dump:
267 * @ptr: memory area to be dumped.
268 * @len: how many bytes will be dumped.
269 *
270 * Dump @len bytes from the memory location given by @ptr.
271 **/
272 void
gsf_mem_dump(guint8 const * ptr,size_t len)273 gsf_mem_dump (guint8 const *ptr, size_t len)
274 {
275 gsf_mem_dump_full (ptr, len, 0);
276 }
277
278 /**
279 * gsf_input_dump:
280 * @input: a #GsfInput
281 * @dump_as_hex: If %TRUE, dump in hexidecmal format
282 *
283 * Dumps @input's contents to STDOUT, optionally in hex format.
284 */
285 void
gsf_input_dump(GsfInput * input,gboolean dump_as_hex)286 gsf_input_dump (GsfInput *input, gboolean dump_as_hex)
287 {
288 gsf_off_t offset = 0, size;
289
290 /* read in small blocks to excercise things */
291 size = gsf_input_size (GSF_INPUT (input));
292 while (size > 0) {
293 size_t count = (size > 0x1000) ? 0x1000 : size;
294 guint8 const *data =
295 gsf_input_read (GSF_INPUT (input), count, NULL);
296 g_return_if_fail (data != NULL);
297 if (dump_as_hex)
298 gsf_mem_dump_full (data, count, offset);
299 else
300 fwrite (data, 1, count, stdout);
301 size -= count;
302 offset += count;
303 }
304 if (!dump_as_hex)
305 fflush (stdout);
306 }
307
308 /**
309 * gsf_le_get_guint64:
310 * @p: pointer to storage
311 *
312 * Interpret binary data as a guint64 (8 byte unsigned integer type) in little
313 * endian order.
314 *
315 * Returns: interpreted data
316 */
317 guint64
gsf_le_get_guint64(void const * p)318 gsf_le_get_guint64 (void const *p)
319 {
320 #if G_BYTE_ORDER == G_BIG_ENDIAN
321 if (sizeof (guint64) == 8) {
322 guint64 li;
323 int i;
324 guint8 *t = (guint8 *)&li;
325 guint8 *p2 = (guint8 *)p;
326 int sd = sizeof (li);
327
328 for (i = 0; i < sd; i++)
329 t[i] = p2[sd - 1 - i];
330
331 return li;
332 } else {
333 g_error ("Big endian machine, but weird size of guint64");
334 }
335 #elif G_BYTE_ORDER == G_LITTLE_ENDIAN
336 if (sizeof (guint64) == 8) {
337 /*
338 * On i86, we could access directly, but Alphas require
339 * aligned access.
340 */
341 guint64 data;
342 memcpy (&data, p, sizeof (data));
343 return data;
344 } else {
345 g_error ("Little endian machine, but weird size of guint64");
346 }
347 #else
348 #error "Byte order not recognised -- out of luck"
349 #endif
350 }
351
352 /**
353 * gsf_le_get_float:
354 * @p: pointer to storage
355 *
356 * Interpret binary data as a float in little endian order.
357 *
358 *
359 * Returns: interpreted data
360 */
361 float
gsf_le_get_float(void const * p)362 gsf_le_get_float (void const *p)
363 {
364 #if G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
365 if (sizeof (float) == 4) {
366 float f;
367 int i;
368 guint8 *t = (guint8 *)&f;
369 guint8 *p2 = (guint8 *)p;
370 int sd = sizeof (f);
371
372 for (i = 0; i < sd; i++)
373 t[i] = p2[sd - 1 - i];
374
375 return f;
376 } else {
377 g_error ("Big endian machine, but weird size of floats");
378 }
379 #elif (G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN) || (G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN)
380 if (sizeof (float) == 4) {
381 /*
382 * On i86, we could access directly, but Alphas require
383 * aligned access.
384 */
385 float data;
386 memcpy (&data, p, sizeof (data));
387 return data;
388 } else {
389 g_error ("Little endian machine, but weird size of floats");
390 }
391 #else
392 #error "Floating-point byte order not recognised -- out of luck"
393 #endif
394 }
395
396 /**
397 * gsf_le_set_float:
398 * @p: pointer to storage
399 * @f: float to be stored
400 *
401 * Store a value of type float in memory in little endian order.
402 */
403 void
gsf_le_set_float(void * p,float f)404 gsf_le_set_float (void *p, float f)
405 {
406 #if G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
407 if (sizeof (float) == 4) {
408 int i;
409 guint8 *t = (guint8 *)&f;
410 guint8 *p2 = (guint8 *)p;
411 int sd = sizeof (f);
412
413 for (i = 0; i < sd; i++)
414 p2[sd - 1 - i] = t[i];
415 } else {
416 g_error ("Big endian machine, but weird size of floats");
417 }
418 #elif (G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN) || (G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN)
419 if (sizeof (float) == 4) {
420 /*
421 * On i86, we could access directly, but Alphas require
422 * aligned access.
423 */
424 memcpy (p, &f, sizeof (f));
425 } else {
426 g_error ("Little endian machine, but weird size of floats");
427 }
428 #else
429 #error "Floating-point byte order not recognised -- out of luck"
430 #endif
431 }
432
433 /**
434 * gsf_le_get_double:
435 * @p: pointer to storage
436 *
437 * Interpret binary data as a double in little endian order.
438 *
439 * Returns: interpreted data
440 */
441 double
gsf_le_get_double(void const * p)442 gsf_le_get_double (void const *p)
443 {
444 #if G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN
445 double data;
446 memcpy ((char *)&data + 4, p, 4);
447 memcpy ((char *)&data, (char const *)p + 4, 4);
448 return data;
449 #elif G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
450 if (sizeof (double) == 8) {
451 double d;
452 int i;
453 guint8 *t = (guint8 *)&d;
454 guint8 *p2 = (guint8 *)p;
455 int sd = sizeof (d);
456
457 for (i = 0; i < sd; i++)
458 t[i] = p2[sd - 1 - i];
459
460 return d;
461 } else {
462 g_error ("Big endian machine, but weird size of doubles");
463 }
464 #elif G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN
465 if (sizeof (double) == 8) {
466 /*
467 * On i86, we could access directly, but Alphas require
468 * aligned access.
469 */
470 double data;
471 memcpy (&data, p, sizeof (data));
472 return data;
473 } else {
474 g_error ("Little endian machine, but weird size of doubles");
475 }
476 #else
477 #error "Floating-point byte order not recognised -- out of luck"
478 #endif
479 }
480
481 /**
482 * gsf_le_set_double:
483 * @p: pointer to storage
484 * @d: double to be stored
485 *
486 * Store a value of type double in memory in little endian order
487 */
488 void
gsf_le_set_double(void * p,double d)489 gsf_le_set_double (void *p, double d)
490 {
491 #if G_FLOAT_BYTE_ORDER == G_ARMFLOAT_ENDIAN
492 memcpy (p, (char const *)&d + 4, 4);
493 memcpy ((char *)p + 4, &d, 4);
494 #elif G_FLOAT_BYTE_ORDER == G_BIG_ENDIAN
495 if (sizeof (double) == 8) {
496 int i;
497 guint8 *t = (guint8 *)&d;
498 guint8 *p2 = (guint8 *)p;
499 int sd = sizeof (d);
500
501 for (i = 0; i < sd; i++)
502 p2[sd - 1 - i] = t[i];
503 } else {
504 g_error ("Big endian machine, but weird size of doubles");
505 }
506 #elif G_FLOAT_BYTE_ORDER == G_LITTLE_ENDIAN
507 if (sizeof (double) == 8) {
508 /*
509 * On i86, we could access directly, but Alphas require
510 * aligned access.
511 */
512 memcpy (p, &d, sizeof (d));
513 } else {
514 g_error ("Little endian machine, but weird size of doubles");
515 }
516 #else
517 #error "Floating-point byte order not recognised -- out of luck"
518 #endif
519 }
520
521 /**
522 * gsf_extension_pointer:
523 * @path: A filename or file path.
524 *
525 * Extracts the extension from the end of a filename (the part after the final
526 * '.' in the filename).
527 *
528 * Returns: (transfer none): A pointer to the extension part of the
529 * filename, or a pointer to the end of the string if the filename
530 * does not have an extension.
531 */
532 char const *
gsf_extension_pointer(char const * path)533 gsf_extension_pointer (char const *path)
534 {
535 char const *s, *end;
536
537 g_return_val_if_fail (path != NULL, NULL);
538
539 end = path + strlen (path);
540 for (s = end; s > path; ) {
541 s--;
542 if (G_IS_DIR_SEPARATOR (*s))
543 break;
544 if (*s == '.')
545 return s + 1;
546 }
547
548 return end;
549 }
550
551 /**
552 * gsf_iconv_close:
553 * @handle: handle to be closed.
554 *
555 * A utility wrapper to safely close an iconv handle.
556 **/
557 void
gsf_iconv_close(GIConv handle)558 gsf_iconv_close (GIConv handle)
559 {
560 if (handle != NULL && handle != ((GIConv)-1))
561 g_iconv_close (handle);
562 }
563
564 /**
565 * gsf_filename_to_utf8:
566 * @filename: file name suitable for open(2).
567 * @quoted: if %TRUE, the resulting utf8 file name will be quoted
568 * (unless it is invalid).
569 *
570 * A utility wrapper to make sure filenames are valid utf8.
571 * Caller must g_free the result.
572 *
573 * Returns: @filename using utf-8 encoding for display
574 **/
575 char *
gsf_filename_to_utf8(char const * filename,gboolean quoted)576 gsf_filename_to_utf8 (char const *filename, gboolean quoted)
577 {
578 char *dname = g_filename_display_name (filename);
579 char *result;
580
581 if (quoted) {
582 result = g_strconcat ("\"", dname, "\"", NULL);
583 g_free (dname);
584 } else
585 result = dname;
586
587 return result;
588 }
589
590 /**
591 * gsf_base64_encode_close:
592 * @in: (array length=inlen): Data to be encoded
593 * @inlen: Length of data to be encoded
594 * @break_lines: Whether to use line breaks
595 * @out: (array): Encoded data.
596 * @state: (inout): holds the number of bits that are stored in @save
597 * @save: (inout): leftover bits that have not yet been decoded
598 *
599 * This funcion should be called to when finished encoding everything, to
600 * flush off the last little bit.
601 *
602 * Returns: a count of the number of bytes in the final block.
603 **/
604 size_t
gsf_base64_encode_close(guint8 const * in,size_t inlen,gboolean break_lines,guint8 * out,int * state,unsigned int * save)605 gsf_base64_encode_close (guint8 const *in, size_t inlen,
606 gboolean break_lines, guint8 *out, int *state, unsigned int *save)
607 {
608 guint8 *outptr = out;
609 if (inlen > 0)
610 outptr += gsf_base64_encode_step (in, inlen, break_lines,
611 outptr, state, save);
612 outptr += g_base64_encode_close (break_lines, outptr, state, save);
613 return outptr-out;
614 }
615
616 /**
617 * gsf_base64_encode_step:
618 * @in: (array): input stream
619 * @len: max length of data to decode
620 * @break_lines: Whether to use line breaks
621 * @out: (array): output stream
622 * @state: (inout): holds the number of bits that are stored in @save
623 * @save: (inout): leftover bits that have not yet been decoded
624 *
625 * Performs an 'encode step', only encodes blocks of 3 characters from @in into
626 * the output @out at a time, saves left-over state in @state and @save
627 * (initialise to 0 on first invocation).
628 *
629 * Returns: the number of bytes encoded
630 */
631 size_t
gsf_base64_encode_step(guint8 const * in,size_t len,gboolean break_lines,guint8 * out,int * state,unsigned int * save)632 gsf_base64_encode_step (guint8 const *in, size_t len,
633 gboolean break_lines, guint8 *out, int *state, unsigned int *save)
634 {
635 return g_base64_encode_step (in, len, break_lines, out, state, save);
636 }
637
638
639 /**
640 * gsf_base64_decode_step:
641 * @in: (array): input stream
642 * @len: max length of data to decode
643 * @out: (array): output stream
644 * @state: (inout): holds the number of bits that are stored in @save
645 * @save: (inout): leftover bits that have not yet been decoded
646 *
647 * Decodes a chunk of base64 encoded data
648 *
649 * Returns: the number of bytes converted
650 **/
651 size_t
gsf_base64_decode_step(guint8 const * in,size_t len,guint8 * out,int * state,guint * save)652 gsf_base64_decode_step (guint8 const *in, size_t len, guint8 *out,
653 int *state, guint *save)
654 {
655 return g_base64_decode_step (in, len, out, state, save);
656 }
657
658 /**
659 * gsf_base64_encode_simple:
660 * @data: (array): data stream
661 * @len: max length of data to encode
662 *
663 * Encodes data from @data back into @data using base64 encoding.
664 *
665 * Returns: the number of bytes encoded
666 */
667 guint8 *
gsf_base64_encode_simple(guint8 const * data,size_t len)668 gsf_base64_encode_simple (guint8 const *data, size_t len)
669 {
670 guint8 *out;
671 int state = 0;
672 guint save = 0;
673 gboolean break_lines = TRUE; /* This differs from g_base64_encode */
674 size_t outlen = len * 4 / 3 + 5;
675
676 if (break_lines)
677 outlen += outlen / 72 + 1;
678 out = g_new (guint8, outlen);
679 outlen = gsf_base64_encode_close (data, len, break_lines,
680 out, &state, &save);
681 out[outlen] = '\0';
682 return out;
683 }
684
685 /**
686 * gsf_base64_decode_simple:
687 * @data: (array): data stream
688 * @len: max length of data to decode
689 *
690 * Decodes a chunk of base64 encoded data from @data back into @data.
691 *
692 * Returns: the number of bytes converted
693 */
694 size_t
gsf_base64_decode_simple(guint8 * data,size_t len)695 gsf_base64_decode_simple (guint8 *data, size_t len)
696 {
697 int state = 0;
698 guint save = 0;
699 return gsf_base64_decode_step (data, len, data, &state, &save);
700 }
701
702
703 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
704
705 /* Largely a copy of g_object_new_valist. */
706 /**
707 * gsf_property_settings_collect_valist:
708 * @object_type: the GType for which the properties are being set.
709 * @p_n_params: a pointer to the number of properties collected. (Used for
710 * both input and output.)
711 * @p_params: a pointer to the GParameter array that holds the properties.
712 * (Used for both input and output. This may point to a %NULL pointer if
713 * there are no properties collected yet.)
714 * @first_property_name: the name of the first property being set, or %NULL.
715 * @var_args: a va_list holding the remainder of the property names and
716 * values, terminated by a %NULL.
717 *
718 * This function builds a GParameter array suitable for g_object_newv.
719 **/
720 void
gsf_property_settings_collect_valist(GType object_type,GParameter ** p_params,size_t * p_n_params,const gchar * first_property_name,va_list var_args)721 gsf_property_settings_collect_valist (GType object_type,
722 GParameter **p_params,
723 size_t *p_n_params,
724 const gchar *first_property_name,
725 va_list var_args)
726 {
727 GObjectClass *class;
728 GParameter *params = *p_params;
729 const gchar *name;
730 size_t n_params = *p_n_params;
731 size_t n_alloced_params = n_params; /* We might have more. */
732
733 g_return_if_fail (G_TYPE_IS_OBJECT (object_type));
734
735 class = g_type_class_ref (object_type);
736
737 name = first_property_name;
738 while (name)
739 {
740 gchar *error = NULL;
741 GParamSpec *pspec = g_object_class_find_property (class, name);
742 if (!pspec)
743 {
744 g_warning ("%s: object class `%s' has no property named `%s'",
745 G_STRFUNC,
746 g_type_name (object_type),
747 name);
748 break;
749 }
750
751 if (n_params >= n_alloced_params)
752 {
753 n_alloced_params += 16;
754 params = g_renew (GParameter, params, n_alloced_params);
755 }
756 params[n_params].name = name;
757 params[n_params].value.g_type = 0;
758 g_value_init (¶ms[n_params].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
759 G_VALUE_COLLECT (¶ms[n_params].value, var_args, 0, &error);
760 if (error)
761 {
762 g_warning ("%s: %s", G_STRFUNC, error);
763 g_free (error);
764 g_value_unset (¶ms[n_params].value);
765 break;
766 }
767 n_params++;
768 name = va_arg (var_args, gchar*);
769 }
770
771 g_type_class_unref (class);
772
773 *p_params = params;
774 *p_n_params = n_params;
775 }
776
777 /* This is a vararg version of gsf_property_settings_collect_valist. */
778 void
gsf_property_settings_collect(GType object_type,GParameter ** p_params,size_t * p_n_params,const gchar * first_property_name,...)779 gsf_property_settings_collect (GType object_type,
780 GParameter **p_params,
781 size_t *p_n_params,
782 const gchar *first_property_name,
783 ...)
784 {
785 va_list var_args;
786 va_start (var_args, first_property_name);
787 gsf_property_settings_collect_valist (object_type, p_params, p_n_params, first_property_name, var_args);
788 va_end (var_args);
789 }
790
791 /**
792 * gsf_property_settings_find:
793 * @name:
794 * @params: (array length=n_params):
795 * @n_params:
796 */
797 const GParameter *
gsf_property_settings_find(const char * name,const GParameter * params,size_t n_params)798 gsf_property_settings_find (const char *name,
799 const GParameter *params,
800 size_t n_params)
801 {
802 size_t i;
803
804 for (i = 0; i < n_params; i++)
805 if (g_str_equal (name, params[i].name))
806 return params + i;
807
808 return NULL;
809 }
810
811 /**
812 * gsf_property_settings_free:
813 * @params: (array length=n_params) (transfer full):
814 * @n_params:
815 */
816 void
gsf_property_settings_free(GParameter * params,size_t n_params)817 gsf_property_settings_free (GParameter *params,
818 size_t n_params)
819 {
820 while (n_params--)
821 g_value_unset (¶ms[n_params].value);
822 g_free (params);
823 }
824 G_GNUC_END_IGNORE_DEPRECATIONS
825
826
827
828 /* Errors */
829
830 /**
831 * gsf_error_quark:
832 *
833 * Returns: the #GQuark used to identify libgsf errors in #GError structures.
834 * Specific error codes come from the #GsfError enumeration.
835 **/
836 GQuark
gsf_error_quark(void)837 gsf_error_quark (void)
838 {
839 static GQuark quark;
840
841 if (quark == 0)
842 quark = g_quark_from_static_string ("gsf-error-quark");
843
844 return quark;
845 }
846