summaryrefslogtreecommitdiff
path: root/TAO/IIOP/lib/runtime/cdr.hh
blob: 61120e0d247e8fe968ed3020eb431ea56c788a82 (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
// @(#)cdr.hh	1.2 95/11/04
// Copyright 1994-1995 by Sun Microsystems Inc.
// All Rights Reserved
//
// CDR:		 Common Data Representation (CDR) marshaling streams.
//
// This implementation assumes that the native numeric representation
// is two's complement for integers, IEEE single/double for floats.  Also
// that characters are in ISO Latin/1.
//
// Note that CDR itself makes no such assumptions, but this implementation
// makes such assumptions for reasons of efficiency.  Careful enhancements
// could preserve that efficiency where the assumptions are true, yet
// still allow the code to work when they aren't true.
//
// The implementation expects that buffers are aligned according to the
// strongest CDR alignment restriction.
//
// NOTE: this does everything "CDR 1.1" does ... that is, it supports
// the five extended OMG-IDL data types in UNO Appendix A, which provide
// richer arithmetic types (64 bit integers, "quad precision" FP) and
// UNICODE-based characters and strings.  Those types are not standard
// parts of OMG-IDL at this time.
//
// THREADING NOTE:  CDR data structures must be protected against
// concurrent access by their owning thread.
//


#ifndef	_CDR_HH
#define	_CDR_HH

#include	<assert.h>

#include	<corba/orb.hh>

#include	<runtime/align.hh>


//
// Identify byte order ... this is basically dependent on processor, but some
// processors support different byte orders (e.g. MIPS, UltraSPARC, PowerPC)
// as required for different software environments.
//
// We currently get this information through the "configure" script, which
// must (!!) be run before source code can be correctly compiled; too bad
// we have no way to ensure that the machine on which "configure" ran is
// the same as the one on which "make" will be run.
//

#undef	LITTLE_ENDIAN
#undef	BIG_ENDIAN
#undef	MY_BYTE_SEX

//
// PC compilers normally don't assume they'll be given code that runs
// on other architectures; cope with that limitation once here, so that
// only truly compiler-specific code needs to use their predefines.
//
// NOTE:  should really be using "__i386" to be strictly ANSI compliant.
//
#if defined (__BORLANDC__) || defined (_M_IX86)
#	if	!defined (i386)
#		define	i386
#		undef	WORDS_BIGENDIAN
#	endif
#endif

//
// Yes, we assume no bizarre mixed-endian "nuxi" machine, just as we
// assume only IEEE arithmetic.
//
#if defined (WORDS_BIGENDIAN)
#	define	BIG_ENDIAN
#	define	MY_BYTE_SEX	0
#else
#	define	LITTLE_ENDIAN
#	define	MY_BYTE_SEX	1
#endif

//
// The core marshaling primitive:  a memory buffer, into which all the basic
// OMG-IDL datatypes can be placed ... or from which they can be retreived.
//
// A particularly useful static member function for this buffer is an
// interpretive encoding routine, usable as a typecode interpreter callback.
// Ditto for decoding.  These are used to support all OMG-IDL datatypes,
// even those not supported directly by put/get primitives.
//
// Struct members are intentionally exposed; the functionality of this
// class, and hence the appropriate abstactions for them, hasn't quite
// settled down enough to settle on fast abstractions that let data be
// hidden without pointlessly sacrificing speed.
//
struct _EXPCLASS CDR
{
    //
    // Define these constants as enums to ensure they get inlined
    // and to avoid pointless static memory allocations.
    //
    enum {
	//
	// Constants defined by the CDR protocol.  Note that some of these
	// get reused as part of the standard binary format:  unsigned is the
	// same size as its signed cousin, float is CDR_LONG_SIZE, and double
	// is CDR_LONGLONG_SIZE.
	//
	SHORT_SIZE = 2,
	LONG_SIZE = 4,
	LONGLONG_SIZE = 8,
	LONGDOUBLE_SIZE = 16,

	//
	// maximal CDR 1.1 alignment:   "quad precision" FP
	// (i.e. "long double", size as above)
	//
	MAX_ALIGNMENT = 16,

	//
	// Default buffer size for request/response messages.  These are
	// normally stack-allocated, and tuning may cause you to want to
	// change this value.  The best value depends on your particular
	// application mix; you can also change how buffers grow().  Most
	// remote invocations (statistically) are "small", and the default
	// used here is perhaps larger than most such messages.
	// 
	// If this size is "too small" you need to heap-allocate buffers too
	// often.  "Too large" is mostly a waste of stackspace, but stack
	// frames as large as the system page size (often 4Kb) can easily
	// overrun the "redzone" at the bottom of most VM-based stacks.
	//
	DEFAULT_BUFSIZE = 1430		// Ethernet MTU, less headers
    };

    //
    // ENCODING SUPPORT ... adjust pointers as needed, then store in the
    // native byte order.
    //
    // There exist only routines to put byte, halfword (2 bytes), word
    // (4 bytes), doubleword (8 bytes) and quadword (16 byte) entities,
    // plus the interpretive encoder.
    //

    CORBA_Boolean		put_byte (char c);
    CORBA_Boolean		put_short (CORBA_Short s);
    CORBA_Boolean		put_long (CORBA_Long l);
    CORBA_Boolean		put_longlong (const CORBA_LongLong &ll);

    inline CORBA_Boolean	put_char (CORBA_Char c)
				{ return put_byte ((char) c); }
    inline CORBA_Boolean	put_wchar (wchar_t wc)
				{
				    //
				    // "wchar_t" isn't always 2 bytes, such
				    // systems might need further conversion
				    // (e.g. hosts with multibyte characters
				    // native, rather than UNICODE)
				    //
				    return put_short ((short)wc);
				}
    
    inline CORBA_Boolean	put_boolean (CORBA_Boolean b)
				{ return put_byte ((char)
					    (b != CORBA_B_FALSE)); }

    inline CORBA_Boolean	put_octet (CORBA_Octet o)
				{ return put_byte ((char) o); }
    inline CORBA_Boolean	put_ushort (CORBA_UShort s)
				{ return put_short ((CORBA_Short) s); }
    inline CORBA_Boolean	put_ulong (CORBA_ULong l)
				{ return put_long ((CORBA_Long) l); }
    inline CORBA_Boolean	put_ulonglong (const CORBA_ULongLong &ll)
				{ return
				    put_longlong ((CORBA_LongLong &) ll); }
				    
    inline CORBA_Boolean	put_float (float f)
				{ return put_long (*(CORBA_Long *) &f); }
    inline CORBA_Boolean	put_double (const double &d)
				{ return
				    put_longlong (*(CORBA_LongLong *) &d); }

    CORBA_Boolean		put_longdouble (CORBA_LongDouble &ld);

    //
    // marshaling interpreter ... 'context' really points to a CDR.
    // 
    static CORBA_TypeCode::traverse_status
				encoder (
					CORBA_TypeCode_ptr	tc,
					const void		*data,
					const void     		*,
					void			*context,
					CORBA_Environment	&env
				);

    //
    // DECODING SUPPORT ... same assumptions are made as above, but a
    // flag is tested to determine whether decode should byteswap or not.
    // It's cheaper to do it that way than to use virtual functions.
    //

    CORBA_Boolean		get_byte (char &c);
    CORBA_Boolean		get_short (CORBA_Short &s);
    CORBA_Boolean		get_long (CORBA_Long &l);
    CORBA_Boolean		get_longlong (CORBA_LongLong &ll);

    inline CORBA_Boolean	get_char (CORBA_Char &o)
				{ return get_byte ((char &) o); }
    inline CORBA_Boolean	get_wchar (wchar_t &wc)
				{
				    short s;

				    //
				    // wchar_t isn't always "short"
				    //
				    CORBA_Boolean retval = get_short (s);
				    wc = s;
				    return retval;
				}

    inline CORBA_Boolean	get_boolean (CORBA_Boolean &b)
				{
				    CORBA_Char c;

				    //
				    // CORBA_Boolean is rarely 'char'
				    //
				    CORBA_Boolean retval = get_char (c);
				    b = (c == 1);
				    return retval;
				}

    inline CORBA_Boolean	get_octet (CORBA_Octet &o)
				{ return get_byte ((char &) o); }
    inline CORBA_Boolean	get_ushort (CORBA_UShort &s)
				{ return get_short ((short&) s); }
    inline CORBA_Boolean	get_ulong (CORBA_ULong &l)
				{ return get_long ((CORBA_Long &) l); }
    inline CORBA_Boolean	get_ulonglong (const CORBA_ULongLong &ull)
				{ return
				    get_longlong ((CORBA_LongLong &) ull); }

    inline CORBA_Boolean	get_float (float &f)
				{ return get_long ((CORBA_Long &) f); }
    inline CORBA_Boolean	get_double (double &d)
				{ return
				    get_longlong ((CORBA_LongLong &) d); }

    CORBA_Boolean		get_longdouble (CORBA_LongDouble &ld);

    //
    // unmarshaling interpreter ... 'context' really points to a CDR.
    // 
    static CORBA_TypeCode::traverse_status
				decoder (
					CORBA_TypeCode_ptr	tc,
					const void		*data,
					const void		*,
					void			*context,
					CORBA_Environment	&env
				);

		//
		// Constructor ... buffer must be aligned for the strictest
		// CDR alignment requirement, since the algorithms used here
		// only maintain alignment with respect to &buffer [0].
		//
		// Yes, that complicates the grow() primitive.
		//
		CDR (
		    unsigned char	*buf = 0,
		    unsigned		len = 0,
		    int			byte_order = MY_BYTE_SEX,
		    int			consume_buf = 0
		) :
		    real_buffer		(buf),
		    do_free		(consume_buf),
		    do_byteswap		(byte_order != MY_BYTE_SEX)
		{
		    ptr_arith_t temp = (ptr_arith_t) buf;

		    temp += MAX_ALIGNMENT - 1;
		    temp &= ~((ptr_arith_t) MAX_ALIGNMENT - 1);
		    buffer = next = (unsigned char *) temp;

		    length = remaining
			= len - (unsigned) (buffer - real_buffer);
		}

		~CDR ()
		{ if (do_free) delete real_buffer; }

    void			*operator new (size_t, void *_FAR p)
				{ return p; }
    void			*operator new (size_t s)
				{ return ::operator new (s); }
    void			operator delete (void *p)
				{ ::operator delete (p); }

    //
    // Used mostly when interpreting typecodes.  These may change the
    // state of a CDR buffer even when errors are reported.
    //
    CORBA_Boolean		skip_string ();
    CORBA_Boolean		skip_bytes (unsigned nbytes)
				{
				    if (remaining < nbytes)
					return CORBA_B_FALSE;
				    remaining -= nbytes;
				    next += nbytes;
				    return CORBA_B_TRUE;
				}
    
    //
    // Also used when interpreting typecodes, but more generally
    // when getting ready to read from encapsulations.  In such
    // cases the buffer alignment guarantees must be provided by
    // the caller, this code doesn't verify them.  These streams
    // are "read only".
    //
    void			setup_encapsulation (
				    unsigned char	*buf,
				    unsigned		len
				)
				{
				    next = buf + 1;
				    remaining = len - 1;
				    do_byteswap = (*buf != MY_BYTE_SEX);
				    do_free = 0;
				}

    //
    // Grow the buffer to the identified size ... if it's zero, just
    // grow it by a standard quantum (e.g. when encoding we can't know
    // in advance how big it will need to become).
    //
    CORBA_Boolean		grow (size_t newlength);

    //
    // Some code needs to know how much is left on encode or decode
    //
    size_t			bytes_remaining () { return remaining; }

  // private:
    //
    //  DATA MEMBERS ...
    //
    unsigned char		*next;		// next data goes here
    size_t			remaining;	// space left

    unsigned char		*real_buffer;	// maybe not aligned
    int				do_free;

    unsigned char		*buffer;
    size_t			length;

    int				do_byteswap;	// decode ONLY
};

#endif	// _CDR_HH