Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| SHA1 Hash: | 4c5cfcaed908f61eb0fb60b56cf1a1ec105f0333 |
|---|---|
| Date: | 2008-11-14 17:30:10 |
| User: | stephan |
| Comment: | minor API refactorings (some argument orders changed) |
Changes
Changes to include/s11n.net/c11n/c11n.h
| Old (b3be28219ec53288) | New (7799fac2c567514e) | |||
|---|---|---|---|---|
| 1 | #ifndef S11N_NET_C11N_H_INCLUDED | 1 | #ifndef S11N_NET_C11N_H_INCLUDED | |
| 2 | #define S11N_NET_C11N_H_INCLUDED 1 | 2 | #define S11N_NET_C11N_H_INCLUDED 1 | |
| 3 | 3 | |||
| 4 | /** @page c11n_page_main c11n: generic serialization library for C | 4 | /** @page c11n_page_main c11n: generic serialization library for C | |
| 5 | 5 | |||
| 116 hidden lines | ||||
| 122 | with a compiler-specific switch. | 122 | with a compiler-specific switch. | |
| 123 | 123 | |||
| 124 | - Some patience. It's beta. | 124 | - Some patience. It's beta. | |
| 125 | 125 | |||
| 126 | 126 | |||
| > | 127 | @section c11n_sec_example_ultrabrief Exceedingly brief example | ||
| > | 128 | |||
| > | 129 | Here's a very sample of what using c11n looks like. Assume we have | ||
| > | 130 | a custom struct type which looks like: | ||
| > | 131 | |||
| > | 132 | @code | ||
| > | 133 | typedef struct MyList | ||
| > | 134 | { | ||
| > | 135 | int x; | ||
| > | 136 | int y; | ||
| > | 137 | struct MyList * left; | ||
| > | 138 | struct MyList * right; | ||
| > | 139 | } MyList; | ||
| > | 140 | @endcode | ||
| > | 141 | |||
| > | 142 | MyList objects represent a singly-linked list. In this case | ||
| > | 143 | each list entry contains two values, though for the general | ||
| > | 144 | case that is irrelevant. | ||
| > | 145 | |||
| > | 146 | With a bit of code in place for converting MyList objects | ||
| > | 147 | to/from c11n (we won't show that here), we can sae | ||
| > | 148 | a MyList list with: | ||
| > | 149 | |||
| > | 150 | @code | ||
| > | 151 | MyList list; | ||
| > | 152 | ... populate list ... | ||
| > | 153 | c11n_stream * str = | ||
| > | 154 | c11n_stream_for_filename( "myfile.c11n", true );//true==write mode | ||
| > | 155 | c11n_save_serializable( str, MyList_c11n, &list, 0 ); | ||
| > | 156 | str->api->destroy(str); | ||
| > | 157 | @endcode | ||
| > | 158 | |||
| > | 159 | We can load it using: | ||
| > | 160 | |||
| > | 161 | @code | ||
| > | 162 | c11n_stream * str = | ||
| > | 163 | c11n_stream_for_filename( "myfile.c11n", false );//false==read mode | ||
| > | 164 | MyList * list = c11n_load_serializable( str, MyList_c11n ); | ||
| > | 165 | str->api->destroy(str); | ||
| > | 166 | @endcode | ||
| > | 167 | |||
| > | 168 | There is also an approach for loading serialized data into | ||
| > | 169 | an existing object, rather than creating a new one. | ||
| > | 170 | |||
| > | 171 | While the API is actually ignorant of what file format it uses, | ||
| > | 172 | here's an example of what a MyList list looks like in an | ||
| > | 173 | XML dialect: | ||
| > | 174 | |||
| > | 175 | @code | ||
| > | 176 | <!DOCTYPE s11n::io::expat_serializer> | ||
| > | 177 | <c11n_root_node class='MyList'> | ||
| > | 178 | <items class='MyListList'> | ||
| > | 179 | <item class='MyListItem'> | ||
| > | 180 | <xy>1 -1</xy> | ||
| > | 181 | </item> | ||
| > | 182 | <item class='MyListItem'> | ||
| > | 183 | <xy>2 -2</xy> | ||
| > | 184 | </item> | ||
| > | 185 | <item class='MyListItem'> | ||
| > | 186 | <xy>3 -3</xy> | ||
| > | 187 | </item> | ||
| > | 188 | </items> | ||
| > | 189 | </c11n_root_node> | ||
| > | 190 | @endcode | ||
| > | 191 | |||
| > | 192 | |||
| 127 | @section c11n_sec_cerializable Serializable types | 193 | @section c11n_sec_cerializable Serializable types | |
| 128 | 194 | |||
| 129 | In c11n, serialization happens via marshaller objects which copy | 195 | In c11n, serialization happens via marshaller objects which copy | |
| 130 | object state to c11n_nodes (essentially a DOM tree) for serialization. | 196 | object state to c11n_nodes (essentially a DOM tree) for serialization. | |
| 131 | For deserialization the marshallers restore an object from data | 197 | For deserialization the marshallers restore an object from data | |
| 1251 hidden lines | ||||
| 1383 | for use as the deserialization target. The new object is created using | 1449 | for use as the deserialization target. The new object is created using | |
| 1384 | marshaller->api->create(). If deserialization fails the new object is | 1450 | marshaller->api->create(). If deserialization fails the new object is | |
| 1385 | deallocated using marshaller->api->destroy(), otherwise it is returned to | 1451 | deallocated using marshaller->api->destroy(), otherwise it is returned to | |
| 1386 | the caller, who takes over ownership of the object. | 1452 | the caller, who takes over ownership of the object. | |
| 1387 | 1453 | |||
| 1388 | WARNINGS AND BUGS: | | | 1454 | Bit fat hairy warning: |
| 1389 | 1455 | |||
| 1390 | This routine cannot work with c11n_marshaller_pod_string. See that type | | | 1456 | This routine cannot work with marshallers which require passing a pointer |
| 1391 | for details. | | | 1457 | to a pointer to an object, as opposed to a pointer to an object. If passed |
| | | 1458 | such a marshaller this routine might silently leak memory. | ||
| 1392 | */ | 1459 | */ | |
| 1393 | void * c11n_deserialize_new( c11n_node const * src, c11n_marshaller const * marshaller ); | 1460 | void * c11n_deserialize_new( c11n_node const * src, c11n_marshaller const * marshaller ); | |
| 1394 | 1461 | |||
| 1395 | /** | 1462 | /** | |
| 1396 | Uses the given marshaller to clone ct using its serialization | 1463 | Uses the given marshaller to clone ct using its serialization | |
| 1397 | API. On success it returns a new instance of ct, populated | 1464 | API. On success it returns a new instance of ct, populated | |
| 1398 | with the data serialized by the marshaller. | | | 1465 | with the data (de)serialized by the marshaller. On error it |
| | | 1466 | returns 0. | ||
| 1399 | 1467 | |||
| 1400 | The caller is responsible for freeing the returned object using | 1468 | The caller is responsible for freeing the returned object using | |
| 1401 | marhshaller->destroy(marhshaller,thatObject) or equivalent | | | 1469 | marshaller->destroy(marshaller,thatObject), or the equivalent |
| 1402 | for the given type. | 1470 | for the given type. | |
| > | 1471 | |||
| > | 1472 | Tip: | ||
| > | 1473 | |||
| > | 1474 | Cloning is an easy way to test the de/serialization routines | ||
| > | 1475 | for a given marshaller. If cloning works then one can be sure | ||
| > | 1476 | that de/serialization as a whole works. | ||
| 1403 | */ | 1477 | */ | |
| 1404 | void * c11n_clone( c11n_marshaller const * marshaller, void * ct ); | 1478 | void * c11n_clone( c11n_marshaller const * marshaller, void * ct ); | |
| 1405 | 1479 | |||
| 1406 | /** | 1480 | /** | |
| 1407 | Returns true if key is equal to val, in the lexical comparison sense | 1481 | Returns true if key is equal to val, in the lexical comparison sense | |
| 330 hidden lines | ||||
| 1738 | void * data; | 1812 | void * data; | |
| 1739 | /** See c11n_deserialize_binary(). */ | 1813 | /** See c11n_deserialize_binary(). */ | |
| 1740 | size_t size; | 1814 | size_t size; | |
| 1741 | } c11n_binary_data; | 1815 | } c11n_binary_data; | |
| 1742 | /** | 1816 | /** | |
| 1743 | UNTESTED! | < | ||
| 1744 | < | |||
| 1745 | The converse of c11n_serialize_binary(). The caller must supply a non-null | 1817 | The converse of c11n_serialize_binary(). The caller must supply a non-null | |
| 1746 | dest pointer. The serialized data pulled from src is stored in dest. | 1818 | dest pointer. The serialized data pulled from src is stored in dest. | |
| 1747 | If dest->data points to an object before this call then the caller | 1819 | If dest->data points to an object before this call then the caller | |
| 1748 | should clean it up (if appropriate) before calling this, as this call | 1820 | should clean it up (if appropriate) before calling this, as this call | |
| 1749 | will overwrite that pointer. | 1821 | will overwrite that pointer. | |
| 41 hidden lines | ||||
| 1791 | #ifdef __cplusplus | 1863 | #ifdef __cplusplus | |
| 1792 | } /* extern "C" */ | 1864 | } /* extern "C" */ | |
| 1793 | #endif | 1865 | #endif | |
| 1794 | 1866 | |||
| 1795 | #endif /* S11N_NET_C11N_H_INCLUDED */ | 1867 | #endif /* S11N_NET_C11N_H_INCLUDED */ | |
Changes to include/s11n.net/c11n/io/c11n_io.h
| Old (2df8e7de086cd98b) | New (434d46e32819ffdc) | |||
|---|---|---|---|---|
| 1 | #ifndef S11N_NET_C11N_IO_H_INCLUDED | 1 | #ifndef S11N_NET_C11N_IO_H_INCLUDED | |
| 2 | #define S11N_NET_C11N_IO_H_INCLUDED 1 | 2 | #define S11N_NET_C11N_IO_H_INCLUDED 1 | |
| 3 | /* | 3 | /* | |
| 4 | This file contains declarations and documentation for the generic | 4 | This file contains declarations and documentation for the generic | |
| 5 | i/o routines for c11n. The core does not know about this API and no | 5 | i/o routines for c11n. The core does not know about this API and no | |
| 227 hidden lines | ||||
| 233 | */ | 233 | */ | |
| 234 | struct c11n_stream_api | 234 | struct c11n_stream_api | |
| 235 | { | 235 | { | |
| 236 | /** | 236 | /** | |
| 237 | isgood() returns whether or not self is in a valid use state. | 237 | isgood() returns whether or not self is in a valid use state. | |
| 238 | It should not return true on eof, as eof is not strictly an | | | 238 | It should return true on eof, as eof is not strictly an error. |
| 239 | error. To report EOF it should return 0 from the read() | | | 239 | To report EOF it should return 0 from the read() |
| 240 | implementation. | 240 | implementation. | |
| 241 | */ | 241 | */ | |
| 242 | bool (*isgood)( struct c11n_stream * self ); | 242 | bool (*isgood)( struct c11n_stream * self ); | |
| 243 | /** | 243 | /** | |
| 244 | read() must read (at most) count bytes from its underlying | 244 | read() must read (at most) count bytes from its underlying | |
| 511 hidden lines | ||||
| 756 | 756 | |||
| 757 | Note that this routine is ONLY for saving root nodes. That is, one | 757 | Note that this routine is ONLY for saving root nodes. That is, one | |
| 758 | node per stream. Subnodes will be written out as part of the src | 758 | node per stream. Subnodes will be written out as part of the src | |
| 759 | tree. | 759 | tree. | |
| 760 | */ | 760 | */ | |
| 761 | bool c11n_save_node( c11n_node const * src, c11n_stream * dest, c11n_io_handler * h ); | | | 761 | bool c11n_save_node( c11n_stream * dest, c11n_node const * src, c11n_io_handler * h ); |
| 762 | 762 | |||
| 763 | /** | 763 | /** | |
| 764 | Works similarly to c11n_load_node(), except that it goes one step further and tries to | 764 | Works similarly to c11n_load_node(), except that it goes one step further and tries to | |
| 765 | deserialize that node into a new object. If a node can be loaded (as described for | 765 | deserialize that node into a new object. If a node can be loaded (as described for | |
| 766 | c11n_load_node()) then a new object is created via m->api->create(m). That object | 766 | c11n_load_node()) then a new object is created via m->api->create(m). That object | |
| 14 hidden lines | ||||
| 781 | 781 | |||
| 782 | Note that this routine is ONLY for saving top-level objects. That | 782 | Note that this routine is ONLY for saving top-level objects. That | |
| 783 | is, one object per stream. Children of src will be written out as | 783 | is, one object per stream. Children of src will be written out as | |
| 784 | part of the serialization of src. | 784 | part of the serialization of src. | |
| 785 | */ | 785 | */ | |
| 786 | bool c11n_save_serializable( c11n_marshaller const * marshaller, void const * src, c11n_stream * dest, c11n_io_handler * h ); | | | 786 | bool c11n_save_serializable( c11n_stream * dest, c11n_marshaller const * marshaller, void const * src, c11n_io_handler * h ); |
| 787 | 787 | |||
| 788 | 788 | |||
| 789 | /** | 789 | /** | |
| 790 | A type for implementing string escape tables. Not a terribly | 790 | A type for implementing string escape tables. Not a terribly | |
| 791 | efficient way to do string escaping, but quite flexible. For | 791 | efficient way to do string escaping, but quite flexible. For | |
| 96 hidden lines | ||||
| 888 | #ifdef __cplusplus | 888 | #ifdef __cplusplus | |
| 889 | } /* extern "C" */ | 889 | } /* extern "C" */ | |
| 890 | #endif | 890 | #endif | |
| 891 | 891 | |||
| 892 | #endif // S11N_NET_C11N_IO_H_INCLUDED | 892 | #endif // S11N_NET_C11N_IO_H_INCLUDED | |
Changes to src/Doxyfile.at
| Old (dd9755ed47933e37) | New (b3bd50b28e263790) | |||
|---|---|---|---|---|
| 1 | # Doxyfile 1.5.5 | 1 | # Doxyfile 1.5.5 | |
| 2 | 2 | |||
| 3 | # This file describes the settings to be used by the documentation system | 3 | # This file describes the settings to be used by the documentation system | |
| 4 | # doxygen (www.doxygen.org) for a project | 4 | # doxygen (www.doxygen.org) for a project | |
| 5 | # | 5 | # | |
| 548 hidden lines | ||||
| 554 | # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude | 554 | # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude | |
| 555 | # certain files from those directories. Note that the wildcards are matched | 555 | # certain files from those directories. Note that the wildcards are matched | |
| 556 | # against the file with absolute path, so to exclude all test directories | 556 | # against the file with absolute path, so to exclude all test directories | |
| 557 | # for example use the pattern */test/* | 557 | # for example use the pattern */test/* | |
| 558 | 558 | |||
| 559 | EXCLUDE_PATTERNS = whgc.* \ | | | 559 | EXCLUDE_PATTERNS = */b64/* \ |
| | | 560 | whgc.* \ | ||
| 560 | My*.* test*.* | 561 | My*.* test*.* | |
| 561 | 562 | |||
| 562 | # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names | 563 | # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names | |
| 563 | # (namespaces, classes, functions, etc.) that should be excluded from the | 564 | # (namespaces, classes, functions, etc.) that should be excluded from the | |
| 564 | # output. The symbol name can be a fully qualified name, a word, or if the | 565 | # output. The symbol name can be a fully qualified name, a word, or if the | |
| 790 hidden lines | ||||
| 1355 | 1356 | |||
| 1356 | # The SEARCHENGINE tag specifies whether or not a search engine should be | 1357 | # The SEARCHENGINE tag specifies whether or not a search engine should be | |
| 1357 | # used. If set to NO the values of all tags below this one will be ignored. | 1358 | # used. If set to NO the values of all tags below this one will be ignored. | |
| 1358 | 1359 | |||
| 1359 | SEARCHENGINE = NO | 1360 | SEARCHENGINE = NO | |
Changes to src/Makefile
| Old (7db471d71f7f96e9) | New (3796d7feebfde657) | |||
|---|---|---|---|---|
| 1 | #!/usr/bin/make -f | 1 | #!/usr/bin/make -f | |
| 2 | # Requires GNU Make 3.80+! | 2 | # Requires GNU Make 3.80+! | |
| 3 | default: all | 3 | default: all | |
| 4 | 4 | |||
| 5 | ifeq (1,$(TCC)) | 5 | ifeq (1,$(TCC)) | |
| 153 hidden lines | ||||
| 159 | libs: $(libc11n.DLL) | 159 | libs: $(libc11n.DLL) | |
| 160 | endif | 160 | endif | |
| 161 | 161 | |||
| 162 | test.o: CFLAGS += -Wno-format | 162 | test.o: CFLAGS += -Wno-format | |
| 163 | test.BIN.LDFLAGS := $(libc11n.LIB) $(libwhgc.LIB) $(EXPAT_LDFLAGS) | 163 | test.BIN.LDFLAGS := $(libc11n.LIB) $(libwhgc.LIB) $(EXPAT_LDFLAGS) | |
| 164 | test.BIN.OBJECTS := test.o MyType.o MyGraph.o | | | 164 | test.BIN.OBJECTS := test.o MyType.o MyList.o |
| 165 | ifeq (1,$(USE_SQLITE3)) | 165 | ifeq (1,$(USE_SQLITE3)) | |
| 166 | test.BIN.LDFLAGS += $(SQLITE3.LDFLAGS) | 166 | test.BIN.LDFLAGS += $(SQLITE3.LDFLAGS) | |
| 167 | endif | 167 | endif | |
| 168 | 168 | |||
| 169 | $(call ShakeNMake.CALL.RULES.BINS,test) | 169 | $(call ShakeNMake.CALL.RULES.BINS,test) | |
| 33 hidden lines | ||||
| 203 | #$(MEGA.BIN): $(libc11n.LIB) $(libwhgc.LIB) | 203 | #$(MEGA.BIN): $(libc11n.LIB) $(libwhgc.LIB) | |
| 204 | # tcc $(INCLUDES) -r -o $(MEGA.OBJ) $(wildcard c11n*.c wh*.c vappendf.c) | 204 | # tcc $(INCLUDES) -r -o $(MEGA.OBJ) $(wildcard c11n*.c wh*.c vappendf.c) | |
| 205 | # tcc -o $(MEGA.BIN) $(MEGA.OBJ) $(SQLITE3.LDFLAGS) | 205 | # tcc -o $(MEGA.BIN) $(MEGA.OBJ) $(SQLITE3.LDFLAGS) | |
| 206 | 206 | |||
| 207 | all: libs bins | 207 | all: libs bins | |
Added src/MyList.c
| Old () | New (347096726de2ca7e) | |||
|---|---|---|---|---|
| > | 1 | /** | ||
| > | 2 | Example of one approach to serializing a linked list using c11n. Note that this | ||
| > | 3 | does not support cycles! It can be done in c11n, but requires a bit of effort. | ||
| > | 4 | There is no single plug-in algorithm which works for all graph types, so we | ||
| > | 5 | can't provide a generic solution to that problem. | ||
| > | 6 | |||
| > | 7 | All of the functions shown here are either required by the | ||
| > | 8 | c11n_marshaller_api API or are helper functions for implementing | ||
| > | 9 | those required by c11n_marshaller_api. | ||
| > | 10 | */ | ||
| > | 11 | #include "MyList.h" | ||
| > | 12 | #include <stdlib.h> | ||
| > | 13 | #include <stdio.h> | ||
| > | 14 | |||
| > | 15 | #if 1 | ||
| > | 16 | #define MARKER if(1) printf("MARKER: %s:%d:%s(): ",__FILE__,__LINE__,__func__); if(1) printf | ||
| > | 17 | #else | ||
| > | 18 | #define if(0) printf | ||
| > | 19 | #endif | ||
| > | 20 | |||
| > | 21 | /** | ||
| > | 22 | A helper routine for MyList_serialize(). | ||
| > | 23 | */ | ||
| > | 24 | static bool MyList_serialize_one( MyList const * g, c11n_node * dest ) | ||
| > | 25 | { | ||
| > | 26 | c11n_node_set_class( dest, "MyListItem" ); | ||
| > | 27 | c11n_node_prop_set_fe( dest, "xy", "%d %d", g->x, g->y ); | ||
| > | 28 | return true; | ||
| > | 29 | } | ||
| > | 30 | |||
| > | 31 | /** | ||
| > | 32 | Requires that src is-a pointer to a MyList object. This routine | ||
| > | 33 | serializes ALL nodes linked from src as a list of entries. At | ||
| > | 34 | deserialization time the links to those items are re-established. | ||
| > | 35 | */ | ||
| > | 36 | static bool MyList_serialize( struct c11n_marshaller const * self, c11n_node * dest, void const * src ) | ||
| > | 37 | { | ||
| > | 38 | c11n_node_set_class( dest, self->api->classname ); | ||
| > | 39 | MyList const * me = (MyList const *)src; | ||
| > | 40 | |||
| > | 41 | MyList const * h = me; | ||
| > | 42 | while( h->left ) h = h->left; | ||
| > | 43 | MyList const * at = h; | ||
| > | 44 | c11n_node * nlist = c11n_node_create_child( dest, "items" ); | ||
| > | 45 | c11n_node_set_class( nlist, "MyListList" ); | ||
| > | 46 | while( at ) | ||
| > | 47 | { | ||
| > | 48 | MARKER("Serializing MyList item @%p...\n",(void const *)at); | ||
| > | 49 | c11n_node * ch = c11n_node_create_child( nlist, "item" ); | ||
| > | 50 | if( ! MyList_serialize_one( at, ch ) ) return false; | ||
| > | 51 | at = at->right; | ||
| > | 52 | } | ||
| > | 53 | return true; | ||
| > | 54 | } | ||
| > | 55 | |||
| > | 56 | /** | ||
| > | 57 | A helper routine for MyList_deserialize(). | ||
| > | 58 | */ | ||
| > | 59 | static bool MyList_deserialize_one( c11n_node const * src, MyList * dest ) | ||
| > | 60 | { | ||
| > | 61 | return (2 == c11n_node_prop_get_fe( src, "xy", "%d %d", &dest->x, &dest->y )); | ||
| > | 62 | } | ||
| > | 63 | |||
| > | 64 | /** | ||
| > | 65 | The invert of MyList_serialize, it requires that src be-a pointer | ||
| > | 66 | to a non-null (but empty!) MyList object. It tries to deserialize a | ||
| > | 67 | list of MyList objects from src. If successful then the head of that list | ||
| > | 68 | is copied over dest, effectively transfering ownership of all list entries | ||
| > | 69 | to dest. On error dest is not modified. | ||
| > | 70 | */ | ||
| > | 71 | static bool MyList_deserialize( struct c11n_marshaller const * self, c11n_node const *src, void * dest ) | ||
| > | 72 | { | ||
| > | 73 | if( ! self || !src || !dest ) return false; | ||
| > | 74 | c11n_node const * nitems = c11n_node_children_search_c( src, c11n_node_predicate_name_is, "items" ); | ||
| > | 75 | if( ! nitems ) return 0; | ||
| > | 76 | c11n_node_iter_c iter = c11n_node_children_iter_c(nitems); | ||
| > | 77 | MyList * current = 0; | ||
| > | 78 | MyList * head = 0; | ||
| > | 79 | bool isokay = true; | ||
| > | 80 | while( c11n_node_iter_isvalid_c( &iter ) ) | ||
| > | 81 | { | ||
| > | 82 | MyList * ml = (MyList*) self->api->create(self); | ||
| > | 83 | MARKER("Deserializing MyList item @%p...\n",(void const *)ml); | ||
| > | 84 | isokay = (ml && MyList_deserialize_one( iter.node, ml )); | ||
| > | 85 | if( ! head ) | ||
| > | 86 | { | ||
| > | 87 | current = head = ml; | ||
| > | 88 | } | ||
| > | 89 | else if(ml) | ||
| > | 90 | { | ||
| > | 91 | current->right = ml; | ||
| > | 92 | ml->left = current; | ||
| > | 93 | current = ml; | ||
| > | 94 | } | ||
| > | 95 | if( ! isokay ) | ||
| > | 96 | { | ||
| > | 97 | if( head ) | ||
| > | 98 | { | ||
| > | 99 | self->api->destroy(self,head); | ||
| > | 100 | } | ||
| > | 101 | return false; | ||
| > | 102 | } | ||
| > | 103 | c11n_node_iter_next_c(&iter); | ||
| > | 104 | } | ||
| > | 105 | if( 0 != head ) | ||
| > | 106 | { | ||
| > | 107 | MyList * me = (MyList *)dest; | ||
| > | 108 | *me = *head; | ||
| > | 109 | free(head); | ||
| > | 110 | return true; | ||
| > | 111 | } | ||
| > | 112 | else return false; | ||
| > | 113 | } | ||
| > | 114 | |||
| > | 115 | /** | ||
| > | 116 | Creates a single MyList item with all values inited to 0. | ||
| > | 117 | */ | ||
| > | 118 | static void * MyList_create( struct c11n_marshaller const * self) | ||
| > | 119 | { | ||
| > | 120 | static MyList MyList_init = {0,0,0,0}; | ||
| > | 121 | MyList * x = (MyList*) malloc(sizeof(MyList)); | ||
| > | 122 | if( x ) *x = MyList_init; | ||
| > | 123 | return x; | ||
| > | 124 | } | ||
| > | 125 | |||
| > | 126 | /** | ||
| > | 127 | Sets all values of ALL neighboring items to 0. Does not actually | ||
| > | 128 | free any items. This isn't a useful practical implementation, but | ||
| > | 129 | it's useful for demonstration purposes. | ||
| > | 130 | */ | ||
| > | 131 | static void MyList_clear( struct c11n_marshaller const * self, void * obj ) | ||
| > | 132 | { | ||
| > | 133 | if( !obj ) return; | ||
| > | 134 | MARKER("Clearing MyList values.\n"); | ||
| > | 135 | MyList * h = (MyList*) obj; | ||
| > | 136 | while( h->left ) h = h->left; | ||
| > | 137 | while( h ) | ||
| > | 138 | { | ||
| > | 139 | h->x = h->y = 0; | ||
| > | 140 | h = h->right; | ||
| > | 141 | } | ||
| > | 142 | } | ||
| > | 143 | |||
| > | 144 | /** | ||
| > | 145 | Deallocates ALL neighboring items. | ||
| > | 146 | */ | ||
| > | 147 | static void MyList_destroy( struct c11n_marshaller const * self, void * obj ) | ||
| > | 148 | { | ||
| > | 149 | if( !obj ) return; | ||
| > | 150 | MARKER("Destroying MyList list.\n"); | ||
| > | 151 | //MyList_clear( self, obj ); /* If MyList_clear() was responsible for freeing any memory we would need to call it here. */ | ||
| > | 152 | MyList * h = (MyList*) obj; | ||
| > | 153 | while( h->left ) h = h->left; | ||
| > | 154 | while( h ) | ||
| > | 155 | { | ||
| > | 156 | MyList * x = h->right; | ||
| > | 157 | free(h); | ||
| > | 158 | h = x; | ||
| > | 159 | } | ||
| > | 160 | } | ||
| > | 161 | |||
| > | 162 | static const c11n_marshaller_api c11n_markshaller_api_MyList = | ||
| > | 163 | C11N_MARSHALLER_API_INIT("MyList", | ||
| > | 164 | MyList_serialize, | ||
| > | 165 | MyList_deserialize, | ||
| > | 166 | MyList_create, | ||
| > | 167 | MyList_clear, | ||
| > | 168 | MyList_destroy); | ||
| > | 169 | |||
| > | 170 | static const c11n_marshaller MyList_c11nX = { &c11n_markshaller_api_MyList }; | ||
| > | 171 | const c11n_marshaller * MyList_c11n = &MyList_c11nX; | ||
Added src/MyList.h
| Old () | New (98969ba5402a4946) | |||
|---|---|---|---|---|
| > | 1 | /* example class for use with libc11n */ | ||
| > | 2 | #include "s11n.net/c11n/c11n.h" | ||
| > | 3 | struct MyList | ||
| > | 4 | { | ||
| > | 5 | int x; | ||
| > | 6 | int y; | ||
| > | 7 | struct MyList * left; | ||
| > | 8 | struct MyList * right; | ||
| > | 9 | }; | ||
| > | 10 | typedef struct MyList MyList; | ||
| > | 11 | /** | ||
| > | 12 | c11n marshaller for MyList objects. | ||
| > | 13 | */ | ||
| > | 14 | extern const c11n_marshaller * MyList_c11n; | ||
Changes to src/c11n_io.c
| Old (0ffdba378af16ac7) | New (fd8c564e1eb5cf41) | |||
|---|---|---|---|---|
| 1 | #ifndef _FILE_OFFSET_BITS | 1 | #ifndef _FILE_OFFSET_BITS | |
| 2 | /** See 'man feature_test_macros' on a gcc system */ | 2 | /** See 'man feature_test_macros' on a gcc system */ | |
| 3 | # define _FILE_OFFSET_BITS 64 | 3 | # define _FILE_OFFSET_BITS 64 | |
| 4 | #endif | 4 | #endif | |
| 5 | #ifndef _ISOC99_SOURCE | 5 | #ifndef _ISOC99_SOURCE | |
| 330 hidden lines | ||||
| 336 | h->api->destroy(h); | 336 | h->api->destroy(h); | |
| 337 | } | 337 | } | |
| 338 | return n; | 338 | return n; | |
| 339 | } | 339 | } | |
| 340 | 340 | |||
| 341 | bool c11n_save_node( c11n_node const * src, c11n_stream * dest, c11n_io_handler * h ) | | | 341 | bool c11n_save_node( c11n_stream * dest, c11n_node const * src, c11n_io_handler * h ) |
| 342 | { | 342 | { | |
| 343 | bool ownHandler = (h==0); | 343 | bool ownHandler = (h==0); | |
| 344 | if( ! src || !dest || !dest->api->isgood(dest) ) return false; | 344 | if( ! src || !dest || !dest->api->isgood(dest) ) return false; | |
| 345 | if( ! h ) | 345 | if( ! h ) | |
| 346 | { | 346 | { | |
| 6 hidden lines | ||||
| 353 | if( ownHandler ) h->api->destroy(h); | 353 | if( ownHandler ) h->api->destroy(h); | |
| 354 | } | 354 | } | |
| 355 | return rc; | 355 | return rc; | |
| 356 | } | 356 | } | |
| 357 | 357 | |||
| 358 | bool c11n_save_serializable( c11n_marshaller const * marshaller, void const * src, c11n_stream * dest, c11n_io_handler * h ) | | | 358 | bool c11n_save_serializable( c11n_stream * dest, c11n_marshaller const * marshaller, void const * src, c11n_io_handler * h ) |
| 359 | { | 359 | { | |
| 360 | c11n_node * n = c11n_node_create("c11n_root_node"); | 360 | c11n_node * n = c11n_node_create("c11n_root_node"); | |
| 361 | bool rc = (n!=0); | 361 | bool rc = (n!=0); | |
| 362 | if( rc ) | 362 | if( rc ) | |
| 363 | { | 363 | { | |
| 364 | rc = c11n_serialize( n, marshaller, src ) | 364 | rc = c11n_serialize( n, marshaller, src ) | |
| 365 | && c11n_save_node( n, dest, h ); | | | 365 | && c11n_save_node( dest, n, h ); |
| 366 | c11n_node_destroy(n); | 366 | c11n_node_destroy(n); | |
| 367 | } | 367 | } | |
| 368 | return rc; | 368 | return rc; | |
| 369 | } | 369 | } | |
| 370 | 370 | |||
| 94 hidden lines | ||||
| 465 | } | 465 | } | |
| 466 | 466 | |||
| 467 | #ifdef __cplusplus | 467 | #ifdef __cplusplus | |
| 468 | } /* extern "C" */ | 468 | } /* extern "C" */ | |
| 469 | #endif | 469 | #endif | |
Changes to src/test.c
| Old (caa3355a092dd802) | New (4730a67623abf384) | |||
|---|---|---|---|---|
| 1 | #include <stdio.h> | 1 | #include <stdio.h> | |
| 2 | #include <stdlib.h> | 2 | #include <stdlib.h> | |
| 3 | #include <string.h> | 3 | #include <string.h> | |
| 4 | #include <ctype.h> | 4 | #include <ctype.h> | |
| 5 | #include <assert.h> | 5 | #include <assert.h> | |
| 193 hidden lines | ||||
| 199 | else | 199 | else | |
| 200 | { | 200 | { | |
| 201 | c11n_node * de = c11n_node_create( "deserialized" ); | 201 | c11n_node * de = c11n_node_create( "deserialized" ); | |
| 202 | c11n_serialize( de, TR, my2 ); | 202 | c11n_serialize( de, TR, my2 ); | |
| 203 | MARKER("c11n_deserialize_new() got:\n"); | 203 | MARKER("c11n_deserialize_new() got:\n"); | |
| 204 | c11n_save_node( de, ThisApp.cout, 0 ); | | | 204 | c11n_save_node( ThisApp.cout, de, 0 ); |
| 205 | c11n_node_destroy(de); | 205 | c11n_node_destroy(de); | |
| 206 | TR->api->destroy(TR,my2); | 206 | TR->api->destroy(TR,my2); | |
| 207 | } | 207 | } | |
| 208 | my2 = c11n_clone( TR, &yourMyVal ); | 208 | my2 = c11n_clone( TR, &yourMyVal ); | |
| 209 | if( ! my2 ) | 209 | if( ! my2 ) | |
| 5 hidden lines | ||||
| 215 | else | 215 | else | |
| 216 | { | 216 | { | |
| 217 | c11n_node * de = c11n_node_create( "cloned" ); | 217 | c11n_node * de = c11n_node_create( "cloned" ); | |
| 218 | c11n_serialize( de, TR, my2 ); | 218 | c11n_serialize( de, TR, my2 ); | |
| 219 | MARKER("c11n_clone_new() got:\n"); | 219 | MARKER("c11n_clone_new() got:\n"); | |
| 220 | c11n_save_node( de, ThisApp.cout, 0 ); | | | 220 | c11n_save_node( ThisApp.cout, de, 0 ); |
| 221 | c11n_node_destroy(de); | 221 | c11n_node_destroy(de); | |
| 222 | TR->api->destroy(TR,my2); | 222 | TR->api->destroy(TR,my2); | |
| 223 | } | 223 | } | |
| 224 | 224 | |||
| 225 | TR->api->clear( TR, &yourMyVal ); | 225 | TR->api->clear( TR, &yourMyVal ); | |
| 227 | #endif | 227 | #endif | |
| 228 | 228 | |||
| 229 | //c11n_dump_node( N, true ); | 229 | //c11n_dump_node( N, true ); | |
| 230 | 230 | |||
| 231 | c11n_stream * o1t = c11n_stream_for_FILE( stdout ); | 231 | c11n_stream * o1t = c11n_stream_for_FILE( stdout ); | |
| 232 | if( ! c11n_save_node( N, o1t, 0 ) || !c11n_save_node( MY, o1t, 0 )) | | | 232 | if( ! c11n_save_node( o1t, N, 0 ) || !c11n_save_node( o1t, MY, 0 )) |
| 233 | { | 233 | { | |
| 234 | MARKER("test save failed\n"); | 234 | MARKER("test save failed\n"); | |
| 235 | o1t->api->destroy(o1t); | 235 | o1t->api->destroy(o1t); | |
| 236 | c11n_node_destroy(N); | 236 | c11n_node_destroy(N); | |
| 237 | return 22; | 237 | return 22; | |
| 132 hidden lines | ||||
| 370 | bob.close_node( &bob ); | 370 | bob.close_node( &bob ); | |
| 371 | SHOW; | 371 | SHOW; | |
| 372 | char const * ofile = "saveload.out"; | 372 | char const * ofile = "saveload.out"; | |
| 373 | c11n_stream * ostr = c11n_stream_for_filename( ofile, true ); | 373 | c11n_stream * ostr = c11n_stream_for_filename( ofile, true ); | |
| 374 | MARKER("ostr @%p, implData @%p\n",ostr,ostr->implData); | 374 | MARKER("ostr @%p, implData @%p\n",ostr,ostr->implData); | |
| 375 | bool rv = c11n_save_node( bob.root_node, ostr, 0 ); | | | 375 | bool rv = c11n_save_node( ostr, bob.root_node, 0 ); |
| 376 | ostr->api->destroy(ostr); | 376 | ostr->api->destroy(ostr); | |
| 377 | #if 1 | 377 | #if 1 | |
| 378 | if( ! rv ) | 378 | if( ! rv ) | |
| 379 | { | 379 | { | |
| 380 | MARKER("Save of %s failed :(\n",ofile); | 380 | MARKER("Save of %s failed :(\n",ofile); | |
| 381 | bob.clear(&bob); | 381 | bob.clear(&bob); | |
| 382 | return -1; | 382 | return -1; | |
| 383 | } | 383 | } | |
| 384 | c11n_save_node( bob.root_node, ThisApp.cout, 0 ); | | | 384 | c11n_save_node( ThisApp.cout, bob.root_node, 0 ); |
| 385 | bob.clear(&bob); | 385 | bob.clear(&bob); | |
| 386 | ostr = c11n_stream_for_filename( ofile, false ); | 386 | ostr = c11n_stream_for_filename( ofile, false ); | |
| 387 | c11n_node * x = c11n_load_node( ostr ); // | 387 | c11n_node * x = c11n_load_node( ostr ); // | |
| 388 | ostr->api->destroy(ostr); | 388 | ostr->api->destroy(ostr); | |
| 389 | MARKER("x=%p\n",x); | 389 | MARKER("x=%p\n",x); | |
| 390 | if( x ) | 390 | if( x ) | |
| 391 | { | 391 | { | |
| 392 | MARKER("Loaded x @%p from file %s.\n",x,ofile); | 392 | MARKER("Loaded x @%p from file %s.\n",x,ofile); | |
| 393 | c11n_save_node( x, ThisApp.cout, 0 ); | | | 393 | c11n_save_node( ThisApp.cout, x, 0 ); |
| 394 | c11n_node_destroy(x); | 394 | c11n_node_destroy(x); | |
| 395 | MARKER("(end of loaded data)\n"); | 395 | MARKER("(end of loaded data)\n"); | |
| 396 | } | 396 | } | |
| 397 | else | 397 | else | |
| 398 | { | 398 | { | |
| 68 hidden lines | ||||
| 467 | { | 467 | { | |
| 468 | MARKER("serialize binary failed!\n"); | 468 | MARKER("serialize binary failed!\n"); | |
| 469 | c11n_node_destroy( n ); | 469 | c11n_node_destroy( n ); | |
| 470 | return 1; | 470 | return 1; | |
| 471 | } | 471 | } | |
| 472 | c11n_save_node( n, ThisApp.cout, 0 ); | | | 472 | c11n_save_node( ThisApp.cout, n, 0 ); |
| 473 | 473 | |||
| 474 | MyType my2; | 474 | MyType my2; | |
| 475 | c11n_binary_data bin; | 475 | c11n_binary_data bin; | |
| 476 | if( ! c11n_deserialize_binary( n, &bin ) ) | 476 | if( ! c11n_deserialize_binary( n, &bin ) ) | |
| 477 | { | 477 | { | |
| 67 hidden lines | ||||
| 545 | c11n_node_destroy(de); | 545 | c11n_node_destroy(de); | |
| 546 | return rc; | 546 | return rc; | |
| 547 | } | 547 | } | |
| 548 | #endif // C11N_IO_USE_SQL | 548 | #endif // C11N_IO_USE_SQL | |
| 549 | 549 | |||
| > | 550 | #include "MyList.h" | ||
| > | 551 | int test_list() | ||
| > | 552 | { | ||
| > | 553 | MARKER("Testing MyList...\n"); | ||
| > | 554 | #define NEW MyList_c11n->api->create(MyList_c11n) | ||
| > | 555 | MyList * head = NEW; | ||
| > | 556 | head->right = NEW; | ||
| > | 557 | head->right->left = head; | ||
| > | 558 | head->right->right = NEW; | ||
| > | 559 | head->right->right->left = head->right; | ||
| > | 560 | #undef NEW | ||
| > | 561 | |||
| > | 562 | head->x = 1; | ||
| > | 563 | head->y = -1; | ||
| > | 564 | head->right->x = 2; | ||
| > | 565 | head->right->y = -2; | ||
| > | 566 | head->right->right->x = 3; | ||
| > | 567 | head->right->right->y = -3; | ||
| > | 568 | |||
| > | 569 | |||
| > | 570 | char const * filename = "MyList.c11n"; | ||
| > | 571 | c11n_stream * str = c11n_stream_for_filename( filename, true ); | ||
| > | 572 | c11n_io_handler * h = c11n_io_handler_by_name( "expat" ); | ||
| > | 573 | c11n_save_serializable( str, MyList_c11n, head, h ); | ||
| > | 574 | str->api->destroy(str); | ||
| > | 575 | str = c11n_stream_for_filename( filename, false ); | ||
| > | 576 | c11n_node * n = c11n_load_node( str ); | ||
| > | 577 | str->api->destroy(str); | ||
| > | 578 | assert( n && "Load node failed :("); | ||
| > | 579 | MARKER("Loaded MyList node tree:\n"); | ||
| > | 580 | c11n_save_node( ThisApp.cout, n, 0 ); | ||
| > | 581 | |||
| > | 582 | MyList_c11n->api->destroy(MyList_c11n,head); | ||
| > | 583 | head = 0; | ||
| > | 584 | head = c11n_deserialize_new( n, MyList_c11n ); | ||
| > | 585 | c11n_node_destroy(n); | ||
| > | 586 | assert(head && "deserialize failed :("); | ||
| > | 587 | MARKER("Deserialized MyList list:\n"); | ||
| > | 588 | c11n_save_serializable( ThisApp.cout, MyList_c11n, head, h ); | ||
| > | 589 | MyList * clone = c11n_clone( MyList_c11n, head ); | ||
| > | 590 | MyList_c11n->api->destroy(MyList_c11n,head); | ||
| > | 591 | assert( clone && "Cloning failed :(" ); | ||
| > | 592 | MARKER("Cloned MyList:\n"); | ||
| > | 593 | c11n_save_serializable( ThisApp.cout, MyList_c11n, clone, h ); | ||
| > | 594 | MyList_c11n->api->destroy( MyList_c11n, clone ); | ||
| > | 595 | if( h ) h->api->destroy(h); | ||
| > | 596 | MARKER("Done testing MyList.\n"); | ||
| > | 597 | return 0; | ||
| > | 598 | } | ||
| 550 | 599 | |||
| 551 | int main( int argc, char ** argv ) | 600 | int main( int argc, char ** argv ) | |
| 552 | { | 601 | { | |
| 553 | //memblob_set_default_alloc_policy( my_memblob_alloc_policy ); | 602 | //memblob_set_default_alloc_policy( my_memblob_alloc_policy ); | |
| 554 | ThisApp.gc = whgc_create_context(&ThisApp); | 603 | ThisApp.gc = whgc_create_context(&ThisApp); | |
| 12 hidden lines | ||||
| 567 | DO(test_otherstuff()); | 616 | DO(test_otherstuff()); | |
| 568 | #if C11N_IO_USE_SQL | 617 | #if C11N_IO_USE_SQL | |
| 569 | DO(test_sql()); | 618 | DO(test_sql()); | |
| 570 | #endif | 619 | #endif | |
| 571 | DO(test_binary()); | 620 | DO(test_binary()); | |
| > | 621 | DO(test_list()); | ||
| 572 | #undef DO | 622 | #undef DO | |
| 573 | printf("Done - cleaning up. rc=%d=[%s].\n",rc, | 623 | printf("Done - cleaning up. rc=%d=[%s].\n",rc, | |
| 574 | (0==rc) | 624 | (0==rc) | |
| 575 | ? "You win :)" | 625 | ? "You win :)" | |
| 576 | : "You lose :("); | 626 | : "You lose :("); | |
| 577 | ThisApp.cout->api->destroy(ThisApp.cout); | 627 | ThisApp.cout->api->destroy(ThisApp.cout); | |
| 578 | whgc_destroy_context(ThisApp.gc); | 628 | whgc_destroy_context(ThisApp.gc); | |
| 579 | return rc; | 629 | return rc; | |
| 580 | } | 630 | } | |