Imported Upstream version 1.1.4
[platform/upstream/xdelta1.git] / libedsio / edsio.c
1 /* -*-Mode: C;-*-
2  * $Id: edsio.c 1.1 Sun, 28 Jan 2007 10:02:26 -0800 jmacd $
3  *
4  * Copyright (C) 1998, 1999, Josh MacDonald.
5  * All Rights Reserved.
6  *
7  * Author: Josh MacDonald <jmacd@CS.Berkeley.EDU>
8  */
9
10 #include "edsio.h"
11 #include <stdio.h>
12
13 #if TIME_WITH_SYS_TIME
14 # include <sys/time.h>
15 # include <time.h>
16 #else
17 # if HAVE_SYS_TIME_H
18 #  include <sys/time.h>
19 # else
20 #  include <time.h>
21 # endif
22 #endif
23
24 #include "maketime.h"
25
26 /*#define DEBUG_PROPS*/
27
28 /* Event delivery
29  */
30
31 static GHashTable* all_event_defs = NULL;
32
33 static GPtrArray* all_event_watchers = NULL;
34
35 typedef struct _ErrorDeliveryWatcher ErrorDeliveryWatcher;
36 typedef struct _DelayedEvent DelayedEvent;
37
38 struct _ErrorDeliveryWatcher {
39   ErrorDeliveryFunc deliver;
40 };
41
42 struct _DelayedEvent {
43   GenericEvent     ev;
44   GenericEventDef *def;
45   const char      *msg;
46 };
47
48 void
49 eventdelivery_initialize_event_def (gint        code,
50                                     gint        level,
51                                     gint        flags,
52                                     const char* name,
53                                     const char* oneline,
54                                     const char * (* field_to_string) (GenericEvent* ev, gint field))
55 {
56   GenericEventDef* def = g_new0 (GenericEventDef, 1);
57
58   if (! all_event_defs)
59     all_event_defs = g_hash_table_new (g_int_hash, g_int_equal);
60
61   def->code = code;
62   def->level = level;
63   def->flags = flags;
64   def->name = name;
65   def->oneline = oneline;
66   def->field_to_string = field_to_string;
67
68   g_hash_table_insert (all_event_defs, & def->code, def);
69 }
70
71 void
72 eventdelivery_event_watch_all (ErrorDeliveryFunc func)
73 {
74   ErrorDeliveryWatcher* w = g_new0 (ErrorDeliveryWatcher, 1);
75
76   w->deliver = func;
77
78   if (! all_event_watchers)
79     all_event_watchers = g_ptr_array_new ();
80
81   g_ptr_array_add (all_event_watchers, w);
82 }
83
84 GenericEventDef*
85 eventdelivery_event_lookup (gint code)
86 {
87   return g_hash_table_lookup (all_event_defs, & code);
88 }
89
90 void
91 eventdelivery_event_deliver (GenericEvent* e)
92 {
93   static gint in_call = FALSE;
94   static GQueue* queued = NULL;
95   static GPtrArray* free_strings = NULL;
96
97   if (! queued)
98     {
99       queued = g_queue_new ();
100       free_strings = g_ptr_array_new ();
101     }
102
103   in_call += 1;
104
105   g_assert (e);
106
107   edsio_edsio_init ();
108
109   if (all_event_defs)
110     {
111       GenericEventDef* def = g_hash_table_lookup (all_event_defs, & e->code);
112
113       if (def)
114         {
115           GString* out;
116           const char* oneline = def->oneline;
117           char c;
118
119           out = g_string_new (NULL);
120
121           while ((c = *oneline++))
122             {
123               switch (c)
124                 {
125                 case '$':
126                   {
127                     const char* field;
128                     char *end;
129                     int f;
130
131                     if ((*oneline++) != '{')
132                       goto badevent;
133
134                     f = strtol (oneline, &end, 10);
135
136                     if (f < 0 || !end || end[0] != '}')
137                       goto badevent;
138
139                     oneline = end+1;
140
141                     g_assert (def->field_to_string);
142
143                     field = def->field_to_string (e, f);
144
145                     if (field)
146                       {
147                         g_string_append (out, field);
148
149                         g_free ((void*) field);
150                       }
151                     else
152                       goto badevent;
153                   }
154                   break;
155                 default:
156                   g_string_append_c (out, c);
157                 }
158             }
159
160           if (! all_event_watchers)
161             {
162               fprintf (stderr, "%s:%d: %s\n", e->srcfile, e->srcline, out->str);
163
164               g_string_free (out, TRUE);
165             }
166           else if (in_call == 1)
167             {
168               gint i;
169
170               for (i = 0; i < all_event_watchers->len; i += 1)
171                 {
172                   ErrorDeliveryWatcher* w = all_event_watchers->pdata[i];
173
174                   if (! w->deliver (e, def, out->str))
175                     {
176                       g_warning ("%s:%d: An error delivery routine failed: %s\n", e->srcfile, e->srcline, out->str);
177                       in_call = 0;
178                       return;
179                     }
180                 }
181
182               while (g_queue_get_size (queued) > 0)
183                 {
184                   DelayedEvent* de = g_queue_pop (queued);
185
186                   for (i = 0; i < all_event_watchers->len; i += 1)
187                     {
188                       ErrorDeliveryWatcher* w = all_event_watchers->pdata[i];
189
190                       if (! w->deliver (& de->ev, de->def, de->msg))
191                         {
192                           g_warning ("%s:%d: An error delivery routine failed: %s\n", e->srcfile, e->srcline, out->str);
193                           in_call = 0;
194                           return;
195                         }
196                     }
197                 }
198
199               for (i = 0; i < free_strings->len; i += 1)
200                 g_string_free (free_strings->pdata[i], TRUE);
201
202               g_ptr_array_set_size (free_strings, 0);
203
204               g_string_free (out, TRUE);
205             }
206           else
207             {
208               DelayedEvent* de = g_new (DelayedEvent, 1);
209
210               de->ev = *e;
211               de->def = def;
212               de->msg = out->str;
213
214               g_queue_push (queued, de);
215
216               g_ptr_array_add (free_strings, out);
217             }
218
219               in_call -= 1;
220
221           return;
222         }
223     }
224
225   g_warning ("%s:%d: Unrecognized event delivered (code=%d)\n", e->srcfile, e->srcline, e->code);
226
227   in_call -= 1;
228
229   return;
230
231  badevent:
232
233   g_warning ("%s:%d: An malformed error could not print here (code=%d)\n", e->srcfile, e->srcline, e->code);
234
235   in_call -= 1;
236
237   return;
238 }
239
240 const char*
241 eventdelivery_int_to_string (int x)
242 {
243   return g_strdup_printf ("%d", x);
244 }
245
246 const char*
247 eventdelivery_string_to_string  (const char* x)
248 {
249   return g_strdup (x);
250 }
251
252 const char*
253 eventdelivery_source_to_string  (SerialSource* x)
254 {
255   return g_strdup ("@@@SerialSource");
256 }
257
258 const char*
259 eventdelivery_sink_to_string  (SerialSink* x)
260 {
261   return g_strdup ("@@@SerialSink");
262 }
263
264 const char*
265 eventdelivery_handle_to_string (FileHandle* x)
266 {
267   g_return_val_if_fail (x, g_strdup ("*error*"));
268
269   return x->table->table_handle_name (x);
270 }
271
272 /* Misc crap.
273  */
274
275 gboolean
276 edsio_time_of_day (SerialGenericTime* setme)
277 {
278 #if HAVE_GETTIMEOFDAY
279
280   struct timeval tv;
281
282   if (gettimeofday (& tv, NULL))
283     {
284       edsio_generate_errno_event (EC_EdsioGetTimeOfDayFailure);
285       goto bail;
286     }
287
288   if (setme)
289     {
290       setme->nanos = tv.tv_usec * 1000;
291       setme->seconds = tv.tv_sec;
292     }
293
294 #else
295
296   struct timeval tv;
297   time_t t = time (NULL);
298
299   if (t < 0)
300     {
301       edsio_generate_errno_event (EC_EdsioTimeFailure);
302       goto bail;
303     }
304
305   if (setme)
306     {
307       setme->nanos = 0;
308       setme->seconds = tv.tv_sec;
309     }
310
311 #endif
312
313   return TRUE;
314
315  bail:
316
317   setme->nanos = 0;
318   setme->seconds = 10;
319
320   return FALSE;
321 }
322
323 gchar*
324 edsio_time_to_iso8601 (SerialGenericTime *tp)
325 {
326   return edsio_time_t_to_iso8601 (tp->seconds);
327 }
328
329 gchar*
330 edsio_time_t_to_iso8601 (GTime t0)
331 {
332   static char timebuf[64];
333   time_t t = t0;
334
335   struct tm lt = *localtime(&t);
336   int utc_offset = difftm(&lt, gmtime(&t));
337   char sign = utc_offset < 0 ? '-' : '+';
338   int minutes = abs (utc_offset) / 60;
339   int hours = minutes / 60;
340
341   sprintf(timebuf,
342           "%d-%02d-%02d %02d:%02d:%02d%c%02d%02d",
343           lt.tm_year + 1900,
344           lt.tm_mon + 1,
345           lt.tm_mday,
346           lt.tm_hour,
347           lt.tm_min,
348           lt.tm_sec,
349           sign,
350           hours,
351           minutes % 60);
352
353   return timebuf;
354 }
355
356 static gboolean
357 strtosl_checked (const char* str, long* l, const char* errmsg)
358 {
359   char* end;
360
361   (*l) = strtol (str, &end, 10);
362
363   if (!end || end[0])
364     {
365       if (errmsg)
366         edsio_generate_stringstring_event (EC_EdsioInvalidIntegerString, errmsg, str);
367
368       (*l) = 0;
369       return FALSE;
370     }
371
372   return TRUE;
373 }
374
375 gboolean
376 strtosi_checked (const char* str, gint32* i,  const char* errmsg)
377 {
378   long l;
379
380   if (! strtosl_checked (str, &l, errmsg))
381     {
382       (*i) = 0;
383       return FALSE;
384     }
385
386   if (l > G_MAXINT || l < G_MININT)
387     {
388       if (errmsg)
389         edsio_generate_stringstring_event (EC_EdsioIntegerOutOfRange, errmsg, str);
390
391       (*i) = 0;
392       return FALSE;
393     }
394
395   (*i) = l;
396
397   return TRUE;
398 }
399
400 gboolean
401 strtoss_checked (const char* str, gint16* i,  const char* errmsg)
402 {
403   long l;
404
405   if (! strtosl_checked (str, &l, errmsg))
406     {
407       (*i) = 0;
408       return FALSE;
409     }
410
411   if (l > G_MAXSHORT || l < G_MINSHORT)
412     {
413       if (errmsg)
414         edsio_generate_stringstring_event (EC_EdsioIntegerOutOfRange, errmsg, str);
415
416       (*i) = 0;
417       return FALSE;
418     }
419
420   (*i) = l;
421
422   return TRUE;
423 }
424
425 gboolean
426 strtoui_checked (const char* str, guint32* i, const char* errmsg)
427 {
428   long l;
429
430   if (! strtosl_checked (str, &l, errmsg))
431     {
432       (*i) = 0;
433       return FALSE;
434     }
435
436   if (l < 0)
437     {
438       if (errmsg)
439         edsio_generate_stringstring_event (EC_EdsioInvalidIntegerSign, errmsg, str);
440
441       (*i) = 0;
442       return FALSE;
443     }
444
445   (*i) = l;
446
447   if (l != (*i))
448     {
449       if (errmsg)
450         edsio_generate_stringstring_event (EC_EdsioIntegerOutOfRange, errmsg, str);
451
452       (*i) = 0;
453       return FALSE;
454     }
455
456   return TRUE;
457 }
458
459 gboolean
460 strtous_checked (const char* str, guint16* i, const char* errmsg)
461 {
462   long l;
463
464   if (! strtosl_checked (str, &l, errmsg))
465     {
466       (*i) = 0;
467       return FALSE;
468     }
469
470   if (l < 0)
471     {
472       if (errmsg)
473         edsio_generate_stringstring_event (EC_EdsioInvalidIntegerSign, errmsg, str);
474
475       (*i) = 0;
476       return FALSE;
477     }
478
479   (*i) = l;
480
481   if (l != (*i))
482     {
483       if (errmsg)
484         edsio_generate_stringstring_event (EC_EdsioIntegerOutOfRange, errmsg, str);
485
486       (*i) = 0;
487       return FALSE;
488     }
489
490   return TRUE;
491 }
492
493 gint
494 edsio_md5_equal (gconstpointer   v,
495                  gconstpointer   v2)
496 {
497   return memcmp (v, v2, 16) == 0;
498 }
499
500 guint
501 edsio_md5_hash  (gconstpointer   v)
502 {
503   guint8* md5 = (guint8*) v;
504   guint x = 0;
505   gint i, j;
506
507   for (i = 0, j = 0; i < 16; i += 1, j += 1, j %= sizeof (guint32))
508     x ^= md5[i] << (8*j);
509
510   return x;
511 }
512
513 void
514 serializeio_print_bytes (const guint8* bytes, guint len0)
515 {
516   char buf[100];
517   int i;
518   guint len;
519
520   len = MIN (len0, 32);
521
522   for (i = 0; i < len; i += 1)
523     sprintf (buf + 2*i, "%02x", bytes[i]);
524
525   if (len0 > len)
526     strcat (buf, "...");
527
528   g_print ("%s\n", buf);
529 }
530
531 void
532 edsio_md5_to_string (const guint8* md5, char buf[33])
533 {
534   gint i;
535
536   for (i = 0; i < 16; i += 1)
537     sprintf (buf + 2*i, "%02x", md5[i]);
538 }
539
540 static gboolean
541 from_hex (char c, int* x, const char* ctx)
542 {
543   char buf[2];
544
545   if (c >= '0' && c <= '9')
546     {
547       (*x) = c - '0';
548       return TRUE;
549     }
550   else if (c >= 'A' && c <= 'F')
551     {
552       (*x) = c - 'A' + 10;
553       return TRUE;
554     }
555   else if (c >= 'a' && c <= 'f')
556     {
557       (*x) = c - 'a' + 10;
558       return TRUE;
559     }
560
561   buf[0] = c;
562   buf[1] = 0;
563
564   edsio_generate_stringstring_event (EC_EdsioInvalidHexDigit, buf, ctx);
565   return FALSE;
566 }
567
568 gboolean
569 edsio_md5_from_string (guint8* md5, const char buf[33])
570 {
571   gint i;
572   gint l = strlen (buf);
573
574   if (l < 32)
575     {
576       edsio_generate_string_event (EC_EdsioMD5StringShort, buf);
577       return FALSE;
578     }
579   else if (l > 32)
580     {
581       edsio_generate_string_event (EC_EdsioMD5StringLong, buf);
582       return FALSE;
583     }
584
585   for (i = 0; i < 16; i += 1)
586     {
587       char c1 = buf[(2*i)];
588       char c2 = buf[(2*i)+1];
589       int x1, x2;
590
591       if (! from_hex (c1, &x1, buf))
592         return FALSE;
593
594       if (! from_hex (c2, &x2, buf))
595         return FALSE;
596
597       md5[i] = (x1 << 4) | x2;
598     }
599
600   return TRUE;
601 }
602
603 /* Strings
604  */
605
606 const char* edsio_intern_string (const char* str)
607 {
608   static GStringChunk* chunk = NULL;
609
610   if (! chunk)
611     chunk = g_string_chunk_new (256);
612
613   return g_string_chunk_insert_const (chunk, str);
614 }
615
616 /* Properties
617  */
618
619 typedef struct _EdsioHostType     EdsioHostType;
620 typedef struct _EdsioPropertyType EdsioPropertyType;
621
622 struct _EdsioPropertyType {
623   const char *type_name;
624   PropFreeFunc freer;
625   PropGSFunc getter;
626   PropGSFunc setter;
627   PropSerialize serialize;
628   PropUnserialize unserialize;
629 };
630
631 struct _EdsioHostType {
632   const char *host_name;
633   PropertyTableFunc ptable;
634   PersistSourceFunc source;
635   PersistSinkFunc   sink;
636   PersistIssetFunc  isset;
637   PersistUnsetFunc  unset;
638 };
639
640 struct _EdsioProperty {
641   guint32     prop_code;
642   const char *prop_name;
643   guint32     prop_flags;
644   EdsioPropertyType *type;
645   EdsioHostType *host;
646 };
647
648 union _EdsioPropertyEntry {
649   guint32          as_uint32;
650   SerialEdsioBytes as_bytes;
651   gpointer         as_vptr;
652   const char*      as_string;
653 };
654
655 struct _EdsioGenericProperty
656 {
657   guint32 code;
658 };
659
660 static GHashTable* all_property_types = NULL;
661 static GHashTable* all_host_types = NULL;
662 static GHashTable* all_properties = NULL;
663 static GHashTable* all_property_codes = NULL;
664 static guint32     property_code_sequence = 0;
665
666 void
667 edsio_initialize_property_type (const char* t, PropFreeFunc freer, PropGSFunc getter, PropGSFunc setter, PropSerialize ser, PropUnserialize unser)
668 {
669   EdsioPropertyType* type;
670
671   t = edsio_intern_string (t);
672
673   if (! all_property_types)
674     all_property_types = g_hash_table_new (g_direct_hash, g_direct_equal);
675
676   if ((type = g_hash_table_lookup (all_property_types, t)) != NULL)
677     {
678       if (getter != type->getter ||
679           setter != type->setter ||
680           ser != type->serialize ||
681           unser != type->unserialize)
682         edsio_generate_string_event (EC_EdsioDuplicatePropertyTypeRegistered, t);
683       return;
684     }
685
686   type = g_new0 (EdsioPropertyType, 1);
687
688   type->type_name = t;
689   type->freer = freer;
690   type->getter = getter;
691   type->setter = setter;
692   type->serialize = ser;
693   type->unserialize = unser;
694
695   g_hash_table_insert (all_property_types, (gpointer) t, type);
696 }
697
698 void
699 edsio_initialize_host_type (const char*       ph,
700                             PropertyTableFunc ptable,
701                             PersistSourceFunc source,
702                             PersistSinkFunc   sink,
703                             PersistIssetFunc  isset,
704                             PersistUnsetFunc  unset)
705 {
706   EdsioHostType* host;
707
708   ph = edsio_intern_string (ph);
709
710   if (! all_host_types)
711     all_host_types = g_hash_table_new (g_direct_hash, g_direct_equal);
712
713   if (g_hash_table_lookup (all_host_types, ph))
714     {
715       edsio_generate_string_event (EC_EdsioDuplicateHostTypeRegistered, ph);
716       return;
717     }
718
719   host = g_new0 (EdsioHostType, 1);
720
721   host->host_name = ph;
722   host->ptable = ptable;
723   host->source = source;
724   host->sink   = sink;
725   host->isset  = isset;
726   host->unset  = unset;
727
728   g_hash_table_insert (all_host_types, (gpointer) ph, host);
729
730 }
731
732 gboolean
733 edsio_new_property (const char* name, const char* ph, const char* t, guint32 flags, EdsioGenericProperty *ret_prop)
734 {
735   EdsioProperty* prop;
736   EdsioPropertyType* type;
737   EdsioHostType* host;
738
739   name = edsio_intern_string (name);
740   ph   = edsio_intern_string (ph);
741   t    = edsio_intern_string (t);
742
743   g_assert (all_property_types);
744
745   if (! all_properties)
746     {
747       all_properties = g_hash_table_new (g_direct_hash, g_direct_equal);
748       all_property_codes = g_hash_table_new (g_int_hash, g_int_equal);
749     }
750
751   if ((prop = g_hash_table_lookup (all_properties, name)) != NULL)
752     {
753       edsio_generate_string_event (EC_EdsioDuplicatePropertyNameRegistered, name);
754       ret_prop->code = prop->prop_code;
755       return TRUE;
756     }
757
758   if ((type = g_hash_table_lookup (all_property_types, t)) == NULL)
759     {
760       edsio_generate_string_event (EC_EdsioNoSuchPropertyType, t);
761       return FALSE;
762     }
763
764   if ((host = g_hash_table_lookup (all_host_types, ph)) == NULL)
765     {
766       edsio_generate_string_event (EC_EdsioNoSuchHostType, ph);
767       return FALSE;
768     }
769
770   if (flags & PF_Persistent && ! host->isset)
771     {
772       edsio_generate_stringstring_event (EC_EdsioPersistenceUnavailable, name, ph);
773       return FALSE;
774     }
775
776   prop = g_new0 (EdsioProperty, 1);
777
778   prop->prop_code  = ++property_code_sequence;
779   prop->prop_name  = name;
780   prop->prop_flags = flags;
781   prop->type       = type;
782   prop->host       = host;
783
784   g_hash_table_insert (all_properties, (gpointer) name, prop);
785   g_hash_table_insert (all_property_codes, & prop->prop_code, prop);
786
787   ret_prop->code = prop->prop_code;
788
789   return TRUE;
790 }
791
792 static EdsioProperty*
793 edsio_property_find (const char* ph, const char* t, guint32 code)
794 {
795   EdsioProperty* prop;
796
797   ph = edsio_intern_string (ph);
798   t  = edsio_intern_string (t);
799
800   if (code <= 0 || code > property_code_sequence)
801     {
802       edsio_generate_int_event (EC_EdsioNoSuchProperty, code);
803       return NULL;
804     }
805
806   if (! (prop = g_hash_table_lookup (all_property_codes, & code)))
807     {
808       edsio_generate_int_event (EC_EdsioNoSuchProperty, code);
809       return NULL;
810     }
811
812   if (prop->host->host_name != ph)
813     {
814       edsio_generate_stringstringstring_event (EC_EdsioWrongHostType, prop->prop_name, ph, prop->host->host_name);
815       return NULL;
816     }
817
818   if (prop->type->type_name != t)
819     {
820       edsio_generate_stringstringstring_event (EC_EdsioWrongDataType, prop->prop_name, t, prop->type->type_name);
821       return NULL;
822     }
823
824   return prop;
825 }
826
827 EdsioPropertyEntry*
828 edsio_property_get (gpointer obj, EdsioProperty* prop)
829 {
830   EdsioPropertyEntry* ent;
831   GHashTable* table = * prop->host->ptable (obj);
832   gboolean persist = prop->prop_flags & PF_Persistent;
833
834 #ifdef DEBUG_PROPS
835   g_print ("get %p.%s\n", obj, prop->prop_name);
836 #endif
837
838   if (table && (ent = g_hash_table_lookup (table, & prop->prop_code)) != NULL)
839     return ent;
840
841   if (persist)
842     {
843       SerialSource* src;
844
845       if (! (src = prop->host->source (obj, prop->prop_name)))
846         return NULL;
847
848       g_assert (prop->type->unserialize);
849
850       if (! prop->type->unserialize (src, & ent))
851         return NULL;
852
853       g_assert (ent);
854
855       if (! src->source_close (src))
856         return NULL;
857
858       src->source_free (src);
859
860       if (! table)
861         table = (* prop->host->ptable (obj)) = g_hash_table_new (g_int_hash, g_int_equal);
862
863       g_hash_table_insert (table, & prop->prop_code, ent);
864
865       return ent;
866     }
867
868   edsio_generate_string_event (EC_EdsioPropertyNotSet, prop->prop_name);
869   return NULL;
870 }
871
872 gboolean
873 edsio_property_set (gpointer obj, EdsioProperty* prop, EdsioPropertyEntry* set)
874 {
875   EdsioPropertyEntry* ent;
876   gboolean persist = prop->prop_flags & PF_Persistent;
877   GHashTable* table = * prop->host->ptable (obj);
878
879 #ifdef DEBUG_PROPS
880   g_print ("set %p.%s\n", obj, prop->prop_name);
881 #endif
882
883   if (! table)
884     table = (* prop->host->ptable (obj)) = g_hash_table_new (g_int_hash, g_int_equal);
885
886   ent = g_hash_table_lookup (table, & prop->prop_code);
887
888   if (ent)
889     {
890       g_hash_table_remove (table, & prop->prop_code);
891       prop->type->freer (ent);
892     }
893
894   g_hash_table_insert (table, & prop->prop_code, set);
895
896   if (persist)
897     {
898       SerialSink* sink;
899
900       if (! (sink = prop->host->sink (obj, prop->prop_name)))
901         return FALSE;
902
903       g_assert (prop->type->serialize);
904
905       if (! prop->type->serialize (sink, set))
906         return FALSE;
907
908       if (! sink->sink_close (sink))
909         return FALSE;
910
911       sink->sink_free (sink);
912     }
913
914   return TRUE;
915 }
916
917 gboolean
918 edsio_property_isset (const char* ph, const char* t, guint32 code, gpointer obj)
919 {
920   EdsioProperty* prop;
921   GHashTable* table;
922   gboolean persist;
923   gboolean result = FALSE;
924
925   if (! (prop = edsio_property_find (ph, t, code)))
926     goto done;
927
928   persist = prop->prop_flags & PF_Persistent;
929
930   table = * prop->host->ptable (obj);
931
932   if (persist)
933     {
934           PersistIssetFunc issetfunc = prop->host->isset;
935       if (issetfunc(obj, prop->prop_name))
936         {
937           if (! edsio_property_get (obj, prop))
938             goto done;
939
940           table = * prop->host->ptable (obj);
941         }
942     }
943
944   if (! table)
945     goto done;
946
947   result = (g_hash_table_lookup (table, & code) != NULL);
948
949  done:
950
951 #ifdef DEBUG_PROPS
952   g_print ("isset %p.%s = %s\n", obj, prop->prop_name, result ? "true" : "false");
953 #endif
954
955   return result;
956 }
957
958 gboolean
959 edsio_property_unset (const char* ph, const char* t, guint32 code, gpointer obj)
960 {
961   EdsioProperty* prop;
962   gboolean persist;
963   GHashTable* table;
964
965   if (! (prop = edsio_property_find (ph, t, code)))
966     return FALSE;
967
968 #ifdef DEBUG_PROPS
969   g_print ("unset %p.%s\n", obj, prop->prop_name);
970 #endif
971
972   persist = prop->prop_flags & PF_Persistent;
973   table = * prop->host->ptable (obj);
974
975   if (table)
976     {
977       EdsioPropertyEntry* ent;
978
979       ent = g_hash_table_lookup (table, & code);
980
981       g_hash_table_remove (table, & code);
982
983       if (g_hash_table_size (table) == 0)
984         {
985           g_hash_table_destroy (table);
986           table = (* prop->host->ptable (obj)) = NULL;
987         }
988
989       /*g_free (ent);*/
990     }
991
992   if (persist)
993     {
994       if (! prop->host->unset (obj, prop->prop_name))
995         return FALSE;
996     }
997
998   return TRUE;
999 }
1000
1001 static gboolean
1002 edsio_false ()
1003 {
1004   return FALSE;
1005 }
1006
1007 PropGSFunc
1008 edsio_property_getter (const char* ph, const char* t, guint32 code, EdsioProperty** ep)
1009 {
1010   if (! ((*ep) = edsio_property_find (ph, t, code)))
1011     return & edsio_false;
1012
1013   return (* ep)->type->getter;
1014 }
1015
1016 PropGSFunc
1017 edsio_property_setter (const char* ph, const char* t, guint32 code, EdsioProperty** ep)
1018 {
1019   if (! ((* ep) = edsio_property_find (ph, t, code)))
1020     return & edsio_false;
1021
1022   return (* ep)->type->setter;
1023 }
1024
1025 /* Primitive type serializers
1026  */
1027
1028 /* integer
1029  */
1030 gboolean
1031 edsio_property_uint_getter (gpointer obj, EdsioProperty* prop, guint32* get)
1032 {
1033   EdsioPropertyEntry *ent;
1034
1035   if (! (ent = edsio_property_get (obj, prop)))
1036     return FALSE;
1037
1038   (*get) = ent->as_uint32;
1039
1040   return TRUE;
1041 }
1042
1043 gboolean
1044 edsio_property_uint_setter (gpointer obj, EdsioProperty* prop, guint32  set)
1045 {
1046   EdsioPropertyEntry *ent = g_new (EdsioPropertyEntry, 1);
1047
1048   ent->as_uint32 = set;
1049
1050   return edsio_property_set (obj, prop, ent);
1051 }
1052
1053 void
1054 edsio_property_uint_free (gpointer obj)
1055 {
1056   g_free (obj);
1057 }
1058
1059 gboolean
1060 unserialize_uint (SerialSource *source, guint32** x)
1061 {
1062   SerialEdsioUint *s;
1063   guint32 *n;
1064
1065   if (! unserialize_edsiouint (source, & s))
1066     return FALSE;
1067
1068   n = g_new (guint32, 1);
1069
1070   (* x) = n;
1071
1072   (* n) = s->val;
1073
1074   g_free (s);
1075
1076   return TRUE;
1077 }
1078
1079 gboolean
1080 serialize_uint_obj (SerialSink *sink, guint32* x)
1081 {
1082   return serialize_edsiouint (sink, *x);
1083 }
1084
1085 /* String
1086  */
1087
1088 void
1089 edsio_property_string_free   (gpointer obj)
1090 {
1091   g_free (obj);
1092 }
1093
1094 gboolean
1095 edsio_property_string_getter (gpointer obj, EdsioProperty* prop, const char** get)
1096 {
1097   if (! ((*get) = (const char*) edsio_property_get (obj, prop)))
1098     return FALSE;
1099
1100   return TRUE;
1101 }
1102
1103 gboolean
1104 edsio_property_string_setter (gpointer obj, EdsioProperty* prop, const char*  set)
1105 {
1106   return edsio_property_set (obj, prop, (EdsioPropertyEntry*) set);
1107 }
1108
1109 gboolean
1110 unserialize_string   (SerialSource *source, const char** x)
1111 {
1112   SerialEdsioString *s;
1113
1114   if (! unserialize_edsiostring (source, & s))
1115     return FALSE;
1116
1117   (*x) = g_strdup (s->val);
1118
1119   g_free (s);
1120
1121   return TRUE;
1122 }
1123
1124 gboolean
1125 serialize_string_obj (SerialSink *sink, const char* x)
1126 {
1127   return serialize_edsiostring (sink, x);
1128 }
1129
1130 /* Bytes
1131  */
1132
1133 gboolean
1134 unserialize_bytes (SerialSource *source, SerialEdsioBytes** x)
1135 {
1136   return unserialize_edsiobytes (source, x);
1137 }
1138
1139 gboolean
1140 serialize_bytes_obj (SerialSink *sink, SerialEdsioBytes *x)
1141 {
1142   return serialize_edsiobytes_obj (sink, x);
1143 }
1144
1145 gboolean
1146 edsio_property_bytes_getter (gpointer obj, EdsioProperty* prop, guint8** get, guint32* get_len)
1147 {
1148   EdsioPropertyEntry *ent;
1149
1150   if (! (ent = edsio_property_get (obj, prop)))
1151     return FALSE;
1152
1153   (* get) = (gpointer) ent->as_bytes.val;
1154   (* get_len) = ent->as_bytes.val_len;
1155
1156   return TRUE;
1157 }
1158
1159 gboolean
1160 edsio_property_bytes_setter (gpointer obj, EdsioProperty* prop, guint8* set, guint32 set_len)
1161 {
1162   EdsioPropertyEntry *ent = g_new (EdsioPropertyEntry, 1);
1163
1164   ent->as_bytes.val = set;
1165   ent->as_bytes.val_len = set_len;
1166
1167   return edsio_property_set (obj, prop, ent);
1168 }
1169
1170 void
1171 edsio_property_bytes_free (gpointer obj)
1172 {
1173   g_free (obj);
1174 }
1175
1176 /* Vptr
1177  */
1178
1179 gboolean
1180 edsio_property_vptr_getter (gpointer obj, EdsioProperty* prop, void** get)
1181 {
1182   if (! ((*get) = edsio_property_get (obj, prop)))
1183     return FALSE;
1184
1185   return TRUE;
1186 }
1187
1188 gboolean
1189 edsio_property_vptr_setter (gpointer obj, EdsioProperty* prop, void* set)
1190 {
1191   return edsio_property_set (obj, prop, (EdsioPropertyEntry*) set);
1192 }
1193
1194 void
1195 edsio_property_vptr_free (gpointer obj)
1196 {
1197   /* nothing */
1198 }
1199
1200 /* Testing
1201  */
1202
1203 #ifdef DEBUG_LIBEDSIO
1204
1205 GHashTable**
1206 edsio_proptest_property_table (PropTest *pt)
1207 {
1208   return & pt->_edsio_property_table;
1209 }
1210
1211 SerialSource*
1212 edsio_persist_proptest_source (PropTest *pt, const char* prop_name)
1213 {
1214   GByteArray* array;
1215
1216   if (! pt->ptable)
1217     {
1218       g_warning ("can't get persist property, no table\n");
1219       return NULL;
1220     }
1221
1222   if (! (array = g_hash_table_lookup (pt->ptable, prop_name)))
1223     {
1224       g_warning ("can't lookup persist property\n");
1225       return NULL;
1226     }
1227
1228   return edsio_simple_source (array->data, array->len, SBF_None);
1229 }
1230
1231 static void
1232 pt_success (gpointer data, GByteArray* result)
1233 {
1234   PropTest* pt = data;
1235
1236   GByteArray* old;
1237
1238   if (! pt->ptable)
1239     pt->ptable = g_hash_table_new (g_str_hash, g_str_equal);
1240
1241   old = g_hash_table_lookup (pt->ptable, (gpointer) pt->kludge);
1242
1243   if (old)
1244     g_byte_array_free (old, TRUE);
1245
1246   g_hash_table_insert (pt->ptable, (gpointer) pt->kludge, result);
1247 }
1248
1249 SerialSink*
1250 edsio_persist_proptest_sink   (PropTest *pt, const char* prop_name)
1251 {
1252   pt->kludge = prop_name;
1253
1254   return edsio_simple_sink (pt, SBF_None, FALSE, pt_success, NULL);
1255 }
1256
1257 gboolean
1258 edsio_persist_proptest_isset  (PropTest *pt, const char* prop_name)
1259 {
1260   if (! pt->ptable)
1261     return FALSE;
1262
1263   return g_hash_table_lookup (pt->ptable, prop_name) != NULL;
1264 }
1265
1266 gboolean
1267 edsio_persist_proptest_unset  (PropTest *pt, const char* prop_name)
1268 {
1269   GByteArray* old;
1270
1271   if (! pt->ptable)
1272     return FALSE;
1273
1274   old = g_hash_table_lookup (pt->ptable, prop_name);
1275
1276   if (old)
1277     {
1278       g_byte_array_free (old, TRUE);
1279       g_hash_table_remove (pt->ptable, prop_name);
1280       return TRUE;
1281     }
1282
1283   return FALSE;
1284 }
1285
1286 #endif
1287
1288 /* Misc source/sink stuff
1289  */
1290
1291 SerialSink*
1292 serializeio_gzip_sink (SerialSink* sink)
1293 {
1294   /* @@@ not implemented */
1295   return sink;
1296 }
1297
1298 SerialSource*
1299 serializeio_gzip_source (SerialSource* source)
1300 {
1301   /* @@@ not implemented */
1302   return source;
1303 }
1304
1305 /* Checksum sink
1306  */
1307 typedef struct _ChecksumSink ChecksumSink;
1308
1309 static gboolean checksum_sink_close (SerialSink* sink);
1310 static gboolean checksum_sink_write (SerialSink* sink, const guint8 *ptr, guint32 len);
1311 static void     checksum_sink_free (SerialSink* sink);
1312 static gboolean checksum_sink_quantum (SerialSink* sink);
1313
1314 struct _ChecksumSink
1315 {
1316   SerialSink sink;
1317
1318   SerialSink* out;
1319
1320   EdsioMD5Ctx ctx;
1321   guint8      md5[16];
1322   gboolean    md5_done;
1323   gboolean    md5_written;
1324 };
1325
1326 SerialSink*
1327 serializeio_checksum_sink   (SerialSink* out)
1328 {
1329   ChecksumSink* it = g_new0 (ChecksumSink, 1);
1330   SerialSink* sink = (SerialSink*) it;
1331
1332   serializeio_sink_init (sink,
1333                          NULL,
1334                          checksum_sink_close,
1335                          checksum_sink_write,
1336                          checksum_sink_free,
1337                          checksum_sink_quantum);
1338
1339   it->out = out;
1340
1341   edsio_md5_init (& it->ctx);
1342
1343   return sink;
1344 }
1345
1346 gboolean
1347 checksum_sink_write (SerialSink* fsink, const guint8 *ptr, guint32 len)
1348 {
1349   ChecksumSink* sink = (ChecksumSink*) fsink;
1350
1351   if (! sink->out->sink_write (sink->out, ptr, len))
1352     return FALSE;
1353
1354   edsio_md5_update (& sink->ctx, ptr, len);
1355
1356   return TRUE;
1357 }
1358
1359 gboolean
1360 checksum_sink_close (SerialSink* fsink)
1361 {
1362   ChecksumSink* sink = (ChecksumSink*) fsink;
1363
1364   if (! sink->md5_done)
1365     {
1366       edsio_md5_final (sink->md5, & sink->ctx);
1367       sink->md5_done = TRUE;
1368     }
1369
1370   if (! sink->out->sink_write (sink->out, sink->md5, 16))
1371     return FALSE;
1372
1373   if (! sink->out->sink_close (sink->out))
1374     return FALSE;
1375
1376   return TRUE;
1377 }
1378
1379 void
1380 checksum_sink_free (SerialSink* fsink)
1381 {
1382   ChecksumSink* sink = (ChecksumSink*) fsink;
1383
1384   sink->out->sink_free (sink->out);
1385
1386   g_free (sink);
1387 }
1388
1389 gboolean
1390 checksum_sink_quantum (SerialSink* fsink)
1391 {
1392   ChecksumSink* sink = (ChecksumSink*) fsink;
1393
1394   if (sink->out->sink_quantum)
1395     return sink->out->sink_quantum (sink->out);
1396
1397   return TRUE;
1398 }
1399
1400 /* Checksum source
1401  */
1402
1403 typedef struct _ChecksumSource ChecksumSource;
1404
1405 struct _ChecksumSource {
1406   SerialSource source;
1407
1408   SerialSource *in;
1409
1410   EdsioMD5Ctx ctx;
1411 };
1412
1413 static gboolean     checksum_source_close        (SerialSource* source);
1414 static gboolean     checksum_source_read         (SerialSource* source, guint8 *ptr, guint32 len);
1415 static void         checksum_source_free         (SerialSource* source);
1416
1417 SerialSource*
1418 serializeio_checksum_source (SerialSource* in0)
1419 {
1420   ChecksumSource* it = g_new0 (ChecksumSource, 1);
1421   SerialSource* source = (SerialSource*) it;
1422
1423   serializeio_source_init (source,
1424                            NULL,
1425                            checksum_source_close,
1426                            checksum_source_read,
1427                            checksum_source_free,
1428                            NULL,
1429                            NULL);
1430
1431   it->in = in0;
1432
1433   edsio_md5_init (& it->ctx);
1434
1435   return source;
1436 }
1437
1438 gboolean
1439 checksum_source_close (SerialSource* fsource)
1440 {
1441   ChecksumSource* source = (ChecksumSource*) fsource;
1442   guint8 buf1[16];
1443   guint8 buf2[16];
1444
1445   if (! source->in->source_read (source->in, buf1, 16))
1446     return FALSE;
1447
1448   edsio_md5_final (buf2, & source->ctx);
1449
1450   if (memcmp (buf1, buf2, 16) != 0)
1451     {
1452       edsio_generate_void_event (EC_EdsioInvalidStreamChecksum);
1453       return FALSE;
1454     }
1455
1456   if (! source->in->source_close (source->in))
1457     return FALSE;
1458
1459   return TRUE;
1460 }
1461
1462 gboolean
1463 checksum_source_read (SerialSource* fsource, guint8 *ptr, guint32 len)
1464 {
1465   ChecksumSource* source = (ChecksumSource*) fsource;
1466
1467   if (! source->in->source_read (source->in, ptr, len))
1468     return FALSE;
1469
1470   edsio_md5_update (& source->ctx, ptr, len);
1471
1472   return TRUE;
1473 }
1474
1475 void
1476 checksum_source_free (SerialSource* fsource)
1477 {
1478   ChecksumSource* source = (ChecksumSource*) fsource;
1479
1480   source->in->source_free (source->in);
1481
1482   g_free (source);
1483 }
1484
1485 /* Missing glib stuff
1486  */
1487
1488 GQueue *
1489 g_queue_new (void)
1490 {
1491   GQueue *q = g_new (GQueue, 1);
1492
1493   q->list = q->list_end = NULL;
1494   q->list_size = 0;
1495
1496   return q;
1497 }
1498
1499
1500 void
1501 g_queue_free (GQueue *q)
1502 {
1503   if (q)
1504     {
1505       if (q->list)
1506         g_list_free (q->list);
1507       g_free (q);
1508     }
1509 }
1510
1511
1512 guint
1513 g_queue_get_size (GQueue *q)
1514 {
1515   return (q == NULL) ? 0 : q->list_size;
1516 }
1517
1518
1519 void
1520 g_queue_push_front (GQueue *q, gpointer data)
1521 {
1522   if (q)
1523     {
1524       q->list = g_list_prepend (q->list, data);
1525
1526       if (q->list_end == NULL)
1527         q->list_end = q->list;
1528
1529       q->list_size++;
1530     }
1531 }
1532
1533
1534 void
1535 g_queue_push_back (GQueue *q, gpointer data)
1536 {
1537   if (q)
1538     {
1539       q->list_end = g_list_append (q->list_end, data);
1540
1541       if (! q->list)
1542         q->list = q->list_end;
1543       else
1544         q->list_end = q->list_end->next;
1545
1546       q->list_size++;
1547     }
1548 }
1549
1550
1551 gpointer
1552 g_queue_pop_front (GQueue *q)
1553 {
1554   gpointer data = NULL;
1555
1556   if ((q) && (q->list))
1557     {
1558       GList *node;
1559
1560       node = q->list;
1561       data = node->data;
1562
1563       if (! node->next)
1564         {
1565           q->list = q->list_end = NULL;
1566           q->list_size = 0;
1567         }
1568       else
1569         {
1570           q->list = node->next;
1571           q->list->prev = NULL;
1572           q->list_size--;
1573         }
1574
1575       g_list_free_1 (node);
1576     }
1577
1578   return data;
1579 }
1580
1581
1582 gpointer
1583 g_queue_pop_back (GQueue *q)
1584 {
1585   gpointer data = NULL;
1586
1587   if ((q) && (q->list))
1588     {
1589       GList *node;
1590
1591       node = q->list_end;
1592       data = node->data;
1593
1594       if (! node->prev)
1595         {
1596           q->list = q->list_end = NULL;
1597           q->list_size = 0;
1598         }
1599       else
1600         {
1601           q->list_end = node->prev;
1602           q->list_end->next = NULL;
1603           q->list_size--;
1604         }
1605
1606       g_list_free_1 (node);
1607     }
1608
1609   return data;
1610 }