Logo Search packages:      
Sourcecode: uget version File versions  Download package

ug_dataset.c

/*
 *
 *   Copyright (C) 2005-2009 by Raymond Huang
 *   plushuang at users.sourceforge.net
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *  ---
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of portions of this program with the
 *  OpenSSL library under certain conditions as described in each
 *  individual source file, and distribute linked combinations
 *  including the two.
 *  You must obey the GNU Lesser General Public License in all respects
 *  for all of the code used other than OpenSSL.  If you modify
 *  file(s) with this exception, you may extend this exception to your
 *  version of the file(s), but you are not obligated to do so.  If you
 *  do not wish to do so, delete this exception statement from your
 *  version.  If you delete this exception statement from all source
 *  files in the program, then also delete it here.
 *
 */

#include <stdlib.h>
#include <string.h>
#include <memory.h>

#include <ug_dataset.h>
#include <ug_class.h>
#include <ug_data_download.h> // for backward compatible


// ----------------------------------------------------------------------------
// UgDataset

static void ug_dataset_init         (UgDataset* dataset);
static void ug_dataset_finalize     (UgDataset* dataset);
static void ug_dataset_assign (UgDataset* dataset, UgDataset* src);
static void ug_datapair_in_markup (UgDataset* dataset, GMarkupParseContext* context);
static void ug_datapair_to_markup (UgDataset* dataset, UgMarkup* markup);

static UgDataEntry      dataset_entry[] =
{
      {"DataPair",            0,    UG_DATA_TYPE_CUSTOM,    (UgInMarkupFunc) ug_datapair_in_markup,   (UgToMarkupFunc) ug_datapair_to_markup},
      {NULL}
};

static UgDataClass      dataset_class =
{
      "dataset",                    // name
      NULL,                         // reserve
      sizeof (UgDataset),           // instance_size
      dataset_entry,                // entry

      (UgInitFunc)            ug_dataset_init,
      (UgFinalizeFunc)  ug_dataset_finalize,
      (UgAssignFunc)          ug_dataset_assign,
};

// extern
const UgDataClass*      UgDatasetClass = &dataset_class;


static void ug_dataset_init   (UgDataset* dataset)
{
      ug_dataset_alloc_list (dataset, UgDataCommonClass);               // 0
      ug_dataset_alloc_list (dataset, UgDataProxyClass);                // 1
      ug_dataset_alloc_list (dataset, UgProgressClass);                 // 2
      ug_dataset_alloc_list (dataset, NULL);    // UgDataAppClass // 3
}

static void ug_dataset_finalize (UgDataset* dataset)
{
      guint index;

      for (index=0; index < dataset->pair_len; index++)
            ug_data_list_free (dataset->pair[index].value);
      g_free (dataset->pair);

      if (dataset->destroy_func) {
            dataset->destroy_func (dataset->destroy_data);
            dataset->destroy_func = NULL;
            dataset->destroy_data = NULL;
      }
}

static void ug_dataset_assign (UgDataset* dataset, UgDataset* src)
{
      guint index;

      if (src->pair) {
            dataset->pair = g_malloc0 (sizeof (UgDataPair) * src->pair_alloc_len);
            dataset->pair_len = src->pair_len;
            dataset->pair_alloc_len = src->pair_alloc_len;
            for (index = 0;  index < src->pair_len;  index++) {
                  dataset->pair[index].key   = src->pair[index].key;
                  dataset->pair[index].value = ug_data_list_copy (src->pair[index].value);
            }
      }
}

// Gets the element at the given position in a list.
gpointer    ug_dataset_get    (UgDataset* dataset, const UgDataClass* data_class, guint nth)
{
      UgData**    list;

      list = ug_dataset_get_list (dataset, data_class);
      if (list == NULL)
            return NULL;

      return ug_data_list_nth (*list, nth);
}

void  ug_dataset_remove (UgDataset* dataset, const UgDataClass* data_class, guint nth)
{
      UgData**    list;
      UgData*           link;

      list = ug_dataset_get_list (dataset, data_class);
      if (list == NULL || *list == NULL)
            return;

      if (nth == 0) {
            link  = *list;
            *list = link->next;
      }
      else
            link = ug_data_list_nth (*list, nth);

      if (link) {
            ug_data_list_unlink (link);
            ug_data_free (link);
      }
}

// If nth instance of data_class exist, return nth instance.
// If nth instance of data_class not exist, alloc new instance in tail and return it.
gpointer    ug_dataset_realloc (UgDataset* dataset, const UgDataClass* data_class, guint nth)
{
      UgData**    list;
      UgData*           link;
      guint       index;

//    assert (data_class != NULL);

      list = ug_dataset_get_list (dataset, data_class);
      if (list == NULL)
            list = ug_dataset_alloc_list (dataset, data_class);

      if (*list == NULL) {
            *list = ug_data_new (data_class);
            return *list;
      }

      for (link = *list, index = 0;  ;  index++) {
            if (index == nth)
                  return link;

            if (link->next == NULL) {
                  link->next = ug_data_new (data_class);
                  link->next->prev = link;
                  return link->next;
            }
            link = link->next;
      }
}

gpointer    ug_dataset_alloc_front (UgDataset* dataset, const UgDataClass* data_class)
{
      UgData**    list;
      UgData*           link;

//    assert (data_class != NULL);

      list = ug_dataset_get_list (dataset, data_class);
      if (list == NULL)
            list = ug_dataset_alloc_list (dataset, data_class);

      link = ug_data_new (data_class);
      *list = ug_data_list_prepend (*list, link);

      return link;
}

gpointer    ug_dataset_alloc_back  (UgDataset* dataset, const UgDataClass* data_class)
{
      UgData**    list;
      UgData*           link;

//    assert (data_class != NULL);

      list = ug_dataset_get_list (dataset, data_class);
      if (list == NULL)
            list = ug_dataset_alloc_list (dataset, data_class);

      link  = ug_data_new (data_class);
      *list = ug_data_list_append (*list, link);

      return link;
}


// ----------------------------------------------
// UgDataset list functions
guint ug_dataset_list_length (UgDataset* dataset, const UgDataClass* data_class)
{
      UgData**    list;

      list = ug_dataset_get_list (dataset, data_class);
      return ug_data_list_length (*list);
}

UgData**    ug_dataset_alloc_list (UgDataset* dataset, const UgDataClass* data_class)
{
      UgDataPair* pair;

      if (dataset->pair_len == dataset->pair_alloc_len) {
            dataset->pair_alloc_len += 8;
            dataset->pair = g_realloc (dataset->pair, sizeof (UgDataPair) * dataset->pair_alloc_len);
      }
      pair        = dataset->pair + dataset->pair_len;
      pair->key   = data_class;
      pair->value = NULL;
      dataset->pair_len++;

      return &pair->value;
}

UgData**    ug_dataset_get_list (UgDataset* dataset, const UgDataClass* data_class)
{
      guint index;

      for (index=0; index < dataset->pair_len; index++) {
            if (dataset->pair[index].key == data_class)
                  return &dataset->pair[index].value;
      }

      return NULL;
}

// free old list in dataset and set list with new_list.
void  ug_dataset_set_list (UgDataset* dataset, const UgDataClass* data_class, gpointer new_list)
{
      UgData**    list;
      UgData*           old_list;

      list = ug_dataset_get_list (dataset, data_class);
      if (list == NULL)
            list = ug_dataset_alloc_list (dataset, data_class);

      old_list = *list;
      *list = new_list;
      ug_data_list_free (old_list);
}

// free old list in dataset and copy src_list to dataset.
void  ug_dataset_copy_list (UgDataset* dataset, const UgDataClass* data_class, gpointer src_list)
{
      ug_dataset_set_list (dataset, data_class, ug_data_list_copy (src_list));
}

// Cuts the element at the given position in a list.
gpointer    ug_dataset_cut_list (UgDataset* dataset, const UgDataClass* data_class, guint nth)
{
      UgData**    list;
      UgData*           link;

      list = ug_dataset_get_list (dataset, data_class);
      if (list == NULL)
            return NULL;

      if (nth == 0) {
            link = *list;
            *list = NULL;
      }
      else {
            // nth > 0
            link = ug_data_list_nth (*list, nth);
            if (link) {
                  UG_DATA_CAST (link)->prev->next = NULL;
                  UG_DATA_CAST (link)->prev = NULL;
            }
      }

      return link;
}

// ----------------------------------------------------------------------------
// UgMarkup input/output
static void ug_datapair_parser_start_element (GMarkupParseContext*      context,
                                              const gchar*        element_name,
                                              const gchar**       attr_names,
                                              const gchar**       attr_values,
                                              UgDataset*          dataset,
                                              GError**                  error);

static GMarkupParser    ug_datapair_parser =
{
      (gpointer) ug_datapair_parser_start_element,
      (gpointer) g_markup_parse_context_pop,
      NULL,
      NULL,
      NULL
};

static void ug_datapair_in_markup (UgDataset* dataset, GMarkupParseContext* context)
{
      g_markup_parse_context_push (context, &ug_datapair_parser, dataset);
}

static void ug_datapair_to_markup (UgDataset* dataset, UgMarkup* markup)
{
      const UgDataClass*      data_class;
      UgData*                       datalist;
      guint                   index;

      for (index=0; index < dataset->pair_len; index++) {
            datalist = ug_data_list_last (dataset->pair[index].value);
            for (;  datalist;  datalist = datalist->prev) {
                  data_class = datalist->data_class;
                  ug_markup_output_element_start (markup, "class name='%s'", data_class->name);
                  ug_data_to_markup (datalist, markup);
                  ug_markup_output_element_end   (markup, "class");
            }
      }
} 

static void ug_datapair_parser_start_element (GMarkupParseContext*      context,
                                              const gchar*        element_name,
                                              const gchar**       attr_names,
                                              const gchar**       attr_values,
                                              UgDataset*          dataset,
                                              GError**                  error)
{
      const UgDataClass*      data_class;
      UgData*                       datalist;
      guint                   index;

      if (strcmp (element_name, "class") != 0)
            return;

      for (index=0; attr_names[index]; index++) {
            if (strcmp (attr_names[index], "name") != 0)
                  continue;

            // find registered data class (UgDataClass)
            data_class = ug_data_class_find (attr_values[index]);
            if (data_class) {
                  // Create new instance by UgDataClass and add it to list.
                  datalist = ug_dataset_realloc (dataset, data_class, 0);
                  g_markup_parse_context_push (context, &ug_data_parser, datalist);
            }
            else {
                  // Skip unregistered class, don't parse anything.
                  g_markup_parse_context_push (context, &ug_markup_skip_parser, GINT_TO_POINTER (6));
            }
            break;
      }
}

// ----------------------------------------------
// for backward compatible
static void ug_dataset_parser_start_element (GMarkupParseContext* context,
                                             const gchar*         element_name,
                                             const gchar**        attr_names,
                                             const gchar**        attr_values,
                                             UgDataset*                 dataset,
                                             GError**             error);

GMarkupParser     ug_dataset_parser =
{
      (gpointer) ug_dataset_parser_start_element,
      (gpointer) g_markup_parse_context_pop,
      NULL,
      NULL,
      NULL
};


void  ug_dataset_in_markup (UgDataset** dataset, GMarkupParseContext* context)
{
      if (*dataset)
            g_markup_parse_context_push (context, &ug_dataset_parser, *dataset);
      else
            g_markup_parse_context_push (context, &ug_markup_skip_parser, GINT_TO_POINTER (6));
}

void  ug_dataset_to_markup (UgDataset** dataset, UgMarkup* markup)
{
      if (*dataset)
            ug_data_to_markup ((UgData*) *dataset, markup);
}

static void ug_dataset_parser_start_element (GMarkupParseContext* context,
                                             const gchar*         element_name,
                                             const gchar**        attr_names,
                                             const gchar**        attr_values,
                                             UgDataset*                 dataset,
                                             GError**             error)
{
      const UgDataClass*      uclass;
      const UgDataEntry*      entry;
      const gchar*            src;
      UgData*                       data;
      gpointer                dest;
      guint                   index;


      entry = UgDataCommonClass->entry;
      src   = NULL;

      if (strcmp (element_name, "DataPair") == 0) {
            g_markup_parse_context_push (context, &ug_datapair_parser, dataset);
            return;
      }
      if (strcmp (element_name, "AppData") == 0) {
            uclass = ug_data_class_find ("AppData");
            if (uclass) {
                  data = ug_dataset_realloc (dataset, uclass, 0);
                  g_markup_parse_context_push (context, &ug_data_parser, data);
            }
            else
                  g_markup_parse_context_push (context, &ug_markup_skip_parser, GINT_TO_POINTER (6));
            return;
      }

      for (; ; entry++) {
            if (entry->name == NULL) {
                  // don't parse anything.
                  g_markup_parse_context_push (context, &ug_markup_skip_parser, GINT_TO_POINTER (6));
                  return;
            }

            if (strcmp (entry->name, element_name) != 0)
                  continue;

            for (index=0; attr_names[index]; index++) {
                  if (strcmp (attr_names[index], "value") == 0) {
                        src = attr_values[index];
                        break;
                  }
            }
            data = ug_dataset_realloc (dataset, UgDataCommonClass, 0);
            dest = ((guint8*) data) + entry->offset;

            switch (entry->type) {
            case UG_DATA_TYPE_STRING:
                  if (src)
                        *(gchar**) dest = g_strdup (src);
                  break;

            case UG_DATA_TYPE_INT:
                  if (src)
                        *(gint*) dest = atoi (src);
                  break;

            default:
                  break;
            }

            // skip end_element() one times.
            g_markup_parse_context_push (context, &ug_markup_skip_parser, GINT_TO_POINTER (0));
            break;
      }
}


Generated by  Doxygen 1.6.0   Back to index