PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/examples/usertypes.c

http://github.com/vrai/Fudge-C
C | 313 lines | 200 code | 42 blank | 71 comment | 20 complexity | 48e7e883de8aac3cdcb8fa6b1036052d MD5 | raw file
Possible License(s): Apache-2.0, AGPL-1.0
  1. /**
  2. * Copyright (C) 2010 - 2010, Vrai Stacey.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <fudge/fudge.h>
  17. #include <fudge/envelope.h>
  18. #include <fudge/codec.h>
  19. #include <fudge/string.h>
  20. #include <stdio.h>
  21. /* For more basic examples of Fudge-C use, see the "simple.c" and
  22. "prettyprint.c" files that should be in the same directory as this one.
  23. This file demostrates the registering and use of user types with the Fudge
  24. API.
  25. A custom type must have an encoding function (takes a FudgeField instance
  26. holding the type and encodes it on to an array of bytes), a decoding
  27. function (constructs a FudgeField instance of the type from an array of
  28. of bytes) and a type coercion function (converts a FudgeField instance of
  29. the type in to other types).
  30. In addition to these, the example uses a custom addField implementation.
  31. This is not required but is recommended as it allows the new type to added
  32. to messages in the same manner as built in types.
  33. */
  34. /* The user type - a simple address details record */
  35. typedef enum
  36. {
  37. Status_Unknown,
  38. Status_Active,
  39. Status_Past
  40. } AddressStatus;
  41. #define ADDRESSDETAILS_NAME_FIELD_LEN 64
  42. #define ADDRESSDETAILS_CITY_FIELD_LEN 32
  43. #define ADDRESSDETAILS_POST_FIELD_LEN 10
  44. typedef struct
  45. {
  46. AddressStatus status;
  47. fudge_i16 house_number;
  48. char street_name [ ADDRESSDETAILS_NAME_FIELD_LEN ];
  49. char city [ ADDRESSDETAILS_CITY_FIELD_LEN ];
  50. char postal_code [ ADDRESSDETAILS_POST_FIELD_LEN ];
  51. } AddressDetails;
  52. #define FUDGE_TYPE_ADDRESSDETAILS 32
  53. /* Utility field to add an AddressDetails structure to a FudgeMsg. Not
  54. required, but allows the user type to match the standard Fudge-C API. */
  55. FudgeStatus FudgeMsg_addFieldAddressDetails ( FudgeMsg message,
  56. const FudgeString name,
  57. const fudge_i16 * ordinal,
  58. const AddressDetails * details )
  59. {
  60. if ( ! ( message && details ) )
  61. return FUDGE_NULL_POINTER;
  62. return FudgeMsg_addFieldOpaque ( message,
  63. FUDGE_TYPE_ADDRESSDETAILS,
  64. name,
  65. ordinal,
  66. ( const fudge_byte * ) details,
  67. sizeof ( AddressDetails ) );
  68. }
  69. /* Encoding and decoding functions for AddressDetails. These are required
  70. if a type is to be used by Fudge. */
  71. FudgeStatus FudgeCodec_encodeFieldAddressDetails ( const FudgeField * field,
  72. fudge_byte * * data )
  73. {
  74. /* The FudgeMsg_addFieldAddressDetails would have simply copied the
  75. structure in to a byte array. */
  76. const AddressDetails * details = ( const AddressDetails * ) field->data.bytes;
  77. /* First, encode the length of the field */
  78. FudgeCodec_encodeFieldLength ( field->numbytes, data );
  79. /* Second, add the fields in turn. Use the encoding functions provided
  80. by the Fudge API to ensure endian correctness and that the target
  81. pointer is correctly advanced after each write. */
  82. FudgeCodec_encodeI32 ( ( fudge_i32 ) details->status, data );
  83. FudgeCodec_encodeI16 ( details->house_number, data );
  84. FudgeCodec_encodeByteArray ( ( const fudge_byte * ) details->street_name,
  85. ADDRESSDETAILS_NAME_FIELD_LEN,
  86. FUDGE_TRUE, data );
  87. FudgeCodec_encodeByteArray ( ( const fudge_byte * ) details->city,
  88. ADDRESSDETAILS_CITY_FIELD_LEN,
  89. FUDGE_TRUE, data );
  90. FudgeCodec_encodeByteArray ( ( const fudge_byte * ) details->postal_code,
  91. ADDRESSDETAILS_POST_FIELD_LEN,
  92. FUDGE_TRUE, data );
  93. return FUDGE_OK;
  94. }
  95. FudgeStatus FudgeCodec_decodeFieldAddressDetails ( const fudge_byte * bytes,
  96. const fudge_i32 width,
  97. FudgeFieldData * data )
  98. {
  99. AddressDetails * details;
  100. /* Make sure that field is of the expected size */
  101. if ( width != sizeof ( AddressDetails ) )
  102. return FUDGE_OUT_OF_BYTES;
  103. /* Allocate the target structure and point the data structure's byte
  104. pointer at it. This memory will be owned by the parent FudgeMsg. */
  105. if ( ! ( details = ( AddressDetails * ) malloc ( width ) ) )
  106. return FUDGE_OUT_OF_MEMORY;
  107. data->bytes = ( const fudge_byte * ) details;
  108. /* Decode and copy in the integer values, advancing the source bytes
  109. pointer after each one */
  110. details->status = ( AddressStatus ) FudgeCodec_decodeI32 ( bytes );
  111. bytes += sizeof ( fudge_i32 );
  112. details->house_number = FudgeCodec_decodeI16 ( bytes );
  113. bytes += sizeof ( fudge_i16 );
  114. /* Copy in the string components and advance the source bytes pointer */
  115. memcpy ( details->street_name, bytes, ADDRESSDETAILS_NAME_FIELD_LEN );
  116. bytes += ADDRESSDETAILS_NAME_FIELD_LEN;
  117. memcpy ( details->city, bytes, ADDRESSDETAILS_CITY_FIELD_LEN );
  118. bytes += ADDRESSDETAILS_CITY_FIELD_LEN;
  119. memcpy ( details->postal_code, bytes, ADDRESSDETAILS_POST_FIELD_LEN );
  120. bytes += ADDRESSDETAILS_POST_FIELD_LEN;
  121. return FUDGE_OK;
  122. }
  123. /* Type coercing function for AddressDetails. Required, but can simply refuse
  124. to coerce the value (returning either FUDGE_COERCION_NOT_REQUIRED if the
  125. types match or FUDGE_INVALID_TYPE_COERCION if not).
  126. For this example a simple string conversion is supported. */
  127. FudgeStatus FudgeType_coerceAddressDetails ( const FudgeField * source,
  128. const fudge_type_id type,
  129. FudgeFieldData * target,
  130. fudge_i32 * numbytes )
  131. {
  132. /* Used for string output */
  133. static const char * statusString [ 3 ] = { "Unknown", "Active", "Past" };
  134. size_t statusInt;
  135. switch ( type )
  136. {
  137. case FUDGE_TYPE_ADDRESSDETAILS:
  138. return FUDGE_COERCION_NOT_REQUIRED;
  139. case FUDGE_TYPE_STRING:
  140. {
  141. FudgeStatus status;
  142. char * tempstr;
  143. const AddressDetails * details = ( const AddressDetails * ) source->data.bytes;
  144. int stringlen;
  145. /* Calculate how much space will be needed for the string and set
  146. the return value */
  147. stringlen = ADDRESSDETAILS_NAME_FIELD_LEN +
  148. ADDRESSDETAILS_CITY_FIELD_LEN +
  149. ADDRESSDETAILS_POST_FIELD_LEN + 32;
  150. /* Allocate string space in temporary buffer */
  151. if ( ! ( tempstr = ( char * ) malloc ( stringlen ) ) )
  152. return FUDGE_OUT_OF_MEMORY;
  153. /* Encode string - yes snprintf is better, but it's not portable
  154. enough for the example code. */
  155. statusInt = ( size_t ) ( details->status >= 0 && details->status <= 3 ? details->status
  156. : Status_Unknown );
  157. sprintf ( tempstr,
  158. "[%s] %d %s, %s. %s.",
  159. statusString [ statusInt ],
  160. details->house_number,
  161. details->street_name,
  162. details->city,
  163. details->postal_code );
  164. /* Use the temporary string to create the return value FudgeString */
  165. status = FudgeString_createFromASCIIZ ( &( target->string ), tempstr );
  166. free ( tempstr );
  167. *numbytes = FudgeString_getSize ( target->string );
  168. return status;
  169. }
  170. default:
  171. return FUDGE_INVALID_TYPE_COERCION;
  172. }
  173. }
  174. void fatalFudgeError ( FudgeStatus status, const char * context );
  175. AddressDetails * constructAddressDetails ( AddressStatus status,
  176. fudge_i16 number,
  177. const char * street,
  178. const char * city,
  179. const char * postal );
  180. int main ( int argc, char * argv [ ] )
  181. {
  182. FudgeStatus status;
  183. FudgeMsg message;
  184. FudgeMsgEnvelope envelope;
  185. AddressDetails * details [ 2 ];
  186. fudge_i16 ordinal;
  187. fudge_byte * encoded;
  188. fudge_i32 encodedsize;
  189. /* Initialise the Fudge library */
  190. if ( ( status = Fudge_init ( ) ) )
  191. fatalFudgeError ( status, "Failed to initialise Fudge library" );
  192. /* Register the AddressDetails type */
  193. if ( ( status = FudgeRegistry_registerType ( FUDGE_TYPE_ADDRESSDETAILS,
  194. FUDGE_TYPE_PAYLOAD_BYTES,
  195. FudgeCodec_decodeFieldAddressDetails,
  196. FudgeCodec_encodeFieldAddressDetails,
  197. FudgeType_coerceAddressDetails ) ) )
  198. fatalFudgeError ( status, "Failed to register AddressDetails type" );
  199. /* Construct and encode two address details */
  200. details [ 0 ] = constructAddressDetails ( Status_Past, 123, "Fake St.", "Some City", "P05 T4L" );
  201. details [ 1 ] = constructAddressDetails ( Status_Active, 45, "Faux Road", "Some Town", "FUD 63C" );
  202. /* Create a message and add the two details */
  203. if ( ( status = FudgeMsg_create ( &message ) ) )
  204. fatalFudgeError ( status, "Failed to create Fudge message" );
  205. for ( ordinal = 0; ordinal < 2; ++ordinal )
  206. FudgeMsg_addFieldAddressDetails ( message, 0, &ordinal, details [ ordinal ] );
  207. /* Encode the message */
  208. if ( ( status = FudgeMsgEnvelope_create ( &envelope, 0, 0, 0, message ) ) )
  209. fatalFudgeError ( status, "Failed to create Fudge messag envelope" );
  210. if ( ( status = FudgeCodec_encodeMsg ( envelope, &encoded, &encodedsize ) ) )
  211. fatalFudgeError ( status, "Failed to encode Fudge message" );
  212. /* Clean up source details and messge */
  213. free ( details [ 0 ] );
  214. free ( details [ 1 ] );
  215. FudgeMsgEnvelope_release ( envelope );
  216. FudgeMsg_release ( message );
  217. /* Decode the message and release the encoded bytes array */
  218. if ( ( status = FudgeCodec_decodeMsg ( &envelope, encoded, encodedsize ) ) )
  219. fatalFudgeError ( status, "Failed to decode Fudge message" );
  220. free ( encoded );
  221. /* Retrieve, convert and display the fields */
  222. for ( ordinal = 0; ordinal < 2; ++ordinal )
  223. {
  224. FudgeField field;
  225. FudgeFieldData data;
  226. FudgeTypePayload payload;
  227. fudge_i32 datasize;
  228. char * ascii;
  229. if ( ( status = FudgeMsg_getFieldByOrdinal ( &field, FudgeMsgEnvelope_getMessage ( envelope ), ordinal ) ) )
  230. fatalFudgeError ( status, "Failed to find field" );
  231. /* Convert the field in to a string */
  232. if ( ( status = FudgeMsg_getFieldAs ( &field, FUDGE_TYPE_STRING, &data, &payload, &datasize ) ) )
  233. fatalFudgeError ( status, "Failed to convert field to string" );
  234. /* This is a bit paranoid, but it's checking that the string
  235. conversion actually resulted in string payload */
  236. if ( payload != FUDGE_TYPE_PAYLOAD_STRING )
  237. {
  238. fprintf ( stderr, "FATAL ERROR: Retrieving field %d as a string returned a non-string!\n", ordinal );
  239. exit ( 1 );
  240. }
  241. FudgeString_convertToASCIIZ ( &ascii, data.string );
  242. printf ( "Field %d: %s\n", ordinal, ascii );
  243. free ( ascii );
  244. FudgeString_release ( data.string );
  245. }
  246. /* Clean up */
  247. FudgeMsgEnvelope_release ( envelope );
  248. return 0;
  249. }
  250. void fatalFudgeError ( FudgeStatus status, const char * context )
  251. {
  252. fprintf ( stderr, "FATAL ERROR: %s : %s\n", context, FudgeStatus_strerror ( status ) );
  253. exit ( 1 );
  254. }
  255. AddressDetails * constructAddressDetails ( AddressStatus status,
  256. fudge_i16 number,
  257. const char * street,
  258. const char * city,
  259. const char * postal )
  260. {
  261. AddressDetails * details = ( AddressDetails * ) malloc ( sizeof ( AddressDetails ) );
  262. details->status = status;
  263. details->house_number = number;
  264. strncpy ( details->street_name, street, ADDRESSDETAILS_NAME_FIELD_LEN );
  265. strncpy ( details->city, city, ADDRESSDETAILS_CITY_FIELD_LEN );
  266. strncpy ( details->postal_code, postal, ADDRESSDETAILS_POST_FIELD_LEN );
  267. return details;
  268. }