aboutsummaryrefslogtreecommitdiffstats
path: root/src/csn1.h
blob: 96f75582d6a1a68ae1d8e8d9d9ad866d20e06c30 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
/* csn1.h
 * Declarations and types for CSN1 dissection in wireshark.
 * By Vincent Helfre, based on original code by Jari Sassi
 * with the gracious authorization of STE
 * Copyright (c) 2011 ST-Ericsson
 *
 * $Id: packet-csn1.h 36306 2011-03-24 09:20:14Z etxrab $
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include <bitvector.h>
#include <iostream>
#include <cstdlib>
#ifndef _PACKET_CSN1_H_
#define _PACKET_CSN1_H_


#define MIN(a,b) (((a)<(b))?(a):(b))
//#define max(a,b) (((a)>(b))?(a):(b))

/* Error codes */
#define  CSN_OK                               0
#define  CSN_ERROR_GENERAL                   -1
#define  CSN_ERROR_DATA_NOT_VALID            -2
#define  CSN_ERROR_IN_SCRIPT                 -3
#define  CSN_ERROR_INVALID_UNION_INDEX       -4
#define  CSN_ERROR_NEED_MORE_BITS_TO_UNPACK  -5
#define  CSN_ERROR_ILLEGAL_BIT_VALUE         -6
#define  CSN_ERROR_INTERNAL                  -7
#define  CSN_ERROR_STREAM_NOT_SUPPORTED      -8
#define  CSN_ERROR_MESSAGE_TOO_LONG          -9
#define  CSN_ERROR_                         -10

#define FALSE (0)
#define TRUE  (1)
typedef signed int gint32;
typedef signed short gint16;
typedef int gint;
typedef gint gboolean;
typedef unsigned char guint8;
typedef unsigned short guint16;
typedef unsigned int guint32;
typedef unsigned long guint64;
/* CallBack return status */
typedef gint16 CSN_CallBackStatus_t;

#define  CSNCBS_OK                      0
#define  CSNCBS_NOT_OK                -10
#define  CSNCBS_NOT_TO_US             -11
#define  CSNCBS_NOT_COMPLETE          -12

#define CSNCBS_REVISION_LIMIT_STOP   -20 /* Stop packing/unpacking - revision limit */
#define CSNCBS_NOT_SUPPORTED_IE      -21 /* Handling of the unpacked IE is not supported by MS-software */



#ifndef ElementsOf
#define ElementsOf(array) (sizeof(array) / sizeof(array[0]))
#endif

/* Context holding CSN1 parameters */
typedef struct
{
  gint  remaining_bits_len;  /* IN to an csn stream operation */
  gint  bit_offset;          /* IN/OUT to an csn stream operation */
  gint  direction;           /* 0 - decode; 1 - encode */
} csnStream_t;

typedef gint16 (*StreamSerializeFcn_t)(csnStream_t* ar, bitvec *vector, unsigned& readIndex, void* data);
typedef enum
{
  CSN_END = 0,
  CSN_BIT,
  CSN_UINT,
  CSN_TYPE,
  CSN_CHOICE,
  CSN_UNION,
  CSN_UNION_LH,
  CSN_UINT_ARRAY,
  CSN_TYPE_ARRAY,
  CSN_BITMAP,                /* Bitmap with constant: <bitmap: bit(64)> */
  CSN_VARIABLE_BITMAP,       /* <N: bit (5)> <bitmap: bit(N + offset)> */
  CSN_VARIABLE_BITMAP_1,     /* <bitmap: bit**> i.e. to the end of message (R99) */
  CSN_LEFT_ALIGNED_VAR_BMP,  /* As variable bitmap but the result is left aligned (R99) */
  CSN_LEFT_ALIGNED_VAR_BMP_1,/* As above only size is to the end of message (R99) */
  CSN_PADDING_BITS,          /* Padding bits fill to the end of the buffer */
  CSN_VARIABLE_ARRAY,        /* Array with length specified in parameter: <N: bit(4)> <list: octet(N + offset)> */
  CSN_VARIABLE_TARRAY,       /* Type Array with length specified in parameter: <N: bit(x)> <Type>*N */
  CSN_VARIABLE_TARRAY_OFFSET,/* As above but with offset. The offset is stored as third parameter of CSN_DESCR (descr.value) */
  CSN_RECURSIVE_ARRAY,       /* Recursive way to specify an array of uint:   <list> ::= {1 <number: bit(4) <list>|0}; */
  CSN_RECURSIVE_TARRAY,      /* Recursive way to specify an array of type:   <list> ::= {1 <type>} ** 0 ; */
  CSN_RECURSIVE_TARRAY_1,    /* same as above but first element always exist:<list> ::= <type> {1 <type>} ** 0 ; */
  CSN_RECURSIVE_TARRAY_2,    /* same as above but with reversed separators :<lists> ::= <type> { 0 <type> } ** 1 ; */
  CSN_EXIST,
  CSN_EXIST_LH,
  CSN_NEXT_EXIST,
  CSN_NEXT_EXIST_LH,
  CSN_NULL,
  CSN_FIXED,
  CSN_CALLBACK,
  CSN_UINT_OFFSET,        /* unpack will add offset, inverse pack will subtract offset */
  CSN_UINT_LH,            /* Low High extraction of int */
  CSN_SERIALIZE,
  CSN_TRAP_ERROR
} csn_type_t;

/******************************************************************************************
 * CSN_DESCR structure:
 *
 * type:
 *       This is the CSN type. All existing types are specified in the section above.
 *
 * i:
 *       Depending on the contents of the type parameter,  the parameter "i" may have following meaning:
 *       - specifies the number of bits for the CSN_UINT or CSN_UINT_OR_NULL types
 *       - the offset for an array size by which the size is incremented
 *          for the CSN_VAR_ARRAY type
 *       - the length of each element of an array for the CSN_REC_ARRAY type
 *       - the number of the elements in an array for the CSN_TYPE_ARRAY type
 *       - the offset to the variable keeping the number of elements of an array for in the CSN_VAR_TARRAY type
 *       - the number of different data types in a union for the CSN_UNION, CSN_UNION_LH, and  for the CSN_CHOICE types
 *       - the length in bits of the fixed number defined for  the CSN_FIXED type
 *       - the number of lines to skip in the CSN_DESCR type specified for the  CSN_NEXT_EXIST, CSN_NEXT_EXIST_LH,
 *          CSN_NEXT_EXIST_OR_NULL, and CSN_NEXT_EXIST_OR_NULL_LH types
 *       - the number of bits in a bitmap for the CSN_BITMAP type
 *       - the value by which the number of bits in a bitmap has to be incremented or decremented for the
 *          CSN_VAR_BITMAP, CSN_LEFT_VAR_BMP, and CSN_LEFT_BMP_1 types
 *       - the offset to param1 for the CSN_CALLBACK type
 *       - ERRORCODE  used by the CSN_ERROR type
 *       - the bit-length of the LENGTH field in a CSN_SERIALISE type
 *
 * descr
 *       This parameter has different meaning depending on the value of the type parameter:
 *       - the offset for  the CSN_UINT_OFFSET type
 *       - the number of the elements in an array of the CSN_UINT_ARRAY type
 *       - the offset to the parameter where the size of the array has to be stored for the CSN_REC_ARRAY type
 *       - the address of the internal structure, describing the member type (by means of the CSN_DESCR type) in the
 *          CSN_TYPE_ARRAY, CSN_VAR_TARRAY, and CSN_TYPE types
 *       - the address of the variable of type CSN_ChoiceElement_t describing all elements in the CSN_CHOICE type union
 *       - the offset to the variable where the number of bits has to be or is stored for the CSN_VAR_BITMAP,
 *          CSN_LEFT_VAR_BMP, and CSN_LEFT_BMP_1 types
 *       - the function number (case number) for the CSN_CALLBACK and CSN_CALLBACK_NO_ARGS types
 *       - the free text used by the CSN_TRAP_ERROR
 *
 * offset
 *         This is an offset to the _MEMBER parameter counting from the beginning of struct
 *         where the unpacked or packed value shall be stored or fetched. The meaning of the _MEMBER parameter
 *         varies depending on the type which is specified  and so is the meaning of the offset parameter.
 *         Some types (and corresponding macros) do not have the _MEMBER parameter and then the offset parameter
 *         is not used or is different from the offset to the _MEMBER.
 *         - the fixed value for the CSN_FIXED type
 *         - an offset to the variable UnionType for CSN_UNION and CSN_UNION_LH types
 *         - an offset to the variable Exist for CSN_NEXT_EXIST and CSN_NEXT_EXIST_LH types
 *         - an offset to param2 in the CSN_CALLBACK  type
 *
 * may_be_null
 *         TRUE: if dissection may be attempted at an offset beyond the length of existing data bits
 *         FALSE: othewise
 *
 * sz
 *    - is the name of the parameter within the descr where their unpacked or packed value shall be stored or fetched.
 *      This paramater is pointed out by the offset parameter in the same CSN_DESCR variable as the sz.
 *    - the free text used by the CSN_TRAP_ERROR (the same as parameter "i")
 *
 * serialize
 *    - stores the size of _MEMBER type in case of the M_TYPE_ARRAY and M_VAR_TARRAY,
 *    - the address of the function which is provided by the M_SERIALIZE type.
 ******************************************************************************************/


typedef struct
{
  gint16      type;
  gint16      i;
  union
  {
    void*     ptr;
    guint32   value;
  } descr;
  unsigned      offset;
  gboolean    may_be_null;
  const char* sz;
  union
  {
    StreamSerializeFcn_t  fcn;
    guint32               value;
    int*                  hf_ptr;
  } serialize;
} CSN_DESCR;

typedef struct
{
  guint8     bits;
  guint8     value;
  CSN_DESCR descr;
} CSN_ChoiceElement_t;

void csnStreamInit(csnStream_t* ar,gint BitOffset,gint BitCount);

/******************************************************************************
* FUNCTION:  csnStreamDecoder
* DESCRIPTION:
*            UnPacks data from bit stream. According to CSN description.
* ARGS:
*   ar        stream will hold the parameters to the pack function
*            ar->remaining_bits_len    [IN] Number of bits to unpack [OUT] number of bits left to unpack.
*            ar->bit_offset            [IN/OUT] is the current bit where to proceed with the next bit to unpack.

*   pDescr    CSN description.
*   tvb       buffer containing the bit stream to unpack.
*   data      unpacked data.
*   ett_csn1  tree
*
* RETURNS:  int  Number of bits left to be unpacked. Negative Error code if failed to unpack all bits
******************************************************************************/

gint16 csnStreamDecoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector, unsigned& readIndex, void* data);

gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector, unsigned& readIndex, void* data);

/* CSN struct macro's */
#define  CSN_DESCR_BEGIN(_STRUCT)\
        CSN_DESCR CSNDESCR_##_STRUCT[] = {

#define  CSN_DESCR_END(_STRUCT)\
        {CSN_END, 0, {0}, 0, FALSE, "", {(StreamSerializeFcn_t)0}} };

/******************************************************************************
 * CSN_ERROR(Par1, Par2, Par3)
 * May be called at any time when an abort of packing or unpacking of a message
 * is desired
 *      Par1: C structure name
 *      Par2: free text which will appear in the error handler
 *      Par3: Error code
 *****************************************************************************/
#define CSN_ERROR(_STRUCT, _Text, _ERRCODE)\
        {CSN_TRAP_ERROR, _ERRCODE, {(void*)_Text}, 0, FALSE, _Text, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_BIT(Par1, Par2)
 * Defines one bit element in the CSN1 syntax.
 *      Par1: C structure name
 *      Par2: C structure element name
 *****************************************************************************/
#define M_BIT(_STRUCT, _MEMBER)\
        {CSN_BIT, 0, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_BIT_OR_NULL(Par1, Par2)
 * Similar to the M_BIT except that not only bit 0 or 1 but also the
 * end of the message may be encountered when looking for the next element in
 * the message.
 * Covers the case {null | 0 | 1}
 *****************************************************************************/
 #define M_BIT_OR_NULL(_STRUCT, _MEMBER)\
         {CSN_BIT, 0, {0}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_NEXT_EXIST(Par1, Par2, Par3)
 * Indicates whether the next element or a group of elements defined in the 
 * structure is present or not.
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: number of lines to skip in the CSN_DESCR type specified if the
 *            element(s) does not exist
 *****************************************************************************/
#define M_NEXT_EXIST(_STRUCT, _MEMBER, _NoOfExisting)\
        {CSN_NEXT_EXIST, _NoOfExisting, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_NEXT_EXIST_LH(Par1, Par2, Par3)
 * similar to the M_NEXT_EXIST except that instead of bit 0/1 which is fetched
 * from the message in order to find out whether the next element/elements are
 * present in the message, the logical operation XOR with the background 
 * pattern 0x2B is performed on the read bit before the decision is made.
 *****************************************************************************/
#define M_NEXT_EXIST_LH(_STRUCT, _MEMBER, _NoOfExisting)\
        {CSN_NEXT_EXIST_LH, _NoOfExisting, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_NEXT_EXIST_OR_NULL(Par1, Par2, Par3)
 * Similar to the M_NEXT_EXIST except that not only bit 0 or 1 but also the end
 * of the message may be encountered when looking for the next element in the 
 * message.
 * Covers the case {null | 0 | 1 < IE >} 
 *****************************************************************************/
#define M_NEXT_EXIST_OR_NULL(_STRUCT, _MEMBER, _NoOfExisting)\
        {CSN_NEXT_EXIST, _NoOfExisting, {(void*)1}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_NEXT_EXIST_OR_NULL_LH(Par1, Par2, Par3)
 * Similar to the M_NEXT_EXIST_LH except that not only bit 0 or 1 but also the
 * end of the message may be encountered when looking for the next element in
 * the message.
 * Covers the case {null | L | H < IE >} 
 *****************************************************************************/
#define M_NEXT_EXIST_OR_NULL_LH(_STRUCT, _MEMBER, _NoOfExisting)\
        {CSN_NEXT_EXIST_LH, _NoOfExisting, {(void*)1}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_UINT(Par1, Par2, Par3)
 * Defines an integer number.
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: number of bits used to code the element (between 1 and 32)
 *****************************************************************************/
#define M_UINT(_STRUCT, _MEMBER, _BITS)\
        {CSN_UINT, _BITS, {(void*)1}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

 /******************************************************************************
 * M_UINT_OR_NULL(Par1, Par2, Par3)
 * Similar to the M_UINT except that not only the request set of bits but also the
 * end of the message may be encountered when looking for the next element in
 * the message.
 * Covers the case {null | 0 | 1 < IE >}
 *****************************************************************************/
 #define M_UINT_OR_NULL(_STRUCT, _MEMBER, _BITS)\
         {CSN_UINT, _BITS, {0}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_UINT(Par1, Par2, Par3)
 * This macro has the same functionality as M_UINT except that  in addition the
 * logical "exclusive or" operation with the background value "0x2B" is 
 * performed before the final value of the integer number is delivered from the 
 * received CSN.1 message
 *****************************************************************************/
#define M_UINT_LH(_STRUCT, _MEMBER, _BITS)\
        {CSN_UINT_LH, _BITS, {(void*)1}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_UINT_OFFSET(Par1, Par2, Par3, Par4)
 * Defines an integer number.
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: number of bits used to code the element (between 1 and 32)
 *      Par4: value added to the returned integer (offset)
 *****************************************************************************/
#define M_UINT_OFFSET(_STRUCT, _MEMBER, _BITS, _OFFSET)\
        {CSN_UINT_OFFSET, _BITS, {(void*)_OFFSET}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_UINT_ARRAY(Par1, Par2, Par3, Par4)
 * Defines an array of integer numbers. The size of the array is fixed.
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: number of bits used to code the each integer element (between 1 and 32)
 *      Par4: number of elements in the array (fixed integer value)
 *****************************************************************************/
#define M_UINT_ARRAY(_STRUCT, _MEMBER, _BITS, _ElementCount)\
        {CSN_UINT_ARRAY, _BITS, {(void*)_ElementCount}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_VAR_UINT_ARRAY(Par1, Par2, Par3, Par4)
 * Defines an array of integer numbers. The size of the array is variable.
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: number of bits used to code the each integer element (between 1 and 32)
 *      Par4: number of elements in the array supplied by reference to the
 *            structure member holding the length value
 *****************************************************************************/
#define M_VAR_UINT_ARRAY(_STRUCT, _MEMBER, _BITS, _ElementCountField)\
        {CSN_UINT_ARRAY, _BITS, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)1}}

/******************************************************************************
 * M_VAR_ARRAY(Par1, Par2, Par3, Par4)
 * Defines an array of 8 bit large integer numbers. The size of the array is variable.
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: name of the structure member holding the size of the array
 *      Par4: offset that is added to the Par3 to get the actual size of the array
 *****************************************************************************/
#define M_VAR_ARRAY(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\
        {CSN_VARIABLE_ARRAY, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_VAR_TARRAY(Par1, Par2, Par3, Par4)
 * Similar to M_TYPE_ARRAY except that the size of the array is variable.
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: the type of each element of the array
 *      Par4: name of the structure member holding the size of the array
 *****************************************************************************/
#define M_VAR_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\
        {CSN_VARIABLE_TARRAY, offsetof(_STRUCT, _ElementCountField), {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}

/******************************************************************************
 * M_VAR_TARRAY_OFFSET(Par1, Par2, Par3, Par4)
 * Same as M_VAR_TARRAY with offset
 *****************************************************************************/
#define M_VAR_TARRAY_OFFSET(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\
        {CSN_VARIABLE_TARRAY_OFFSET, offsetof(_STRUCT, _ElementCountField), {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}

/******************************************************************************
 * M_REC_ARRAY(Par1, Par2, Par3, Par4)
 * similar to the M_VAR_ARRAY. The difference is that the size of the array is 
 * not known in advance and it has to be calculated during unpacking. Its value
 * is stored in a variable which belongs to the same structure as the array. 
 * A zero element terminates the array. The CSN.1 syntax describes it 
 * recursively as:
 * <array> ::={1 <element> <array>| 0} 
 *
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: name of the structure member where the calculated the size of the 
 *            array will be stored
 *      Par4: length of each element in bits
 *****************************************************************************/
#define M_REC_ARRAY(_STRUCT, _MEMBER, _ElementCountField, _BITS)\
        {CSN_RECURSIVE_ARRAY, _BITS, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_VAR_TYPE_ARRAY(Par1, Par2, Par3, Par4)
 * Defines an array of structures. The size of the array is variable.
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: name of the structure
 *      Par4: number of elements in the array (fixed integer value)
 *****************************************************************************/
#define M_TYPE_ARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCount)\
        {CSN_TYPE_ARRAY, _ElementCount, {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}

/******************************************************************************
 * M_REC_TARRAY(Par1, Par2, Par3, Par4)
 * Defines an recursive array of structures. The size of the array is variable.
 * <list> ::= {1 <type>} ** 0 ;
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: name of the structure
 *      Par4: will hold the number of element in the array after unpacking
 *****************************************************************************/
#define M_REC_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\
        {CSN_RECURSIVE_TARRAY, offsetof(_STRUCT, _ElementCountField), {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}

/******************************************************************************
 * M_REC_TARRAY1(Par1, Par2, Par3, Par4)
 * Same as M_REC_TARRAY but first element always exist:
 * <list> ::= <type> {1 <type>} ** 0 ;
 *****************************************************************************/
#define M_REC_TARRAY_1(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\
        {CSN_RECURSIVE_TARRAY_1, offsetof(_STRUCT, _ElementCountField), {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}

/******************************************************************************
 * M_REC_TARRAY2(Par1, Par2, Par3, Par4)
 * Same as M_REC_TARRAY but with reversed separators :
 * <lists> ::= <type> { 0 <type> } ** 1 ;
 *****************************************************************************/
#define M_REC_TARRAY_2(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\
        {CSN_RECURSIVE_TARRAY_2, offsetof(_STRUCT, _ElementCountField), {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}

/******************************************************************************
 * M_TYPE(Par1, Par2, Par3)
 * Defines a reference to a structure which is described elsewhere
 * <list> ::= {1 <type>} ** 0 ;
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: type of member
 *****************************************************************************/
#define M_TYPE(_STRUCT, _MEMBER, _MEMBER_TYPE)\
        {CSN_TYPE, 0, {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_UNION(Par1, Par2)
 * Informs the CSN.1 library that a union follows and how many possible choices
 * there are in the union. The actual value of the choice, which points out the
 * chosen element of the union is stored in the uint8 variable and is usually 
 * called UnionType. The elements of the union have to be listed directly after 
 * the M_UNION statement.
 *      Par1: C structure name
 *      Par2: number of possible choice in the union
 *****************************************************************************/
#define M_UNION(_STRUCT, _COUNT)\
        {CSN_UNION, _COUNT, {0}, offsetof(_STRUCT, UnionType), FALSE, "UnionType", {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_UNION_LH(Par1, Par2)
 * Same as M_UNION but masked with background value 0x2B
 *****************************************************************************/
#define M_UNION_LH(_STRUCT, _COUNT)\
        {CSN_UNION_LH, _COUNT, {0}, offsetof(_STRUCT, UnionType), FALSE, "UnionType", {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_CHOICE(Par1, Par2, Par3, Par4)
 * Similar to the M_UNION. In the M_UNION the selected element of all possible 
 * choices in the union is referred as a sequential numbers,  i.e., the first 
 * choice is addressed as choice 0 the second as choice 1, the third as choice 
 * 2 and so on, both in the encoded message and in the variable UnionType which
 * is the part of the message.  In the CSN_CHOICE case, this rule does not 
 * apply. There is free but predefined mapping of the element of the union and 
 * the value which addresses this element.
 * The value of the address is called a selector.
 * After unpacking, this value is then converted to the sequential number of the
 * element in the union and stored in the UnionType variable.
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: address of an array of type CSN_ChoiceElement_t where all possible
 *            values of the selector are provided, together with the selector 
 *            length expressed in bits and the address of  the CSN_DESCR type 
 *            where the element is defined. For every element in the union 
 *            there is one line in the Choice variable. These lines have to 
 *            appear in the _CHOICE in the same order as the elements in the 
 *            union. The element of the union selected in the message through 
 *            the _CHOICE parameter is after unpacking translated to the 
 *            corresponding sequential number of this element and stored in 
 *            the variable pointed out by the _MEMBER
 *      Par4: number of possible choices in the union
 *****************************************************************************/
#define M_CHOICE(_STRUCT, _MEMBER, _CHOICE, _ElementCount)\
        {CSN_CHOICE, _ElementCount, {(void*)_CHOICE}, offsetof(_STRUCT, _MEMBER), FALSE, #_CHOICE, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_FIXED(Par1, Par2, Par3)
 * Defines a fixed value of type integer which should be fetched from or stored 
 * in  the message
 *      Par1: C structure name
 *      Par2: gives the length of the fixed number in bits.
 *      Par3: the value of the number. If the expected value is not present in 
*             the message the unpacking procedure is aborted
 *****************************************************************************/
#define M_FIXED(_STRUCT, _BITS, _BITVALUE)\
        {CSN_FIXED, _BITS, {0}, _BITVALUE, FALSE, #_BITVALUE, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_SERIALIZE(Par1, Par2, Par3)
 * Allows using a complete free format of data being encoded or decoded. 
 * When the M_SERIALIZE is encounted during encoding or decoding of a message
 * the CSNstream program passes the control over to the specified function 
 * together with all necessary parameters about the current position within 
 * the message being unpacked or packed.  When transferring of "serialized" 
 * data to or from the message is finished by the function the CSNstream gets 
 * back control over the data stream and continues to work with the message.
 *****************************************************************************/
#define M_SERIALIZE(_STRUCT, _MEMBER, _LENGTH_LEN, _SERIALIZEFCN)\
        {CSN_SERIALIZE, _LENGTH_LEN, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {_SERIALIZEFCN}}

#define M_CALLBACK(_STRUCT, _CSNCALLBACKFCN, _PARAM1, _PARAM2)\
        {CSN_CALLBACK, offsetof(_STRUCT, _PARAM1), {_CSNCALLBACKFCN}, offsetof(_STRUCT, _PARAM2),  FALSE, "CallBack_"#_CSNCALLBACKFCN, {(StreamSerializeFcn_t)0}}

/******************************************************************************
 * M_BITMAP(Par1, Par2, Par3)
 * Defines a type which consists of a bitmap. The size of the bitmap in bits 
 * is fixed and provided by the parameter Par3
 *      Par1: C structure name
 *      Par2: C structure element name
 *      Par3: length of the bitmap expressed in bits
 *****************************************************************************/
#define M_BITMAP(_STRUCT, _MEMBER, _BITS)\
        {CSN_BITMAP, _BITS, {0}, offsetof(_STRUCT, _MEMBER),  FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/* variable length, right aligned bitmap i.e. _ElementCountField = 11 => 00000111 11111111 */
#define M_VAR_BITMAP(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\
        {CSN_VARIABLE_BITMAP, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/* variable length, right aligned bitmap filling the rest of message
 * - when unpacking the _ElementCountField will be set in runtime
 * - when packing _ElementCountField contains the size of bitmap
 */
#define M_VAR_BITMAP_1(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\
        {CSN_VARIABLE_BITMAP_1, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/* variable length, left aligned bitmap i.e. _ElementCountField = 11 => 11111111 11100000 */
#define M_LEFT_VAR_BMP(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\
        {CSN_LEFT_ALIGNED_VAR_BMP, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/* variable length, left aligned bitmap filling the rest of message
 *- when unpacking the _ElementCountField will be set in runtime
 * - when packing _ElementCountField contains the size of bitmap
 */
#define M_LEFT_VAR_BMP_1(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\
        {CSN_LEFT_ALIGNED_VAR_BMP_1, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

/* todo: dissect padding bits looking for unexpected extensions */
#define M_PADDING_BITS(_STRUCT)\
        {CSN_PADDING_BITS, 0, {0}, 0, TRUE, "Padding", {(StreamSerializeFcn_t)0}}

#define M_NULL(_STRUCT, _MEMBER)\
        {CSN_NULL, 0, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}

#define M_THIS_EXIST(_STRUCT)\
        {CSN_EXIST, 0, {0}, offsetof(_STRUCT, Exist), FALSE, "Exist", {(StreamSerializeFcn_t)0}}

#define M_THIS_EXIST_LH(_STRUCT)\
        {CSN_EXIST_LH, 0, {0}, offsetof(_STRUCT, Exist), FALSE, "Exist", {(StreamSerializeFcn_t)0}}

/* return value 0 if ok else discontionue the unpacking */
typedef gint16 (*CsnCallBackFcn_t)(void* pv ,...);

#define CSNDESCR(_FuncType) CSNDESCR_##_FuncType

#endif /*_PACKET_CSN1_H_*/