home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / libgimp / gserialize.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-17  |  7.3 KB  |  274 lines

  1. /* gserialize.h
  2.  * Copyright (C) 1998 Jay Cox <jaycox@earthlink.net>
  3.  *
  4.  * This library is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU Lesser General Public
  6.  * License as published by the Free Software Foundation; either
  7.  * version 2 of the License, or (at your option) any later version.
  8.  *
  9.  * This library is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.  * Library General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU Lesser General Public
  15.  * License along with this library; if not, write to the
  16.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  17.  * Boston, MA 02111-1307, USA.
  18.  */
  19.  
  20. #include <string.h>
  21.  
  22. #include "gserialize.h"
  23.  
  24. struct _GSerialDescription
  25. {
  26.   char *struct_name;
  27.   GSList *list;
  28. };
  29.  
  30.  
  31. struct _GSerialItem
  32. {
  33.   GSerialType type;          /* the type of this data member                 */
  34.   gulong      offset;        /* the offset into the struct of this item      */
  35.   glong       length;        /* the number of elements (if this is an array) */
  36.                      /* or -1 if this is a variable length array     */
  37.   gulong      length_offset; /* offset to the length of the array            */
  38. };
  39.  
  40. #define g_serial_copy_from_n g_serial_copy_to_n
  41.  
  42. static long g_serial_copy_to_n(char *dest, char *source, long data_size,
  43.                    long n_items)
  44. {
  45.   int i;
  46.   int length = n_items*data_size;
  47. #if G_BYTE_ORDER == G_BIG_ENDIAN
  48.   memcpy(dest, source, length);
  49. #else
  50.   switch (data_size)
  51.   {
  52.    case 1: memcpy(dest, source, n_items);
  53.      break;
  54.    case 2: 
  55.      for (i = 0; i < length; i+=2)
  56.      {
  57.        dest[i]   = source[i + 1];
  58.        dest[i+1] = source[i];
  59.      } break;
  60.    case 4: 
  61.      for (i = 0; i < length; i+=4)
  62.      {
  63.        dest[i]   = source[i + 3];
  64.        dest[i+1] = source[i + 2];
  65.        dest[i+2] = source[i + 1];
  66.        dest[i+3] = source[i];
  67.      } break;
  68.    case 8: 
  69.      for (i = 0; i < length; i+=8)
  70.      {
  71.        dest[i]   = source[i+7];
  72.        dest[i+1] = source[i+6];
  73.        dest[i+2] = source[i+5];
  74.        dest[i+3] = source[i+4];
  75.        dest[i+4] = source[i+3];
  76.        dest[i+5] = source[i+2];
  77.        dest[i+6] = source[i+1];
  78.        dest[i+7] = source[i];
  79.      } break;
  80.    default:
  81.      g_assert_not_reached();
  82.   }
  83. #endif /* G_BYTE_ORDER != G_BIG_ENDIAN */
  84.   return length;
  85. }
  86.  
  87. GSerialItem *g_new_serial_item(GSerialType type, gulong offset,
  88.                    gint32 length, gulong length_offset)
  89. {
  90.   GSerialItem *item = g_new(GSerialItem, 1);
  91.   item->type          = type;
  92.   item->offset        = offset;
  93.   item->length        = length;
  94.   item->length_offset = length_offset;
  95.   return item;
  96. }
  97.  
  98. GSerialDescription *g_new_serial_description(char *name, ...)
  99. {
  100.   va_list argp;
  101.   void *tmp;
  102.   GSerialDescription *d = g_new(GSerialDescription, 1);
  103.  
  104.   d->struct_name = g_strdup(name);
  105.   d->list = 0;
  106.  
  107.   va_start(argp, name);
  108.   while ((tmp =  va_arg (argp, void*)))
  109.     d->list = g_slist_append(d->list, tmp);
  110.   va_end(argp);
  111.   return d;
  112. }
  113.  
  114. void g_free_serial_description(GSerialDescription *d)
  115. {
  116.   g_free (d->struct_name);
  117.   while (d->list)
  118.   {
  119.     g_free(d->list->data);
  120.     d->list = g_slist_remove_link(d->list, d->list);
  121.   }
  122.   g_free (d);
  123. }
  124.  
  125. static int g_serial_item_is_array(GSerialItem *item)
  126. {
  127.   if (item->type < GSERIAL_STRING)
  128.     return 0;
  129.   return 1;
  130. }
  131.  
  132. static long g_serial_item_data_size(GSerialItem *item)
  133. {
  134.   static long sizes[] = {0, 1, 2, 4, 4, 8, 1, 1, 2, 4, 4, 8};
  135.   if (item->type >= GSERIAL_STRING)
  136.     return sizes[item->type - 95];
  137.   return sizes[item->type];
  138. }
  139.  
  140. static long g_serial_item_n_items(GSerialItem *item, void *struct_data)
  141. {
  142.   if (item->type < GSERIAL_STRING)
  143.     return 1;
  144.   if (item->type == GSERIAL_STRING)
  145.     return (strlen(G_STRUCT_MEMBER(char*, struct_data, item->offset)) + 1);
  146.   if (item->length >= 0)
  147.     return item->length;
  148.   return (G_STRUCT_MEMBER(gint32, struct_data, item->length_offset));
  149. }
  150.  
  151. static long g_serial_item_compute_length(GSerialItem *item, void *struct_data)
  152. {
  153.   int length;
  154.   length = g_serial_item_n_items(item, struct_data) * g_serial_item_data_size(item);
  155.   length += g_serial_item_is_array(item) * 4;
  156.   return length + 1;
  157. }
  158.  
  159. static long g_serial_description_compute_length(GSerialDescription *d,
  160.                         void *struct_data)
  161. {
  162.   long length = 0;
  163.   GSList *list;
  164.   list = d->list;
  165.   while (list)
  166.   {
  167.     length += g_serial_item_compute_length((GSerialItem *) list->data, struct_data);
  168.     list = list->next;
  169.   }
  170.   return length;
  171. }
  172.  
  173. static long g_serial_item_serialize(GSerialItem *item, char *buffer,
  174.                     void *struct_data)
  175. {
  176.   char *buf = buffer;
  177.   gint32 tmp;
  178.   if (item->type >= GSERIAL_LAST_TYPE ||
  179.       (item->type > GSERIAL_DOUBLE && item->type < GSERIAL_STRING))
  180.   {
  181.     g_warning("Error serializing: Unknown serial item type.\n");
  182.     return 0;
  183.   }
  184.   *buf++ = item->type;
  185.   if (g_serial_item_is_array(item))
  186.   {
  187.     tmp = g_serial_item_n_items(item, struct_data);
  188.     buf += g_serial_copy_to_n(buf, (char *)&tmp, 4, 1);
  189.     buf += g_serial_copy_to_n(buf,
  190.                   G_STRUCT_MEMBER(char*, struct_data,item->offset),
  191.                   g_serial_item_data_size(item),
  192.                   tmp);
  193.   }
  194.   else
  195.   {
  196.     buf += g_serial_copy_to_n(buf,
  197.                   G_STRUCT_MEMBER_P(struct_data, item->offset),
  198.                   g_serial_item_data_size(item), 1);
  199.   }
  200.   return (buf - buffer);
  201. }
  202.  
  203. static long g_serial_item_deserialize(GSerialItem *item, void *struct_data, 
  204.                       char *buffer)
  205. {
  206.   char *buf = buffer;
  207.   gint32 n_items;
  208.   if (*buf != item->type)
  209.   {
  210.     g_warning("Error deserializing: item types do not match: %d vs %d.\n",
  211.           *buf, item->type);
  212.     return 0;
  213.   }
  214.   buf++;
  215.   if (g_serial_item_is_array(item))
  216.   {
  217.     buf += g_serial_copy_from_n((char *)&n_items, buf, 4, 1);
  218.     if (item->length < 0)
  219.       G_STRUCT_MEMBER(gint32, struct_data, item->length_offset) = n_items;
  220.     G_STRUCT_MEMBER(void*, struct_data, item->offset) 
  221.       = g_malloc(n_items*g_serial_item_data_size(item));
  222.     buf += g_serial_copy_from_n(G_STRUCT_MEMBER(void *, struct_data,
  223.                         item->offset),
  224.                 buf,
  225.                 g_serial_item_data_size(item),
  226.                 n_items);
  227.   }
  228.   else
  229.   {
  230.     buf += g_serial_copy_from_n(G_STRUCT_MEMBER_P(struct_data, item->offset),
  231.                 buf,
  232.                 g_serial_item_data_size(item),
  233.                 1);
  234.   }
  235.   return (buf - buffer);
  236. }
  237.  
  238. long g_serialize(GSerialDescription *d,  void **output, void *struct_data)
  239. {
  240.   int length = g_serial_description_compute_length(d, struct_data);
  241.   char *outbuf;
  242.   GSList *list;
  243.   long item_length;
  244.   outbuf = (char *)g_malloc(length);
  245.   *output = outbuf;
  246.  
  247.   list = d->list;
  248.   while (list)
  249.   {
  250.     item_length = g_serial_item_serialize((GSerialItem *)list->data, outbuf,
  251.                       struct_data);
  252.     if (item_length == 0)
  253.       g_error("Error serializing %s\n", d->struct_name);
  254.     outbuf += item_length;
  255.     list = list->next;
  256.   }
  257.   return length;
  258. }
  259.  
  260. long g_deserialize(GSerialDescription *d,  void *struct_data, void *serial)
  261. {
  262.   GSList *list;
  263.   char *in_buf = serial;
  264.   char *out_buf = struct_data;
  265.   list = d->list;
  266.   while (list)
  267.   {
  268.     in_buf += g_serial_item_deserialize((GSerialItem *)list->data, 
  269.                     out_buf, in_buf);
  270.     list = list->next;
  271.   }
  272.   return (in_buf - (char *)serial);
  273. }
  274.