You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@etch.apache.org by jd...@apache.org on 2009/04/22 19:25:51 UTC
svn commit: r767594 [17/43] - in /incubator/etch/trunk/binding-c/runtime/c:
./ ext/ ext/hashtab/ ext/lib/ inc/ lib/ project/ project/$etchstop/
project/bin/ project/etch/ project/logcli/ project/logsrv/ project/notes/
project/test/ project/test/logcli/...
Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etch_linklist.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etch_linklist.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etch_linklist.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etch_linklist.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,305 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * etch_linklist.c -- implementation of linklist.
+ */
+
+#include <stdio.h>
+#include "etch_linklist.h"
+#include "etchmem.h"
+
+
+
+/**
+ * new_linkist()
+ * constructor for an etch_linklist.
+ * Creates the underlying list and returns a pointer to the list.
+ */
+etch_linklist* new_linklist()
+{
+ etch_linklist* list = etch_malloc(sizeof(etch_linklist), ETCHTYPEB_COLLECTION);
+ memset(list, 0, sizeof(etch_linklist));
+ return list;
+}
+
+
+/*
+ * linklist_clear()
+ * remove all content from the arraylist, freeing bucket memory always,
+ * and content memory if requested.
+ */
+void linklist_clear(etch_linklist* list, const int is_free_content)
+{
+ linklist_node *p = NULL, *nextp = NULL;
+ if (NULL == list) return;
+
+ for(p = list->head; p; p = nextp)
+ {
+ if (is_free_content && p->content)
+ etch_free(p->content);
+ nextp = p->next;
+ free(p);
+ }
+
+ memset(list, 0, sizeof(etch_linklist));
+}
+
+
+/**
+ * linklist_destroy()
+ * Destructor for an etch_linklist.
+ * Destroys the underlying list, the list shell, and the list content if requested.
+ */
+void linklist_destroy(etch_linklist* list, const int is_free_content)
+{
+ if (NULL == list) return;
+ linklist_clear(list, is_free_content);
+ etch_free(list);
+}
+
+
+/*
+ * linklist_add()
+ * add a node to the end of the list, returning the new node's index
+ */
+int linklist_add(etch_linklist* list, void* content)
+{
+ linklist_node* node = NULL;
+ if (NULL == list) return -1;
+
+ node = etch_malloc(sizeof(linklist_node), ETCHTYPEB_LINKLIST);
+ node->content = content;
+
+ if (list->head == NULL) /* first entry? */
+ list->head = node;
+ else
+ { assert(list->tail);
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+ return ++list->count;
+}
+
+
+/*
+ * linklist_insert()
+ * add a node anywhere in the list, returning the new node's index,
+ * or -1 if a parameter was in error.
+ * this implementation cannot insert past the current end of list,
+ * in other words to insert at index n, there must be at least n
+ * entries currently in the list.
+ */
+int linklist_insert(etch_linklist* list, const unsigned int i, void* content)
+{
+ unsigned count = 0;
+ linklist_node* newnode = NULL, *p = NULL, *priorp = NULL;
+ if ((NULL == list) || (i > list->count) || (i < 0)) return -1;
+
+ newnode = etch_malloc(sizeof(linklist_node), ETCHTYPEB_LINKLIST);
+ newnode->content = content;
+ p = priorp = list->head;
+
+ if (list->head == NULL)
+ list->head = list->tail = newnode;
+ else
+ if (i == list->count)
+ list->tail->next = list->tail = newnode;
+ else
+ { for(p = list->head; p, count < i; p = p->next, count++)
+ priorp = p;
+
+ newnode->next = priorp->next;
+ priorp->next = newnode;
+ }
+
+ ++list->count;
+ return i;
+}
+
+
+/*
+ * linklist_moveto()
+ * private method to move to an indicated index in the list.
+ * returns the index moved to, or -1 if a parameter was in error.
+ * returns also in outp, a pointer to the node at the requested position.
+ */
+int linklist_moveto(etch_linklist* list, const unsigned startat, const linklist_node** outp)
+{
+ unsigned count = 0;
+ linklist_node* p = NULL;
+ if ((NULL == list) || (startat > list->count) || (startat < 0)) return -1;
+
+ for(p = list->head; p, count < startat; p = p->next, count++);
+ *outp = p;
+ return 0;
+}
+
+
+/*
+ * linklist_containsp()
+ * return 1 or 0 indicating if the list contains the supplied content pointer,
+ * or -1 if a parameter was in error.
+ */
+int linklist_containsp(etch_linklist* list, void* content, const unsigned startat)
+{
+ struct linklist_node *p = NULL;
+
+ if (-1 == linklist_moveto(list, startat, &p)) return -1;
+
+ for(; p; p = p->next)
+ if (p->content == content)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+/*
+ * linklist_indexofp()
+ * if the list contains the supplied content pointer, return its index;
+ * return -1 if not found or if a parameter was in error.
+ */
+int linklist_indexofp(etch_linklist* list, void* content, const unsigned startat)
+{
+ struct linklist_node *p = NULL;
+ int count = startat, foundat = -1;
+
+ if (-1 == linklist_moveto(list, startat, &p)) return -1;
+
+ for(; p; p = p->next)
+ {
+ if (p->content == content)
+ { foundat = count;
+ break;
+ }
+ else count++;
+ }
+
+ return foundat;
+}
+
+
+/*
+ * linklist_contains()
+ * return 1 or 0 indicating if the list contains the supplied content
+ * or -1 if a parameter was in error.
+ * caller must supply a comparator function of signature int f(void* this, void* that),
+ * which returns -1 if less, 0 if equal, 1 if greater.
+ */
+int linklist_contains(etch_linklist* list, void* content, const unsigned startat, etch_comparator compare)
+{
+ struct linklist_node *p = NULL;
+ int result = 0;
+
+ if (!list || !compare) return -1;
+ if (-1 == linklist_moveto(list, startat, &p)) return -1;
+
+ for(; p; p = p->next)
+ {
+ result = compare(content, p->content);
+ if (result == 0) return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * linklist_indexof()
+ * if the list contains the supplied content pointer, return its index.
+ * return -1 if a parameter was in error.
+ * caller must supply a comparator function of signature: int (*f)(void* this, void* that);
+ * which must return -1 if less, 0 if equal, 1 if greater.
+ */
+int linklist_indexof(etch_linklist* list, void* content, const unsigned startat, etch_comparator compare)
+{
+ struct linklist_node *p = NULL;
+ int result = 0, count = startat, foundat = -1;
+
+ if (!list || !compare) return -1;
+ if (-1 == linklist_moveto(list, startat, &p)) return -1;
+
+ for(; p; p = p->next)
+ {
+ result = compare(content, p->content);
+ if (result == 0)
+ { foundat = count;
+ break;
+ }
+ else count++;
+ }
+
+ return foundat;
+}
+
+
+/*
+ * linklist_get()
+ * return entry at specified index position, or NULL if parameter error.
+ * if we find the lists are not generally short, we'll supply an indexed version of this list,
+ * and/or implement a resizable array of pointers which we block memcpy to insert and delete.
+ */
+linklist_node* linklist_get(etch_linklist* list, const unsigned i)
+{
+ unsigned count = 0;
+ struct linklist_node *p = NULL;
+ if ((NULL == list) || (i >= list->count) || (i < 0)) return NULL;
+
+ for(p = list->head; p; p = p->next, count++)
+ if (count == i) return p;
+
+ return NULL; /* can't arrive here */
+}
+
+
+/*
+ * linklist_remove()
+ * remove entry at specified index position, free bucket memory; free content memory on request
+ * return -1 if a parameter was in error, or zero if OK.
+ */
+int linklist_remove(etch_linklist* list, const unsigned i, const int is_free_content)
+{
+ int priori = i - 1;
+ struct linklist_node *p = NULL, *priorp = NULL;
+ if (!list || (i >= list->count) || (i < 0)) return -1;
+
+ /* move to node prior to requested node */
+ if (-1 == linklist_moveto(list, priori, &priorp))
+ {
+ p = list->head; /* asked to remove node[0] */
+ list->head = p->next;
+ if (list->tail == p)
+ list->tail = NULL;
+ }
+ else
+ { p = priorp->next;
+ priorp->next = p->next;
+ if (list->tail == p)
+ list->tail = priorp;
+ }
+
+ if (is_free_content && p->content)
+ etch_free(p->content);
+
+ etch_free(p);
+ list->count--;
+ return 0;
+}
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etch_natarray.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etch_natarray.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etch_natarray.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etch_natarray.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,592 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * etch_natarray.c
+ * etch_nativearray implementation
+ * does allocation and subscripting for n-dimensional arrays stored as a single
+ * byte vector, to overcome the well-known C compiler issues with passing around
+ * multi dimensioned arrays when the low order dimension is not known at compile
+ * time. the mapping here from byte vector to array tests out as k&r compliant,
+ * this is verified by constructing from a static array using new_nativearray_from
+ * and testing that the get methods return the same result as statically indexed
+ * array items. as it stands, this code handles a max of 3 dimensions. it can be
+ * generalized to n dimensions, however the caller would have to allocate, populate,
+ * and pass arrays of subscripts for this to happen.
+ */
+
+#include <stdio.h>
+#include "etch_global.h"
+
+etch_nativearray* init_nativearray
+ (unsigned short, const size_t, const int, const int, const int, const int);
+int etch_nativearray_put1 (etch_nativearray*, void*, int);
+int etch_nativearray_put2 (etch_nativearray*, void*, int, int);
+int etch_nativearray_put3 (etch_nativearray*, void*, int, int, int);
+int etch_nativearray_get1 (etch_nativearray*, void*, int);
+int etch_nativearray_get2 (etch_nativearray*, void*, int, int);
+int etch_nativearray_get3 (etch_nativearray*, void*, int, int, int);
+int etch_nativearray_set_content_type(etch_nativearray*);
+
+
+/*
+ * new_nativearray()
+ * etch_nativearray constructor
+ * note that when creating arrays, the dimensions are passed low-order first,
+ * so for x[2][3][4], dim0 is 4, dim1 is 3, dim2 is 2. for y[7][9], dim0 is 9,
+ * dim1 is 7, and dim2 is zero of course.
+ */
+etch_nativearray* new_nativearray (unsigned short class_id, const size_t itemsize,
+ const int numdims, const int dim0, const int dim1, const int dim2)
+{
+ etch_nativearray* newarray = init_nativearray(class_id, itemsize, numdims, dim0, dim1, dim2);
+ if (NULL == newarray) return NULL;
+
+ newarray->values = etch_malloc(newarray->bytecount, ETCHTYPEB_BYTES);
+ memset(newarray->values, 0, newarray->bytecount);
+ newarray->is_content_owned = TRUE;
+
+ etch_nativearray_set_content_type(newarray);
+ return newarray;
+}
+
+
+/*
+ * new_nativearray_from()
+ * etch_nativearray constructor from existing byte vector
+ * @param values source array, caller retains ownership.
+ */
+etch_nativearray* new_nativearray_from (void* values, unsigned short class_id, const size_t itemsize,
+ const int numdims, const int dim0, const int dim1, const int dim2)
+{
+ etch_nativearray* newarray = init_nativearray(class_id, itemsize, numdims, dim0, dim1, dim2);
+ if (NULL == newarray) return NULL;
+
+ newarray->values = values;
+ newarray->is_content_owned = FALSE;
+
+ etch_nativearray_set_content_type(newarray);
+ return newarray;
+}
+
+
+/*
+ * new_nativearray_of()
+ * etch_nativearray constructor for array of objects of specified type and class
+ */
+etch_nativearray* new_nativearray_of
+ (unsigned short content_obj_type, unsigned short content_class_id,
+ const int numdims, const int dim0, const int dim1, const int dim2)
+{
+ etch_nativearray* newarray = init_nativearray
+ (CLASSID_ARRAY_OBJECT, sizeof(void*), numdims, dim0, dim1, dim2);
+ if (NULL == newarray) return NULL;
+
+ newarray->content_obj_type = content_obj_type;
+ newarray->content_class_id = content_class_id;
+ return newarray;
+}
+
+
+
+/*
+ * init_nativearray()
+ * etch_nativearray private constructor
+ * assumes max number of dimensions is 3
+ */
+etch_nativearray* init_nativearray (unsigned short class_id, const size_t itemsize,
+ const int numdims, const int dim0, const int dim1, const int dim2)
+{
+ etch_nativearray* newarray = NULL;
+ int i,j;
+ if (numdims < 1 || itemsize < 1) return NULL;
+ if (numdims > 1 && dim1 < 1) return NULL;
+ if (numdims > 2 && dim2 < 1) return NULL;
+
+ newarray = newarray = (etch_nativearray*) new_object
+ (sizeof(etch_nativearray), ETCHTYPEB_NATIVEARRAY, class_id);
+
+ newarray->numdims = numdims;
+ newarray->itemsize = itemsize;
+
+ /* dimension array contains the array dimensions,
+ * e.g., for x[2][3][4], [0] is 4, [1] is 3, [2] is 2
+ */
+ newarray->dimension[0] = dim0;
+ newarray->dimension[1] = numdims > 1? dim1: 0;
+ newarray->dimension[2] = numdims > 2? dim2: 0;
+
+ /* dimsize array contains size in bytes of the next lower dimension,
+ * stored so that the values need not be calculated on each array access.
+ * [0] is item size, so for int x[5][7][9], [0] is sizeof(int),
+ * [1] is 9*sizeof(int), [2] is 7*9*sizeof(int)
+ */
+ newarray->dimsize[0] = itemsize;
+ newarray->bytecount = itemsize * dim0;
+
+ for(i = 1, j = 0; i < numdims; i++, j++)
+ {
+ newarray->dimsize[i] = newarray->dimension[j] * newarray->dimsize[j];
+ newarray->bytecount *= newarray->dimension[i];
+ }
+
+ newarray->clone = clone_null;
+ newarray->destroy = destroy_nativearray;
+
+ newarray->put1 = etch_nativearray_put1;
+ newarray->put2 = etch_nativearray_put2;
+ newarray->put3 = etch_nativearray_put3;
+ newarray->get1 = etch_nativearray_get1;
+ newarray->get2 = etch_nativearray_get2;
+ newarray->get3 = etch_nativearray_get3;
+
+ return newarray;
+}
+
+
+/**
+ * destroy_nativearray_content()
+ * destroy nativearray's content vector.
+ * return -1 if content not owned by nativearray and therefore not destroyed;
+ * otherwise return zero, regardless of whether content was null.
+ */
+int destroy_nativearray_content(etch_nativearray* a)
+{
+ int result = 0;
+ if (!is_etchobj_static_content(a) && a->is_content_owned)
+ etch_free(a->values); /* OK if values null */
+ else result = -1;
+ return result;
+}
+
+
+/**
+ * destroy_nativearray()
+ * etch_nativearray destructor
+ */
+int destroy_nativearray(etch_nativearray* a)
+{
+ if (a->refcount > 0 && --a->refcount > 0) return -1;
+ if (a->is_content_owned && !is_etchobj_static_content(a))
+ destroy_nativearray_content(a);
+ destroy_objectex((objmask*)a);
+ return 0;
+}
+
+
+/*
+ * new_subarray()
+ * construct and return subaarray[i] of this array.
+ * subarray points into parent content and so does not own its content
+ */
+etch_nativearray* new_subarray(etch_nativearray* a, const int i)
+{
+ etch_nativearray* subarray = NULL;
+ const int sub_numdims = a->numdims - 1;
+
+ if (a->numdims > 1 && i < (int) a->dimension[sub_numdims])
+ {
+ const size_t sub_bytelen = a->dimsize[sub_numdims];
+ const size_t vector_offset = i * sub_bytelen;
+ byte* subvector = (byte*) a->values + vector_offset;
+
+ subarray = new_nativearray_from(subvector,
+ a->class_id, (int) a->itemsize, sub_numdims,
+ (int) a->dimension[0], (int) a->dimension[1], 0);
+
+ subarray->bytecount = sub_bytelen;
+ subarray->content_obj_type = a->content_obj_type;
+ subarray->content_class_id = a->content_class_id;
+ subarray->is_content_owned = a->is_content_owned;
+
+ subarray->counts[0] = a->counts[0]; /* user-maintained counts */
+ subarray->counts[1] = a->counts[1];
+ subarray->counts[2] = 0;
+ }
+
+ return subarray;
+}
+
+
+/*
+ * etch_nativearray_assign_to()
+ * assign array b to array a, if legal to do so.
+ */
+etch_nativearray* etch_nativearray_assign_to(etch_nativearray* a, etch_nativearray* b)
+{
+ if (!is_etch_nativearray(a) || !is_etch_nativearray(b)) return NULL;
+
+ /* arrays must be either of same type, or the left side an array of
+ * object; and the dimensionalities of the two arrays must be the same.
+ */
+ if(((a->class_id != b->class_id) && (a->class_id != CLASSID_ARRAY_OBJECT))
+ || (a->numdims != b->numdims))
+ return NULL;
+
+ destroy_nativearray_content(a); /* destroy a content if owned */
+
+ a->values = b->values; /* assign b content to a */
+ a->itemsize = b->itemsize;
+ a->bytecount = b->bytecount;
+ memcpy(a->dimension, b->dimension, sizeof(a->dimension));
+ memcpy(a->dimsize, b->dimsize, sizeof(a->dimsize));
+ memcpy(a->counts, b->counts, sizeof(a->counts));
+ a->content_obj_type = b->content_obj_type;
+ a->content_class_id = b->content_class_id;
+ a->is_content_owned = FALSE; /* b still owns array content */
+ a->is_copy = TRUE;
+ return a;
+}
+
+
+/*
+ * etch_nativearray_get_element()
+ * return element[i] of specified array, which, if array is multi-dimensioned,
+ * will be another native array, otherwise an etch object. for example, if
+ * the supplied array is byte[2][4], a native array of byte[4] is returned.
+ * if the supplied array is byte[4], an etch_byte object is returned.
+ * returned subarrays do not own content, their content references the content
+ * of their parent.
+ */
+objmask* etch_nativearray_get_element(etch_nativearray* a, const int i)
+{
+ int result = 0;
+ objmask* wrapped_element = NULL;
+ etch_nativearray* subarray = NULL;
+
+ const int sub_numdims = a->numdims - 1;
+ if (sub_numdims < 0) return NULL;
+
+ if (sub_numdims > 0)
+ return (objmask*) new_subarray(a, i);
+
+ result = etch_nativearray_get_wrapped_component(a, i, &wrapped_element);
+
+ return wrapped_element;
+}
+
+
+/*
+ * etch_nativearray_set_content_type()
+ * set content_obj_type and content_class_id based on array class_id.
+ * returns zero if content type was set, otherwise -1
+ */
+int etch_nativearray_set_content_type(etch_nativearray* a)
+{
+ unsigned short obj_type = 0;
+ int result = 0;
+
+ switch(a->class_id)
+ {
+ case CLASSID_ARRAY_BYTE: obj_type = ETCHTYPEB_BYTE; break;
+ case CLASSID_ARRAY_BOOL: obj_type = ETCHTYPEB_BOOL; break;
+ case CLASSID_ARRAY_INT8: obj_type = ETCHTYPEB_INT8; break;
+ case CLASSID_ARRAY_INT16: obj_type = ETCHTYPEB_INT16; break;
+ case CLASSID_ARRAY_INT32: obj_type = ETCHTYPEB_INT32; break;
+ case CLASSID_ARRAY_INT64: obj_type = ETCHTYPEB_INT64; break;
+ case CLASSID_ARRAY_FLOAT: obj_type = ETCHTYPEB_IEEE32; break;
+ case CLASSID_ARRAY_DOUBLE: obj_type = ETCHTYPEB_IEEE64; break;
+ }
+
+ if (obj_type)
+ { a->content_obj_type = obj_type;
+ a->content_class_id = CLASSID_UNWRAPPED;
+ }
+ else switch(a->class_id)
+ {
+ case CLASSID_ARRAY_OBJECT:
+ a->content_obj_type = ETCHTYPEB_ETCHOBJECT;
+ a->content_class_id = CLASSID_OBJECT;
+ break;
+
+ case CLASSID_ARRAY_STRING:
+ a->content_obj_type = ETCHTYPEB_STRING;
+ a->content_class_id = CLASSID_STRING;
+ break;
+
+ default:
+ result = -1; /* indicates content type not set */
+ }
+
+ return result;
+}
+
+
+/**
+ * put1()
+ * insert item to singly dimensioned array
+ * array access can be generalized by passing an array of subscripts; however
+ * since we are currently handling max 3 dimensions, the calling sequence is
+ * much simpler when we have separate accessors for each dimensionality.
+ */
+int etch_nativearray_put1(etch_nativearray* a, void* value, int i)
+{
+ size_t offset = etch_nativearray_off1(a, i);
+ if (value == NULL || offset < 0) return -1;
+ memcpy((byte*)a->values + offset, value, a->itemsize);
+ return 0;
+}
+
+
+/**
+ * put2()
+ * insert item to 2-dimensional array
+ */
+int etch_nativearray_put2(etch_nativearray* a, void* value, int i, int j)
+{
+ size_t offset = etch_nativearray_off2(a, i, j);
+ if (value == NULL || offset < 0) return -1;
+ memcpy((byte*)a->values + offset, value, a->itemsize);
+ return 0;
+}
+
+
+/**
+ * put3()
+ * insert item to 3-dimensional array
+ */
+int etch_nativearray_put3(etch_nativearray* a, void* value, int i, int j, int k)
+{
+ size_t offset = etch_nativearray_off3(a, i, j, k);
+ if (value == NULL || offset < 0) return -1;
+ memcpy((byte*)a->values + offset, value, a->itemsize);
+ return 0;
+}
+
+
+/**
+ * get1()
+ * access and return item from singly dimensioned array
+ */
+int etch_nativearray_get1(etch_nativearray* a, void* value, int i)
+{
+ size_t offset = etch_nativearray_off1(a, i);
+ if (value == NULL || offset < 0) return -1;
+ memcpy(value, (byte*)a->values + offset, a->itemsize);
+ return 0;
+}
+
+
+/**
+ * get2()
+ * access and return item from 2-dimensional array
+ */
+int etch_nativearray_get2(etch_nativearray* a, void* value, int i, int j)
+{
+ size_t offset = etch_nativearray_off2(a, i, j);
+ if (value == NULL || offset < 0) return -1;
+ memcpy(value, (byte*)a->values + offset, a->itemsize);
+ return 0;
+}
+
+
+/**
+ * get3()
+ * access and return item from 3-dimensional array
+ */
+int etch_nativearray_get3(etch_nativearray* a, void* value, int i, int j, int k)
+{
+ size_t offset = etch_nativearray_off3(a, i, j, k);
+ if (value == NULL || offset < 0) return -1;
+ memcpy(value, (byte*)a->values + offset, a->itemsize);
+ return 0;
+}
+
+
+/*
+ * etch_nativearray_off1()
+ * calculate byte offset into byte vector for a 1-dimension array
+ */
+size_t etch_nativearray_off1(etch_nativearray* a, int i)
+{
+ size_t offset = 0;
+ if (i >= (int) a->dimension[0] || i < 0) return -1;
+
+ offset = i * a->dimsize[0];
+ return offset;
+}
+
+
+/*
+ * etch_nativearray_off2()
+ * calculate byte offset into byte vector for a 2-dimension array
+ */
+size_t etch_nativearray_off2(etch_nativearray* a, int i, int j)
+{
+ size_t offset = 0;
+ if ((i >= (int) a->dimension[1] || i < 0)
+ || (j >= (int) a->dimension[0] || j < 0)) return -1;
+
+ offset = (i * a->dimsize[1]) + (j * a->dimsize[0]);
+ return offset;
+}
+
+
+/*
+ * etch_nativearray_off3()
+ * calculate byte offset into byte vector for a 3-dimension array
+ */
+size_t etch_nativearray_off3(etch_nativearray* a, int i, int j, int k)
+{
+ size_t offset = 0;
+ if ((i >= (int) a->dimension[2] || i < 0)
+ || (j >= (int) a->dimension[1] || j < 0)
+ || (k >= (int) a->dimension[0] || k < 0)) return -1;
+
+ offset = (i * a->dimsize[2]) + (j * a->dimsize[1]) + (k * a->dimsize[0]);
+ return offset;
+}
+
+
+/**
+ * etch_nativearray_get_component_type()
+ * java.lang.class.getcomponenttype returns the class of an array's members.
+ * we instead identify the etch object type and class id of the array's members,
+ * returning results in the passed parameter struct reference.
+ */
+int etch_nativearray_get_component_type
+ (etch_object* classobj, etch_component_type_params* p)
+{
+ int result = 0;
+ if (!p) return -1;
+ memset(p, 0, sizeof(etch_component_type_params));
+ if (!is_etch_nativearray(classobj)) return -1;
+
+ p->origl_array = (etch_nativearray*) classobj;
+ p->origl_obj_type = p->origl_array->content_obj_type;
+ p->origl_class_id = p->origl_array->content_class_id;
+ p->dimensions = p->origl_array->numdims;
+
+ p->final_array = p->origl_array;
+ p->final_obj_type = p->origl_obj_type;
+ p->final_class_id = p->origl_class_id;
+
+ /* we could have here an array of (pointers to) array. recurse the array
+ * until array content is no longer array.
+ */
+ while(is_etch_nativearray(p->final_obj_type))
+ {
+ /* the content of the current array is array,
+ * so peek at item[0] in this array of arrays */
+ etch_nativearray* content_array = p->final_array->bytecount >= sizeof(void*)?
+ (etch_nativearray*) ((etch_nativearray**) p->final_array->values)[0]: NULL;
+
+ if (!is_etch_nativearray(content_array))
+ { result = -1;/* sanity check, [0] not array, however content */
+ break; /* type indicated array, logic error, exception */
+ }
+
+ p->final_array = content_array;
+ p->final_obj_type = content_array->content_obj_type;
+ p->final_class_id = content_array->content_class_id;
+ if (is_etch_nativearray(p->final_obj_type))
+ p->dimensions += p->final_array->numdims;
+ }
+
+ return result;
+}
+
+
+/**
+ * etch_nativearray_get_wrapped_component()
+ * get wrapped component[i] from the single-dimensioned native array.
+ * caller owns returned object.
+ * todo: test that if array content was wrapped, the is_value_owned
+ * setting is sufficient for tranparent memory management of returned object.
+ */
+int etch_nativearray_get_wrapped_component(etch_nativearray* a, const int i, objmask** out)
+{
+ const int numentries = (int) a->dimension[0];
+ const int is_wrapped_content = a->content_class_id != 0;
+ int result = 0;
+ union
+ { char vbyte; short vint16; int vint32; int64 vint64;
+ float vfloat;double vdouble;void* vaddr; int64 all;
+ } v;
+
+ if (a->numdims != 1 || i >= numentries) return -1;
+ v.all = 0;
+
+ if (is_wrapped_content)
+ { /* content of the native array is wrapped, e.g, etch_object*,
+ * so we return the item as is */
+ result = a->get1(a, &v.vaddr, i);
+ *out = v.vaddr;
+ }
+ else switch(a->content_obj_type)
+ { /* content of the native array is unwrapped, e.g, int[], so we wrap
+ * the array item with an etch object prior to returning it */
+ case ETCHTYPEB_BYTE:
+ result = a->get1(a, &v.vbyte, i);
+ *out = (objmask*) new_byte(v.vbyte);
+ break;
+
+ case ETCHTYPEB_BOOL:
+ result = a->get1(a, &v.vbyte, i);
+ *out = (objmask*) new_boolean(v.vbyte);
+ break;
+
+ case ETCHTYPEB_INT8:
+ result = a->get1(a, &v.vbyte, i);
+ *out = (objmask*) new_int8(v.vbyte);
+ break;
+
+ case ETCHTYPEB_INT16:
+ result = a->get1(a, &v.vint16, i);
+ *out = (objmask*) new_int16(v.vint16);
+ break;
+
+ case ETCHTYPEB_INT32:
+ result = a->get1(a, &v.vint32, i);
+ *out = (objmask*) new_int32(v.vint32);
+ break;
+
+ case ETCHTYPEB_INT64:
+ result = a->get1(a, &v.vint64, i);
+ *out = (objmask*) new_int64(v.vint64);
+ break;
+
+ case ETCHTYPEB_IEEE32:
+ result = a->get1(a, &v.vfloat, i);
+ *out = (objmask*) new_float(v.vfloat);
+ break;
+
+ case ETCHTYPEB_IEEE64:
+ result = a->get1(a, &v.vdouble, i);
+ *out = (objmask*) new_double(v.vdouble);
+ break;
+
+ case ETCHTYPEB_STRING:
+ result = a->get1(a, &v.vaddr, i);
+ *out = (objmask*) new_string(v.vaddr, ETCH_ENCODING_UTF16);
+ break;
+
+ default: /* item is an anonymous pointer to a value owned by caller */
+ { etch_object* wrapper = NULL;
+ result = a->get1(a, &v.vaddr, i);
+ wrapper = new_etch_object(a->content_class_id, v.vaddr);
+ /* we clear is_value_owned so value will not be freed by dtor */
+ wrapper->is_value_object = wrapper->is_value_owned = FALSE;
+ *out = (objmask*) wrapper;
+ }
+
+ } /* switch(a->content_obj_type) */
+
+ return result;
+}
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etch_objects.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etch_objects.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etch_objects.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etch_objects.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,259 @@
+/**
+ * etch_objects.c
+ * etch type object wrappers construction
+ */
+
+#include <stdio.h>
+#include "etch_objects.h"
+#include "etchmem.h"
+#include "etchrun.h"
+#include "etch_arraylist.h"
+
+
+/**
+ * new_etch_primitive_object()
+ * constructor for an etchobject wrapper for a primitive value
+ * TODO LOSE
+ */
+etchobject* new_etchobject_primitive(const int objtype)
+{
+ etchobject* newobj = new_etchobject(objtype);
+ // newobj->is_static_data = 0; // *****************
+ return newobj;
+}
+
+/**
+ * new_etch_int32()
+ * constructor for ETCH_INT32, a boxed 32-bit integer
+ */
+ETCH_INT32* new_etch_int32(const int value)
+{
+ etchobject* newobj = new_etchobject_primitive(ETCHTYPE_BOXED_INT32);
+ newobj->value_int32 = value;
+ newobj->size = sizeof(int);
+ return newobj;
+}
+
+/**
+ * new_etch_int8()
+ * constructor for ETCH_INT8, a boxed 8-bit integer
+ */
+ETCH_INT8* new_etch_int8(const signed char value)
+{
+ etchobject* newobj = new_etchobject_primitive(ETCHTYPE_BOXED_INT8);
+ newobj->value_int8 = value;
+ newobj->size = sizeof(char);
+ return newobj;
+}
+
+/**
+ * new_etch_int16()
+ * constructor for ETCH_INT16, a boxed 16-bit integer
+ */
+ETCH_INT16* new_etch_int16(const short value)
+{
+ etchobject* newobj = new_etchobject_primitive(ETCHTYPE_BOXED_INT16);
+ newobj->value_int16 = value;
+ newobj->size = sizeof(short);
+ return newobj;
+}
+
+
+/**
+ * new_etch_int64()
+ * constructor for ETCH_INT64, a boxed 64-bit integer
+ */
+ETCH_INT64* new_etch_int64(const int64 value)
+{
+ etchobject* newobj = new_etchobject_primitive(ETCHTYPE_BOXED_INT64);
+ newobj->value_int64 = value;
+ newobj->size = sizeof(int64);
+ return newobj;
+}
+
+/**
+ * new_etch_byte()
+ * constructor for ETCH_BYTE, a boxed unsigned char
+ */
+ETCH_BYTE* new_etch_byte(const unsigned char value)
+{
+ etchobject* newobj = new_etchobject_primitive(ETCHTYPE_BOXED_BYTE);
+ newobj->value_byte = value;
+ newobj->size = sizeof(char);
+ return newobj;
+}
+
+/**
+ * new_etch_bool()
+ * constructor for ETCH_BOOL, a boxed unsigned char
+ */
+
+ETCH_BOOL* new_etch_bool(const unsigned char value)
+{
+ etchobject* newobj = new_etchobject_primitive(ETCHTYPE_BOXED_BOOL);
+ newobj->value_byte = value? TRUE: FALSE;
+ newobj->size = sizeof(char);
+ return newobj;
+}
+
+/**
+ * new_etch_ieee32()
+ * constructor for ETCH_IEEE32, a boxed float
+ */
+ETCH_IEEE32* new_etch_ieee32(const float value)
+{
+ etchobject* newobj = new_etchobject_primitive(ETCHTYPE_BOXED_IEEE32);
+ newobj->value_ieee32 = value;
+ newobj->size = sizeof(float);
+ return newobj;
+}
+
+/**
+ * new_etch_ieee64()
+ * constructor for ETCH_IEEE64, a boxed float
+ */
+ETCH_IEEE64* new_etch_ieee64(const double value)
+{
+ etchobject* newobj = new_etchobject_primitive(ETCHTYPE_BOXED_IEEE64);
+ newobj->value_ieee64 = value;
+ newobj->size = sizeof(double);
+ return newobj;
+}
+
+/**
+ * new_etch_string()
+ * constructor for ETCH_STRING, a boxed array of wchar_t
+ */
+ETCH_STRING* new_etch_string(const wchar_t* value)
+{
+ etchobject* newobj = NULL;
+ wchar_t* newval = NULL;
+ size_t bytelen = 0;
+ size_t numchars = value? wcslen(value) + 1: 0;
+ bytelen = sizeof(wchar_t) * numchars;
+
+ newval = etch_malloc (bytelen, ETCHTYPEB_BYTES);
+ memcpy(newval, value, bytelen);
+
+ newobj = new_etchobject(ETCHTYPE_BOXED_STRING);
+ newobj->value_ptr_to = newval;
+ newobj->size = bytelen;
+ return newobj;
+}
+
+
+/**
+ * new_etch_static_string()
+ * constructor for ETCH_STRING, a boxed array of wchar_t
+ * specified string will not be freed when the object is destroyed
+ */
+ETCH_STRING* new_etch_static_string(const wchar_t* value)
+{
+ etchobject* newobj = NULL;
+ //size_t bytelen = 0;
+ //size_t numchars = value? wcslen(value) + 1: 0;
+ //bytelen = sizeof(wchar_t) * numchars;
+
+ //newobj = new_etchobject(ETCHTYPE_BOXED_STRING);
+ //newobj->value_ptr_to = (wchar_t*)value;
+ //newobj->size = bytelen;
+ //newobj->is_static_data = TRUE;
+ return newobj;
+}
+
+
+/**
+ * destroy_boxed_arraylist(()
+ * destructor for ETCH_ARRAYLIST, a boxed etch_arraylist.
+ */
+void destroy_boxed_arraylist(ETCH_ARRAYLIST* thisp)
+{
+ //if (!thisp->is_static_data && thisp->value_ptr_to)
+ // arraylist_destroy((etch_arraylist*)thisp->value_ptr_to, TRUE);
+
+ //if (!thisp->is_static_object)
+ // etch_free(thisp);
+}
+
+
+/**
+ * clone_boxed_arraylist()
+ */
+ETCH_ARRAYLIST* clone_boxed_arraylist(ETCH_ARRAYLIST* thisp)
+{
+ int i = 0, result = 0;
+ void* content = NULL;
+ etchobject* newobj = NULL;
+ //etch_arraylist* newlist = NULL, *oldlist = NULL;
+ //if (thisp == NULL) return NULL;
+
+ //if (thisp->is_static_data) /* if static string return it */
+ // return thisp->value_ptr_to;
+ // /* null if nothing to copy */
+ //if (thisp->value_ptr_to == NULL || thisp->size < 1)
+ // return NULL;
+
+ //oldlist = (etch_arraylist*) thisp->value_ptr_to;
+ //newlist = new_arraylist(oldlist->count, oldlist->delta);
+ //newlist->is_readonly = oldlist->is_readonly;
+ //newlist->content_type = oldlist->content_type;
+
+ //while((result == 0) && (NULL != (content = arraylist_get(oldlist, i++))))
+ // result = arraylist_add(newlist, content);
+
+ //newobj = new_etchobject(ETCHTYPE_BOXED_ARRAYLIST);
+ //memcpy(newobj, thisp, sizeof(etchobject));
+ //newobj->value_ptr_to = newlist;
+
+ return newobj;
+}
+
+
+
+/**
+ * new_etch_arraylist(initsize, delta)
+ * constructor for ETCH_ARRAYLIST, a boxed etch_arraylist.
+ * initsize: initial number of entries allocated, default configured.
+ * deltsize: number of entries added upon expansion, default initsize.
+ * is_readonly: if TRUE, memory for arraylist content will not be freed
+ * upon invoking destroy() (of course, more control could be exerted
+ * by operating on the underlying etch_arraylist directly).
+ */
+ETCH_ARRAYLIST* new_etch_arraylist
+ (const unsigned initsize, const unsigned deltsize, const unsigned is_readonly)
+{
+ etchobject* newobj = NULL;
+ //i_etchobject* vtab = NULL;
+ //const int VTAB_KEY = ETCHTYPEB_ARRAYLIST;
+
+ //etch_arraylist* list = new_arraylist(initsize, deltsize);
+ //if (NULL == list) return NULL;
+
+ //newobj = new_etchobject(ETCHTYPE_BOXED_ARRAYLIST);
+ //newobj->value_ptr_to = list;
+ //newobj->size = list->size; /* TODO size as elsewhere */
+ //list->is_readonly = is_readonly != 0; /* static content indicator */
+
+ //vtab = cache_find(VTAB_KEY, 0);
+
+ //if(!vtab) /* cache the vtable for this object type */
+ //{
+ // vtab = new_vtable(newobj->vtab, ETCHOBJ_VTABSIZE, ETCHTYPEB_VTABLE, 0);
+
+ // /* function overrides */
+ // vtab->destroy = destroy_boxed_arraylist;
+ // vtab->clone = clone_boxed_arraylist;
+ //
+ // vtab->vtab = newobj->vtab; /* chain parent vtable to override vtable */
+
+ // cache_insert(VTAB_KEY, vtab, 0); /* cache the new vtable */
+ //}
+
+ //newobj->vtab = vtab; /* set override vtable */
+ return newobj;
+}
+
+
+
+
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etchexcp.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etchexcp.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etchexcp.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etchexcp.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,487 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * etchexcp.c -- exception objects native and boxed
+ */
+
+#include <stdio.h>
+#include "etch_encoding.h"
+#include "etchexcp.h"
+#include "etch_global.h"
+#pragma warning (disable:4996)
+
+
+/**
+ * etch_throw()
+ * "throw" specified exception on specified object, meaning create an exception
+ * and store it in the specified object's return value.
+ * type: arbitrary exception type, not edited. if a known type and text is not
+ * supplied, attempt is made to locate and supply default text for that type.
+ * text: optional text descriptive of the exception.
+ * bitwise flags:
+ * ETCHEXCP_COPYTEXT: make a copy of supplied text and free it on destroy
+ * ETCHEXCP_FREETEXT: at destroy time, free the exception text memory
+ */
+objmask* etch_throw(objmask* obj, const excptype type, wchar_t* text, unsigned flags)
+{
+ int result = 0;
+ if (!obj) return NULL;
+
+ if(!obj->result)
+ obj->result = new_etchresult(0, 0);
+
+ if (obj->result->exception)
+ destroy_exception(obj->result->exception);
+
+ obj->result->exception = new_exception(type, text, flags);
+ return obj;
+}
+
+
+/**
+ * etch_throwex()
+ * throw specified exception.
+ * same as etch_throw but with etch_result parameters specified as well.
+ */
+objmask* etch_throwex(objmask* obj, const excptype type, wchar_t* text,
+ unsigned flags, const int resultcode, const int reasoncode)
+{
+ if (NULL == etch_throw(obj, type, text, flags)) return NULL;
+ obj->result->resultcode = resultcode;
+ obj->result->reasoncode = reasoncode;
+ return obj;
+}
+
+
+/*
+ * new_exception()
+ * instantiate a native exception object.
+ * this is not an etch object, it is a raw struct, see new_etch_exception()
+ * bitwise flags:
+ * ETCHEXCP_COPYTEXT: make a copy of supplied text and free it on destroy
+ * ETCHEXCP_FREETEXT: at destroy time, free the exception text memory
+ * ETCHEXCP_UNCHECKED: exception is unchecked
+ */
+etchexception* new_exception(const excptype type, wchar_t* text, const unsigned flags)
+{
+ size_t numchars = 0;
+ etchexception* excp = etch_malloc(sizeof(etchexception), ETCHTYPEB_EXCEPTION);
+ memset(excp, 0, sizeof(etchexception));
+ excp->excptype = type;
+ excp->flags = flags;
+
+ if (text && !flags) /* if text without flags, default to copy text */
+ excp->flags = ETCHEXCP_COPYTEXT;
+ else
+ if(!text) /* if no text, get default text and clear copy and free flags */
+ { text = default_excptext(type);
+ excp->flags &= ~(ETCHEXCP_FREETEXT | ETCHEXCP_COPYTEXT);
+ }
+
+ if (text) /* calculate byte length of text */
+ { numchars = wcslen(text) + 1;
+ excp->textlen = sizeof(wchar_t) * numchars;
+ }
+
+ if (text && (flags & ETCHEXCP_COPYTEXT))
+ { /* if asked to make a copy of the text, do so */
+ excp->excptext = etch_malloc(excp->textlen, ETCHTYPEB_STRING);
+ wcscpy_s(excp->excptext, numchars, text);
+ excp->flags |= ETCHEXCP_FREETEXT; /* indicate free on destroy */
+ }
+ else excp->excptext = text; /* ETCHEXCP_FREETEXT may or may not be set */
+
+ /* etch_malloc an ansi copy for display */
+ if (0 == etch_unicode_to_ansi (&excp->ansitext, excp->excptext))
+ excp->atxtlen = strlen(excp->ansitext);
+
+ if (type >= EXCPTYPE_CHECKED_START) /* mark checked excp as such */
+ excp->flags |= ETCHEXCP_CHECKED;
+
+ return excp;
+}
+
+
+/**
+ * destroy_etch_exception()
+ */
+int destroy_etch_exception(etch_exception* ee)
+{
+ if (ee->refcount > 0 && --ee->refcount > 0) return -1;
+
+ if (!is_etchobj_static_content(ee))
+ destroy_exception(ee->value);
+
+ return destroy_objectex((objmask*) ee);
+}
+
+
+/**
+ * clone_etch_exception()
+ */
+etch_exception* clone_etch_exception (etch_exception* ee)
+{
+ etch_exception* newobj = NULL;
+ etchexception* excp = ee? (etchexception*) ee->value: NULL;
+ if (!excp) return NULL;
+ newobj = new_etch_exception (excp->excptype, excp->excptext, ETCHEXCP_COPYTEXT);
+ return newobj;
+}
+
+
+/**
+ * new_etch_exception()
+ * constructor for wrapped exception
+ */
+etch_exception* new_etch_exception(const excptype type, wchar_t* text,
+ const unsigned flags)
+{
+ etch_exception* newobj = (etch_exception*) new_object
+ (sizeof(struct etch_exception), ETCHTYPEB_EXCEPTION, CLASSID_EXCEPTION);
+
+ newobj->value = new_exception(type, text, flags);
+
+ newobj->destroy = destroy_etch_exception;
+ newobj->clone = clone_etch_exception;
+
+ return newobj;
+}
+
+
+/* builtin exception text */
+const wchar_t* excptext_excp = L"etch";
+const wchar_t* excptext_io = L"I/O";
+const wchar_t* excptext_auth = L"authorization";
+const wchar_t* excptext_runtime = L"etch runtime";
+const wchar_t* excptext_nullptr = L"null pointer";
+const wchar_t* excptext_arg = L"illegal argument";
+const wchar_t* excptext_unsupop = L"unsupported operation";
+const wchar_t* excptext_internal= L"internal error";
+const wchar_t* excptext_notfound= L"not found";
+
+
+/*
+ * default_excptext()
+ * find and return default text for exception type
+ */
+wchar_t* default_excptext(const excptype type)
+{
+ wchar_t* text = NULL;
+
+ switch(type)
+ {
+ case EXCPTYPE_GENERIC: text = (wchar_t*) excptext_excp; break;
+ case EXCPTYPE_ETCHRUNTIME: text = (wchar_t*) excptext_runtime; break;
+ case EXCPTYPE_ETCHAUTH: text = (wchar_t*) excptext_auth; break;
+ case EXCPTYPE_IO: text = (wchar_t*) excptext_io; break;
+ case EXCPTYPE_NULLPTR: text = (wchar_t*) excptext_nullptr; break;
+ case EXCPTYPE_ILLEGALARG: text = (wchar_t*) excptext_arg; break;
+ case EXCPTYPE_UNSUPPORTEDOP: text = (wchar_t*) excptext_unsupop; break;
+ case EXCPTYPE_INTERNALERR: text = (wchar_t*) excptext_internal;break;
+ case EXCPTYPE_NOTFOUND: text = (wchar_t*) excptext_notfound;break;
+ }
+
+ return text;
+}
+
+
+/*
+ * destroy_exception()
+ * free memory for specified native exception object
+ */
+void destroy_exception (etchexception* excp)
+{
+ if(!excp) return; /* text may be static or freed elsewhere */
+
+ if (excp->flags & ETCHEXCP_FREETEXT)
+ { ETCHOBJ_FREE(excp->excptext); /* free exception text */
+ }
+
+ /* always allocated in ctor, never passed in */
+ ETCHOBJ_FREE(excp->ansitext);
+
+ etch_free(excp); /* free exception wrapper */
+}
+
+
+/*
+ * get_excpobj()
+ * create and return an etchobject for the sole purpose of returning an exception.
+ * we might use this functionality where our method returns an object which we have
+ * not yet created, we edit parameters, find them wanting, and wish to throw an
+ * exception, and need an object in which to return the exception.
+ */
+objmask* get_excpobj (int objsize, short obj_type, short class_id,
+ excptype xcptype, wchar_t* xcptext, unsigned flags)
+{
+ objmask* newobj = new_object(objsize, obj_type, class_id);
+ newobj->is_null = TRUE;
+ etch_throw(newobj, xcptype, xcptext, flags);
+ return newobj;
+}
+
+
+/*
+ * get_excptype()
+ * return exception type given result code
+ */
+excptype get_excptype(const results result)
+{
+ excptype xtype;
+ if (result >= 0) return EXCPTYPE_NONE;
+
+ switch(result)
+ {
+ case ETCHRESULT_EXCPERR_IO: xtype = EXCPTYPE_IO; break;
+ case ETCHRESULT_EXCPERR_BADARG: xtype = EXCPTYPE_ILLEGALARG; break;
+ case ETCHRESULT_EXCPERR_NULLPTR: xtype = EXCPTYPE_NULLPTR; break;
+ case ETCHRESULT_EXCPERR_BADOP: xtype = EXCPTYPE_UNSUPPORTEDOP; break;
+ default: xtype = EXCPTYPE_GENERIC;
+ }
+ return xtype;
+}
+
+
+/*
+ * excp_tostring
+ * returns unicode string representation of exception
+ * caller owns returned buffer
+ */
+wchar_t* excp_tostring (etchexception* excp)
+{
+ wchar_t *newbuf = NULL;
+ const wchar_t *x = L"exception ", charlen = sizeof(wchar_t), *space = L" " ;
+ const size_t xbytelen = wcslen(x) * charlen;
+ wchar_t* deftext = default_excptext(excp->excptype);
+ const size_t deftextbytelen = deftext?
+ wcslen(deftext) * charlen: 0;
+ const size_t excptextbytelen = excp->excptext?
+ wcslen(excp->excptext) * charlen: 0;
+ wchar_t* excptext
+ = excptextbytelen? excp->excptext:
+ deftextbytelen? deftext:
+ L"generic";
+ const size_t textbytelen = wcslen(excp->excptext) * charlen;
+ const size_t buflen = xbytelen + textbytelen + (3 * charlen);
+
+ newbuf = etch_malloc(buflen, ETCHTYPEB_BYTES);
+ memset(newbuf, 0, buflen);
+
+ wcscat(newbuf, excptext); /* e.g. "null pointer" */
+ wcscat(newbuf, space);
+ wcscat(newbuf, x); /* "exception " */
+
+ return newbuf;
+}
+
+
+/*
+ * excp_tostringx
+ * returns ascii string representation of exception
+ * caller owns returned buffer
+ */
+char* excp_tostringx(etchexception* excp)
+{
+ char* ansibuf = NULL;
+ wchar_t* unibuf = excp_tostring(excp);
+ const int result = etch_unicode_to_ansi(&ansibuf, unibuf);
+ etch_free(unibuf);
+ return ansibuf;
+}
+
+
+/*
+ * is_catch_exception()
+ * "catch" exception defined by result code, returning FALSE if no exception.
+ * the etchobject wrapping the exception is returned in the out parameter.
+ * this object is created if no such object is passed.
+ */
+boolean is_catch_exception(objmask* obj, const int result, objmask** outobj)
+{
+ objmask* excpobj = throw_exception(obj, result);
+
+ if (is_exception(excpobj))
+ {
+ if (outobj) *outobj = excpobj;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * is_catch()
+ * "catch" exception defined by result code, returning FALSE if no exception.
+ * the etchobject wrapping the exception is returned in the out parameter.
+ * this object is created if no such object is passed.
+ */
+boolean is_catch(objmask* obj, const int result, const int objtype, objmask** outobj)
+{
+ objmask* excpobj = obj?
+ throw_exception(obj, result):
+ throw_exception_from(objtype, result);
+
+ if (is_exception(excpobj))
+ {
+ if (outobj) *outobj = excpobj;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * catch_exception()
+ * return an etchobject containing the exception mapping to the specified
+ * result code. an anonymous object is generated if none is supplied.
+ */
+objmask* catch_exception(objmask* obj, const int result)
+{
+ return throw_exception(obj, result);
+}
+
+
+/*
+ * throw_exception()
+ * return an etchobject of the specified type containing the exception mapping to
+ * the specified result code. an anonymous object is generated if none is supplied.
+ */
+objmask* throw_exception(objmask* obj, const int result)
+{
+ excptype xtype = get_excptype(result);
+ if (obj == NULL)
+ obj = get_excpobj(sizeof(objmask), ETCHTYPEB_UNDEFINED, 0, xtype, NULL, 0);
+
+ if (xtype != EXCPTYPE_NONE)
+ etch_throw(obj, xtype, NULL, 0);
+
+ return obj;
+}
+
+
+/*
+ * throw_exception_from()
+ * generate and return an etch object of the specified type containing the exception
+ * mapping to the specified result code.
+ */
+objmask* throw_exception_from(const short obj_type, const int result)
+{
+ objmask* obj = NULL;
+ excptype xtype = get_excptype(result);
+ obj = get_excpobj(sizeof(objmask), obj_type, 0, xtype, NULL, 0);
+ return obj;
+}
+
+
+/*
+ * throw_from()
+ * generate and return an etchobject of the specified type
+ * containing the specified exception
+ */
+objmask* throw_from(excptype xtype, const short obj_type, wchar_t* text, unsigned flags)
+{
+ return get_excpobj(sizeof(objmask), obj_type, 0, xtype, text, flags);
+}
+
+
+/*
+ * etch_rethrow
+ * throw an exception from an existing exception
+ */
+objmask* etch_rethrow(objmask* target, objmask* source)
+{
+ etchexception* excp = NULL;
+ if (target != NULL)
+ excp = get_exception(source);
+ if (excp == NULL) return throw_from(EXCPTYPE_INTERNALERR, target->obj_type, NULL, 0);
+
+ return etch_throwex(target, excp->excptype, excp->excptext, excp->flags,
+ source->result->resultcode, source->result->reasoncode);
+}
+
+
+/*
+ * get_etch_exception_from()
+ * returns the etch_exception object if any from the specified etch object.
+ * @return a non-disposable reference to the etch_exception object, or NULL.
+ */
+etch_exception* get_etch_exception_from (objmask* obj)
+{
+ if (obj && (obj->obj_type == ETCHTYPEB_EXCEPTION))
+ return (etch_exception*) obj;
+ return NULL;
+}
+
+
+/*
+ * get_exception_from
+ * returns the unwrapped etchexception if any from the specified etch object.
+ */
+etchexception* get_exception_from (objmask* obj)
+{
+ if (NULL == obj) return NULL;
+ if (obj->obj_type == ETCHTYPEB_EXCEPTION)
+ return (etchexception*) ((etch_exception*) obj)->value;
+ if (obj->result) return obj->result->exception;
+ return NULL;
+}
+
+
+/*
+ * get_exception_from()
+ * returns a disposable exception object based on the exception contained in
+ * the specified object.
+ */
+etch_exception* new_etch_exception_from (objmask* obj)
+{
+ etch_exception* x = NULL;
+ etchexception* excp = get_exception_from (obj);
+ if (excp)
+ x = new_etch_exception (excp->excptype, excp->excptext, ETCHEXCP_COPYTEXT);
+ return x;
+}
+
+
+/*
+ * verifyx()
+ * test specified object for specified type, throw specified exception if not
+ */
+objmask* verifyx(objmask* obj,
+ const unsigned short objtype, const unsigned short classid, excptype xtype)
+{
+ if(!obj)
+ obj = throw_from(xtype, objtype, NULL, 0);
+ else
+ if ((objtype != 0 && obj->obj_type != objtype)
+ || (classid != 0 && obj->class_id != classid))
+ etch_throwex(obj, xtype, NULL, 0, -1, 0);
+
+ return obj;
+}
+
+
+
+
+
+
+
+
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/common/etchflexbuf.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/common/etchflexbuf.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/common/etchflexbuf.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/common/etchflexbuf.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,744 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * etchflexbuf.c
+ * flex buffer
+ */
+
+#include "etchflexbuf.h"
+#include "etchobjtypes.h"
+#include "etch_global.h"
+#include "etchlog.h"
+
+#define ETCH_INIT_FLEXBUFSIZE 2048
+#define ETCH_MAX_FLEXBUFSIZE (4*1024*1024)
+
+void etch_flexbuf_fix_length (etch_flexbuffer*);
+BOOLEAN etch_flexbuf_ensure_size (etch_flexbuffer*, size_t);
+
+/*
+ * java binding syntax is confusing and ambiguous so we change it a bit. java
+ * calls the data region in the buffer "length". since "length" is non-specific,
+ * and there are other "length"s, such as "buffer.length", and "object.length",
+ * we'll call it "datalen", to mean "meaningful bytes within the buffer". java
+ * also uses "buffer.length", which is the size of the allocated buffer. c of
+ * course does not associate properties with arrays, so we carry an additional
+ * property "bufsize" to indicate the allocated length of the byte array.
+ */
+
+
+/**
+ * new_flexbuffer()
+ * etch_flexbuffer constructor
+ */
+etch_flexbuffer *new_flexbuffer (size_t bufsize)
+{
+ void *buf;
+ if (bufsize <= 0 || bufsize > ETCH_MAX_FLEXBUFSIZE) bufsize = ETCH_INIT_FLEXBUFSIZE;
+
+ buf = etch_malloc(bufsize, ETCHTYPEB_BYTES);
+ memset(buf, 0, bufsize);
+
+ return etch_flexbuf_create_bi (buf, bufsize, 0, 0);
+}
+
+
+/**
+ * new_flexwriter_from()
+ * etch_flexbuffer constructor with index set to write
+ */
+etch_flexbuffer *new_flexwriter_from (void *buf, size_t datalen, size_t bufsize)
+{
+ return new_flexbuffer_from (buf, datalen, bufsize, datalen);
+}
+
+
+/**
+ * new_flexbuffer_from()
+ * etch_flexbuffer constructor.
+ * @param buf data which is to become the internal buffer. caller relinquishes this memory.
+ * @param datalen length of real data in bytes.
+ * @param bufsize size of buffer in bytes.
+ * @param buffer index at which to start.
+ */
+etch_flexbuffer *new_flexbuffer_from (void* buf, size_t datalen, size_t bufsize, size_t index)
+{
+ if (bufsize <= 0 || bufsize > ETCH_MAX_FLEXBUFSIZE) bufsize = ETCH_INIT_FLEXBUFSIZE;
+ if (datalen > bufsize || (!buf && datalen)) return NULL;
+ if (NULL == buf)
+ { buf = etch_malloc(bufsize, ETCHTYPEB_BYTES);
+ memset(buf, 0, bufsize);
+ }
+
+ return etch_flexbuf_create_bi (buf, bufsize, datalen, index);
+}
+
+
+/**
+ * etch_flexbuf_create_b()
+ * create a flex buffer out of an existing buffer, ready to read to,
+ * using specified size and an index of zero.
+ *
+ * @param buf the existing buffer.
+ * @param bufsize the buffer size.
+ * @param datalen the data length in the buffer
+ *
+ * @return the created and initialized the flex buffer.
+ *
+ */
+etch_flexbuffer *etch_flexbuf_create_b (void *buf, size_t bufsize, size_t datalen)
+{
+ return etch_flexbuf_create_bi(buf, bufsize, datalen, 0);
+}
+
+
+/**
+ * etch_flexbuf_create_bi()
+ * create a flex buffer out of an existing buffer, ready to read with specified
+ * index and size.
+ * @param buf the existing buffer.
+ * @param bufsize the buffer size.
+ * @param datalen the data length in the buffer
+ * @param index current position of the buffer.
+ */
+etch_flexbuffer *etch_flexbuf_create_bi (void *buf, size_t bufsize, size_t datalen, size_t index)
+{
+ etch_flexbuffer *fbuf = (etch_flexbuffer*) new_object
+ (sizeof(etch_flexbuffer), ETCHTYPEB_FLEXBUF, CLASSID_FLEXBUF);
+
+ fbuf->destroy = destroy_etch_flexbuffer;
+
+ fbuf->buf = buf;
+ fbuf->bufsize = bufsize;
+ fbuf->datalen = datalen;
+ fbuf->index = index;
+ fbuf->is_littleendian = IS_ETCH_TRANSPORT_LITTLEENDIAN;
+ return fbuf;
+}
+
+
+/**
+ * etch_flexbuf_get_buffer()
+ * @return the current byte array. might change if any operation
+ * needs to extend length past the end of the array.
+ */
+byte* etch_flexbuf_get_buffer (etch_flexbuffer *fbuf)
+{
+ return fbuf->buf;
+}
+
+
+/**
+ * etch_flexbuf_clear()
+ * zero fill the internal buffer
+ */
+void etch_flexbuf_clear (etch_flexbuffer *fbuf)
+{
+ memset (fbuf->buf, 0, fbuf->bufsize);
+}
+
+
+/**
+ * etch_flexbuf_ensure_size().
+ * verify sufficient buffer capacity, reallocating if necessary.
+ * @return boolean value indicating if buffer is as requested.
+ */
+static int etch_flexbuf_ensure_size (etch_flexbuffer *fbuf, size_t reqsize)
+{
+ byte *newbuf = NULL;
+ size_t newsize = fbuf->bufsize;
+ if (reqsize < ETCH_INIT_FLEXBUFSIZE)
+ reqsize = ETCH_INIT_FLEXBUFSIZE;
+ if (reqsize <= newsize) return TRUE;
+ if (reqsize > ETCH_MAX_FLEXBUFSIZE) return FALSE;
+
+ while(reqsize > newsize) newsize += ETCH_INIT_FLEXBUFSIZE;
+ newbuf = etch_realloc (fbuf->buf, newsize, 0);
+ fbuf->buf = newbuf;
+ fbuf->bufsize = newsize;
+ return TRUE;
+}
+
+
+/**
+ * destroy_etch_flexbuffer()
+ * etch_flexbuffer destructor
+ */
+int destroy_etch_flexbuffer(etch_flexbuffer *fbuf)
+{
+ if (fbuf == NULL) return 0;
+ if (fbuf->refcount > 0 && --fbuf->refcount > 0) return 0;
+
+ if (!is_etchobj_static_content(fbuf))
+ etch_free(fbuf->buf); /* OK if null */
+
+ destroy_objectex((objmask*) fbuf);
+ return 0;
+}
+
+
+/**
+ * sets a new data length. If the index is larger than new length,
+ * the index is set to the new length as well.
+ * the method name was retained from java, however it is more properly
+ * set_data_length, since as noted previously, "length" is ambiguous,
+ * referring to data length, not to allocated bytes.
+ */
+int etch_flexbuf_set_length (etch_flexbuffer *fbuf, size_t new_datalen)
+{
+ int result = 0;
+
+ if (new_datalen >= 0 && etch_flexbuf_ensure_size(fbuf, new_datalen))
+ {
+ fbuf->datalen = new_datalen;
+
+ if (fbuf->index > new_datalen)
+ fbuf->index = new_datalen;
+ }
+ else result = -1;
+
+ return result;
+}
+
+
+/**
+ * sets a new buffer index. the index must be greater than 0 and less
+ * than the buffer size
+ * @param fbuf the buffer pointer to be set.
+ * @param index the new index for the buffer.
+ */
+int etch_flexbuf_set_index (etch_flexbuffer *fbuf, size_t index)
+{
+ if (index < 0 || index > fbuf->datalen) return -1;
+ fbuf->index = index;
+ return 0;
+}
+
+
+/**
+ * get the number of bytes available in the buffer.
+ * @return the available space in the buffer.
+ */
+size_t etch_flexbuf_avail (etch_flexbuffer *fbuf)
+{
+ return (fbuf->datalen - fbuf->index);
+}
+
+
+/**
+ * etch_flexbuffer_reset_to()
+ * set index to zero and length to specified length.
+ */
+int etch_flexbuffer_reset_to (etch_flexbuffer *fbuf, size_t new_datalen)
+{
+ const int result = etch_flexbuf_set_length (fbuf, new_datalen);
+ fbuf->index = 0;
+ return result;
+}
+
+
+/**
+ * etch_flexbuf_reset()
+ * set index and length to zero, same as etch_flexbuf_set_index(buf, 0)
+ */
+etch_flexbuffer *etch_flexbuf_reset (etch_flexbuffer *fbuf)
+{
+ fbuf->index = fbuf->datalen = 0;
+ return fbuf;
+}
+
+
+/**
+ * Compacts the buffer by moving remaining data (from index to length)
+ * to the front of the buffer. Sets index to 0, and sets length to
+ * avail (before index was changed).
+ * @return this flex buffer object.
+ */
+etch_flexbuffer *etch_flexbuf_compact(etch_flexbuffer *fbuf)
+{
+ size_t curlen;
+ if (fbuf->index == 0) return fbuf;
+
+ if (0 == (curlen = etch_flexbuf_avail(fbuf)))
+ {
+ etch_flexbuf_set_length(fbuf, 0);
+ return fbuf;
+ }
+
+ memmove(fbuf->buf, fbuf->buf+fbuf->index, curlen);
+ fbuf->index = 0;
+ fbuf->datalen = curlen;
+
+ return fbuf;
+}
+
+
+/**
+ * Copies data from the internal buffer to buf.
+ *
+ * @param fbuf the flex buffer to get data from.
+ * @param buf a buffer to receive the data. At most
+ * min( len, avail() ) bytes are transferred, starting
+ * at off.
+ * @param off the index in buf to receive the data.
+ * Off must be >= 0 && <= buf.datalen.
+ * @param len the max amount of data to transfer. Len
+ * must be >= 0 and <= buf.datalen - off.
+ * @return the amount of data transferred.
+ */
+size_t etch_flexbuf_get(etch_flexbuffer *fbuf, byte *buf, size_t off, size_t len)
+{
+ size_t bytecount = 0, avail = etch_flexbuf_avail(fbuf);
+ if (len <= 0 || NULL == buf) return 0;
+
+ bytecount = min(len, avail);
+ /* changed 6/16 to add index */
+ memcpy(buf + off, fbuf->buf + fbuf->index + off, bytecount);
+ fbuf->index += bytecount;
+
+ return bytecount;
+}
+
+
+/**
+ * etch_flexbuf_get_allfrom()
+ * return buffer contents starting at index, in a byte vector, caller owns returned memory
+ */
+byte* etch_flexbuf_get_allfrom(etch_flexbuffer* fbuf, size_t index, size_t* out_count)
+{
+ byte* newbuf = 0;
+ size_t bytecount = 0;
+ if (index < 0) index = fbuf->index;
+ if (index > fbuf->datalen) index = fbuf->datalen;
+ fbuf->index = index; /* 6/16 so etch_flexbuf_get can skip index */
+
+ bytecount = fbuf->datalen - index;
+ newbuf = etch_malloc(bytecount, ETCHTYPEB_BYTES);
+
+ bytecount = etch_flexbuf_get(fbuf, newbuf, 0, bytecount);
+
+ if (out_count) *out_count = bytecount;
+ return newbuf;
+}
+
+
+/**
+ * etch_flexbuf_get_all()
+ * return buffer contents in a byte array, caller owns memory
+ */
+byte* etch_flexbuf_get_all(etch_flexbuffer* fbuf, size_t* out_count)
+{
+ return etch_flexbuf_get_allfrom(fbuf, fbuf->index, out_count);
+}
+
+
+/**
+ * return next byte in buffer
+ */
+int etch_flexbuf_get_byte(etch_flexbuffer *fbuf, byte* out)
+{
+ if (etch_flexbuf_avail(fbuf) < sizeof(byte)) return -1;
+ *out = fbuf->buf[fbuf->index++];
+ return 0;
+}
+
+
+void reverse2(unsigned short* item)
+{
+ unsigned short newitem = 0;
+ byte *p = (byte*) &item, *q = (byte*) &newitem;
+ p[0] = q[1]; p[1] = q[0];
+ *item = newitem;
+}
+
+void reverse4(unsigned* item)
+{
+ unsigned curitem = *item, newitem = 0;
+ byte *p = (byte*) &curitem, *q = (byte*) &newitem;
+ q[0] = p[3]; q[1] = p[2]; q[2] = p[1]; q[3] = p[0];
+ *item = newitem;
+}
+
+
+/**
+ * etch_flexbuf_get_short()
+ * @return a short composed from the next 2 bytes.
+ */
+int etch_flexbuf_get_short(etch_flexbuffer *fbuf, short* out)
+{
+ int value, svalue;
+ if (etch_flexbuf_avail(fbuf) < sizeof(short)) return -1;
+
+ if (fbuf->is_littleendian)
+ {
+ value = fbuf->buf[fbuf->index++] & 255;
+ svalue = (short) (value + ((fbuf->buf[fbuf->index++] & 255) << 8));
+ }
+ else
+ { value = fbuf->buf[fbuf->index++]; /* big endian */
+ svalue = (short) ((value << 8) + (fbuf->buf[fbuf->index++] & 255));
+ }
+
+ *out = svalue;
+ return 0;
+}
+
+
+/**
+ * etch_flexbuf_get_int()
+ * @return an int composed from the next 4 bytes.
+ * TODO convert the rest of these functions to not do byte by byte subscripting
+ */
+int etch_flexbuf_get_int(etch_flexbuffer *fbuf, int* out)
+{
+ int value = 0, bytesavail = (int) etch_flexbuf_avail(fbuf);
+ if (bytesavail < sizeof(int)) return -1;
+
+ value = *( (int*) &fbuf->buf[fbuf->index] );
+
+ if (! fbuf->is_littleendian);
+ reverse4(&value);
+
+ fbuf->index += sizeof(int);
+ *out = value;
+ return 0;
+}
+
+
+#if(0)
+/**
+ * @return an int composed from the next 4 bytes.
+ * @throws IOException if avail() < 4.
+ */
+int etch_flexbuf_get_int(etch_flexbuffer *fbuf)
+{
+ int value = 0;
+ if (fbuf->is_littleendian)
+ {
+ // little-endian
+ value = fbuf->buf[fbuf->index++] & 255;
+ value += ((fbuf->buf[fbuf->index++] & 255) << 8);
+ value += ((fbuf->buf[fbuf->index++] & 255) << 16);
+ return value + ((fbuf->buf[fbuf->index++] & 255) << 24);
+ }
+
+ // big-endian
+ value = fbuf->buf[fbuf->index++];
+ value = (value << 8) + (fbuf->buf[fbuf->index++] & 255);
+ value = (value << 8) + (fbuf->buf[fbuf->index++] & 255);
+ return (value << 8) + (fbuf->buf[fbuf->index++] & 255);
+}
+#endif
+
+
+/**
+ * etch_flexbuf_get_long()
+ * @return a long composed from the next 8 bytes.
+ * note jim are we taking sign into consideration on reversal?
+ */
+int etch_flexbuf_get_long(etch_flexbuffer *fbuf, int64* out)
+{
+ int64 value, valout;
+ int bytesavail = (int) etch_flexbuf_avail(fbuf);
+ if (bytesavail < sizeof(int64)) return -1;
+
+ if (fbuf->is_littleendian)
+ {
+ /* little-endian */
+ value = fbuf->buf[fbuf->index++] & 255;
+ value += (((int64)(fbuf->buf[fbuf->index++] & 255)) << 8);
+ value += (((int64)(fbuf->buf[fbuf->index++] & 255)) << 16);
+ value += (((int64)(fbuf->buf[fbuf->index++] & 255)) << 24);
+ value += (((int64)(fbuf->buf[fbuf->index++] & 255)) << 32);
+ value += (((int64)(fbuf->buf[fbuf->index++] & 255)) << 40);
+ value += (((int64)(fbuf->buf[fbuf->index++] & 255)) << 48);
+ valout = value + (((int64)(fbuf->buf[fbuf->index++] & 255)) << 56);
+ }
+ else /* big-endian */
+ { value = fbuf->buf[fbuf->index++];
+ value = (value << 8) + (fbuf->buf[fbuf->index++] & 255);
+ value = (value << 8) + (fbuf->buf[fbuf->index++] & 255);
+ value = (value << 8) + (fbuf->buf[fbuf->index++] & 255);
+ value = (value << 8) + (fbuf->buf[fbuf->index++] & 255);
+ value = (value << 8) + (fbuf->buf[fbuf->index++] & 255);
+ value = (value << 8) + (fbuf->buf[fbuf->index++] & 255);
+ valout =(value << 8) + (fbuf->buf[fbuf->index++] & 255);
+ }
+
+ *out = valout;
+ return 0;
+}
+
+
+/**
+ * etch_flexbuf_get_float()
+ * @return a float from the next available bytes.
+ */
+int etch_flexbuf_get_float(etch_flexbuffer *fbuf, float* out)
+{
+ float value;
+ if (-1 == etch_flexbuf_get_int(fbuf, (int*) &value)) return -1;
+ *out = value;
+ return 0;
+}
+
+
+/**
+ * etch_flexbuf_get_double()
+ * @return a double from the next available bytes.
+ */
+int etch_flexbuf_get_double(etch_flexbuffer *fbuf, double* out)
+{
+ double value;
+ if (-1 == etch_flexbuf_get_long(fbuf, (int64*) &value)) return -1;
+ *out = value;
+ return 0;
+}
+
+
+
+/**
+ * fills a buffer fully from the next available bytes.
+ * @param b
+ * @throws IOException if avail() < b.datalen.
+ */
+size_t etch_flexbuf_get_fully( etch_flexbuffer *fbuf, byte *b, size_t bufsize )
+{
+ return etch_flexbuf_get( fbuf, b, 0, bufsize );
+}
+
+
+/**
+ * If index has moved past length during a put, then adjust length
+ * to track index.
+ */
+static void etch_flexbuf_fix_length(etch_flexbuffer *fbuf)
+{
+ if (fbuf->index > fbuf->datalen)
+ fbuf->datalen = fbuf->index;
+}
+
+
+/**
+ * Puts some bytes into the buffer as if by repeated calls to put().
+ * @param buf the source of the bytes to put.
+ * @param off the index to the first byte to put.
+ * @param bytecount the number of bytes to put.
+ * @return count of bytes put
+ */
+size_t etch_flexbuf_put (etch_flexbuffer *fbuf, byte *buf, size_t off, size_t bytecount)
+{
+ if (bytecount <= 0) return 0;
+ if (!etch_flexbuf_ensure_size (fbuf, fbuf->index + bytecount)) return 0;
+
+ memcpy(fbuf->buf + fbuf->index, buf + off, bytecount);
+ fbuf->index += bytecount;
+ etch_flexbuf_fix_length (fbuf);
+ return bytecount;
+}
+
+
+/**
+ * Copies the specified number of bytes from buf[index] into buffer
+ * as if by repeated execution of put( buf.get() ).
+ * @param buf the source of the bytes to put.
+ * @param len the number of bytes to put. if -1, copy everything.
+ * @return number of bytes put
+ */
+size_t etch_flexbuf_put_from(etch_flexbuffer *dstfb, etch_flexbuffer *srcfb, size_t bytecount)
+{
+ size_t bytes_put = 0;
+ if (bytecount == -1)
+ bytecount = srcfb->datalen - srcfb->index;
+
+ bytes_put = etch_flexbuf_put (dstfb, srcfb->buf, srcfb->index, bytecount);
+
+ etch_flexbuf_skip (srcfb, bytes_put, FALSE);
+
+ return bytes_put;
+}
+
+
+/**
+ * etch_flexbuf_put_byte()
+ * @return number of bytes put
+ */
+size_t etch_flexbuf_put_byte (etch_flexbuffer *fbuf, byte value)
+{
+ size_t bytes_put = 0;
+
+ if (etch_flexbuf_ensure_size(fbuf, fbuf->index + 1))
+ {
+ fbuf->buf[fbuf->index++] = value;
+ etch_flexbuf_fix_length(fbuf);
+ bytes_put = sizeof(value);
+ }
+
+ return bytes_put;
+}
+
+
+/**
+ * etch_flexbuf_put_short()
+ */
+size_t etch_flexbuf_put_short(etch_flexbuffer *fbuf, short value)
+{
+ if (!etch_flexbuf_ensure_size( fbuf, fbuf->index + sizeof(value) ))
+ return 0;
+
+ if (fbuf->is_littleendian)
+ {
+ fbuf->buf[fbuf->index++] = (byte) value;
+ fbuf->buf[fbuf->index++] = (byte) (value >> 8);
+ }
+ else
+ {
+ fbuf->buf[fbuf->index++] = (byte) (((unsigned short)value) >> 8);
+ fbuf->buf[fbuf->index++] = (byte) value;
+ }
+
+ etch_flexbuf_fix_length(fbuf);
+
+ return sizeof(value);
+}
+
+
+/**
+ * etch_flexbuf_put_int()
+ */
+size_t etch_flexbuf_put_int( etch_flexbuffer *fbuf, int value )
+{
+ if (!etch_flexbuf_ensure_size( fbuf, fbuf->index + sizeof(value) ))
+ return 0;
+
+ if (fbuf->is_littleendian)
+ {
+ fbuf->buf[fbuf->index++] = (byte) value;
+ fbuf->buf[fbuf->index++] = (byte) (value >> 8);
+ fbuf->buf[fbuf->index++] = (byte) (value >> 16);
+ fbuf->buf[fbuf->index++] = (byte) (value >> 24);
+ }
+ else
+ {
+ fbuf->buf[fbuf->index++] = (byte) ( ((unsigned int) value) >> 24);
+ fbuf->buf[fbuf->index++] = (byte) ( ((unsigned int) value) >> 16);
+ fbuf->buf[fbuf->index++] = (byte) ( ((unsigned int) value) >> 8);
+ fbuf->buf[fbuf->index++] = (byte) value;
+ }
+
+ etch_flexbuf_fix_length(fbuf);
+
+ return sizeof(value);
+}
+
+
+/**
+ * etch_flexbuf_put_long()
+ */
+size_t etch_flexbuf_put_long(etch_flexbuffer *fbuf, int64 value )
+{
+ if (!etch_flexbuf_ensure_size( fbuf, fbuf->index + sizeof(value) ))
+ return 0;
+
+ if (fbuf->is_littleendian)
+ {
+ fbuf->buf[fbuf->index++] = (byte) value;
+ fbuf->buf[fbuf->index++] = (byte) (value >> 8);
+ fbuf->buf[fbuf->index++] = (byte) (value >> 16);
+ fbuf->buf[fbuf->index++] = (byte) (value >> 24);
+ fbuf->buf[fbuf->index++] = (byte) (value >> 32);
+ fbuf->buf[fbuf->index++] = (byte) (value >> 40);
+ fbuf->buf[fbuf->index++] = (byte) (value >> 48);
+ fbuf->buf[fbuf->index++] = (byte) (value >> 56);
+ }
+ else
+ {
+ fbuf->buf[fbuf->index++] = (byte) ( ((uint64) value ) >> 56);
+ fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 48);
+ fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 40);
+ fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 32);
+ fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 24);
+ fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 16);
+ fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 8);
+ fbuf->buf[fbuf->index++] = (byte) value;
+ }
+
+ etch_flexbuf_fix_length(fbuf);
+
+ return sizeof(value);
+}
+
+
+/**
+ * etch_flexbuf_put_float()
+ */
+size_t etch_flexbuf_put_float( etch_flexbuffer *fbuf, float value )
+{
+ /* return etch_flexbuf_put_int( fbuf, * ((int *)( &value )) ); */
+ const unsigned int u = * ( (int*)&value );
+ return etch_flexbuf_put_int(fbuf, u);
+}
+
+
+/**
+ * etch_flexbuf_put_double()
+ */
+size_t etch_flexbuf_put_double(etch_flexbuffer *fbuf, double value )
+{
+ /* return etch_flexbuf_put_long( fbuf, *( (int64*) &value ) ); */
+ const int64 u = * ( (int64*)&value );
+ return etch_flexbuf_put_long(fbuf, u);
+}
+
+
+/**
+ * Adjusts index as if by a get or put but without transferring
+ * any data. This could be used to skip over a data item in an
+ * input or output buffer.
+ *
+ * @param len the number of bytes to skip over. Len must be
+ * >= 0. If put is false, it is an error if len > avail().
+ * If put is true, the buffer may be extended (and the buffer
+ * length adjusted).
+ *
+ * @param put if true it is ok to extend the length of the
+ * buffer.
+ *
+ * @return this flex buffer object.
+ *
+ * @throws EOFException if put is false and len > avail().
+ *
+ * @throws IOException if the max buffer size is exceeded.
+ */
+etch_flexbuffer *etch_flexbuf_skip(etch_flexbuffer *fbuf, size_t len, int put )
+{
+ if (len < 0) return NULL;
+ if (len == 0) return fbuf;
+
+ if (put)
+ {
+ etch_flexbuf_ensure_size( fbuf, fbuf->index+len );
+ fbuf->index += len;
+ etch_flexbuf_fix_length(fbuf);
+ return fbuf;
+ }
+
+ fbuf->index += len;
+ return fbuf;
+}