1/*
2  Copyright (C) 2000-2005 SKYRIX Software AG
3
4  This file is part of SOPE.
5
6  SOPE is free software; you can redistribute it and/or modify it under
7  the terms of the GNU Lesser General Public License as published by the
8  Free Software Foundation; either version 2, or (at your option) any
9  later version.
10
11  SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12  WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14  License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with SOPE; see the file COPYING.  If not, write to the
18  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19  02111-1307, USA.
20*/
21
22#include "config.h"
23
24#if !defined(WIN32)
25# if HAVE_SYS_TYPES_H
26#  include <sys/types.h>
27# endif
28# if HAVE_SYS_SOCKET_H
29#  include <sys/socket.h>
30# endif
31# if HAVE_NETINET_IN_H
32#  include <netinet/in.h>
33# endif
34#  include <arpa/inet.h>
35#endif
36
37#include "common.h"
38#include "NGStream+serialization.h"
39
40#if NeXT_RUNTIME
41#  include <objc/objc-class.h>
42#endif
43
44@implementation NGStream(serialization)
45
46// serialization
47
48- (void)serializeChar:(char)_value {
49  NGStreamSerializeObjC(self, &_value, @encode(char), nil);
50}
51- (void)serializeShort:(short)_value {
52  NGStreamSerializeObjC(self, &_value, @encode(short), nil);
53}
54- (void)serializeInt:(int)_value {
55  NGStreamSerializeObjC(self, &_value, @encode(int), nil);
56}
57- (void)serializeLong:(long)_value {
58  NGStreamSerializeObjC(self, &_value, @encode(long), nil);
59}
60
61- (void)serializeFloat:(float)_value {
62  NGStreamSerializeObjC(self, &_value, @encode(float), nil);
63}
64- (void)serializeDouble:(double)_value {
65  NGStreamSerializeObjC(self, &_value, @encode(double), nil);
66}
67- (void)serializeLongLong:(long long)_value {
68  NGStreamSerializeObjC(self, &_value, @encode(long long), nil);
69}
70
71- (void)serializeCString:(const char *)_value {
72  NGStreamSerializeObjC(self, &_value, @encode(char *), nil);
73}
74
75#if USE_SERIALIZER
76- (void)serializeDataAt:(const void*)_value ofObjCType:(const char*)_type
77  context:(id<NSObjCTypeSerializationCallBack>)_callback
78{
79  NGStreamSerializeObjC(self, _value, _type, _callback);
80}
81#endif
82
83// deserialization
84
85- (char)deserializeChar {
86  char c;
87  NGStreamDeserializeObjC(self, &c, @encode(char), nil);
88  return c;
89}
90- (short)deserializeShort {
91  short s;
92  NGStreamDeserializeObjC(self, &s, @encode(short), nil);
93  return s;
94}
95- (int)deserializeInt {
96  int i;
97  NGStreamDeserializeObjC(self, &i, @encode(int), nil);
98  return i;
99}
100- (long)deserializeLong {
101  long l;
102  NGStreamDeserializeObjC(self, &l, @encode(long), nil);
103  return l;
104}
105- (float)deserializeFloat {
106  float f;
107  NGStreamDeserializeObjC(self, &f, @encode(float), nil);
108  return f;
109}
110
111- (double)deserializeDouble {
112  double d;
113  NGStreamDeserializeObjC(self, &d, @encode(double), nil);
114  return d;
115}
116- (long long)deserializeLongLong {
117  long long l;
118  NGStreamDeserializeObjC(self, &l, @encode(long long), nil);
119  return l;
120}
121
122- (char *)deserializeCString {
123  char *result = NULL;
124  NGStreamDeserializeObjC(self, &result, @encode(char *), nil);
125  return result;
126}
127
128#if USE_SERIALIZER
129- (void)deserializeDataAt:(void *)_value ofObjCType:(const char *)_type
130  context:(id<NSObjCTypeSerializationCallBack>)_callback
131{
132  NGStreamDeserializeObjC(self, _value, _type, _callback);
133}
134#endif
135
136@end
137
138void NGStreamSerializeObjC(id<NGStream> self,
139                           const void *_value, const char *_type,
140#if USE_SERIALIZER
141                           id<NSObjCTypeSerializationCallBack> _callback
142#else
143                           id _callback
144#endif
145                           )
146{
147  switch (*_type) {
148    case _C_ID:
149    case _C_CLASS:
150      [_callback serializeObjectAt:(id *)_value
151                 ofObjCType:_type
152                 intoData:(NSMutableData *)self];
153      break;
154
155    case _C_CHARPTR: {
156      const char *cstr = *(char **)_value;
157      int        len   = cstr ? (int)strlen(cstr) : -1;
158
159      NGStreamSerializeObjC(self, &len, @encode(int), _callback);
160      if (cstr)
161        [self safeWriteBytes:cstr count:len];
162
163      break;
164    }
165
166    case _C_ARY_B: {
167      int i, offset, itemSize, count;
168
169      count = atoi(_type + 1); // skip '[' and get dimension
170
171      while (isdigit((int)*++_type)) ; // skip '[' and dimension
172      itemSize = objc_sizeof_type(_type);
173
174      for (i = offset = 0; i < count; i++, offset += itemSize)
175        NGStreamSerializeObjC(self, (char *)_value + offset, _type, _callback);
176      break;
177    }
178
179    case _C_STRUCT_B: {
180      int offset = 0;
181
182      while ((*_type != _C_STRUCT_E) && (*_type++ != '=')) ; // skip '<name>='
183
184      while (YES) {
185        NGStreamSerializeObjC(self, (char *)_value + offset, _type, _callback);
186
187        offset += objc_sizeof_type(_type);
188        _type  =  objc_skip_typespec(_type);
189
190        if (*_type != _C_STRUCT_E) {
191          int align, remainder;
192
193          align = objc_alignof_type(_type);
194          if ((remainder = offset % align))
195            offset += align - remainder;
196        }
197        else // done with structure
198          break;
199      }
200      break;
201    }
202
203    case _C_PTR:
204      NGStreamSerializeObjC(self, *(char **)_value, _type + 1, _callback);
205      break;
206
207    case _C_CHR:
208    case _C_UCHR:
209      [self safeWriteBytes:_value count:1];
210      break;
211
212    case _C_SHT:
213    case _C_USHT: {
214      short netValue = htons(*(short *)_value);
215      [self safeWriteBytes:&netValue count:2];
216      break;
217    }
218
219    case _C_INT:
220    case _C_UINT: {
221      int netValue = htonl(*(int *)_value);
222      [self safeWriteBytes:&netValue count:4];
223      break;
224    }
225
226    case _C_LNG:
227    case _C_ULNG: {
228      long netValue = htonl(*(long *)_value);
229      [self safeWriteBytes:&netValue count:sizeof(long)];
230      break;
231    }
232
233    case _C_FLT: {
234      union fconv {
235        float         value;
236        unsigned long ul;
237      } fc;
238      fc.value = *(float *)_value;
239      fc.ul    = htonl(fc.ul);
240      [self safeWriteBytes:&fc count:sizeof(unsigned long)];
241      break;
242    }
243    case _C_DBL: {
244      [self safeWriteBytes:_value count:8];
245      break;
246    }
247
248    default:
249      NSCAssert1(0, @"unsupported C type %s ..", _type);
250      break;
251  }
252}
253
254void NGStreamDeserializeObjC(id<NGStream> self,
255                             void *_value, const char *_type,
256#if USE_SERIALIZER
257                             id<NSObjCTypeSerializationCallBack> _callback
258#else
259                             id _callback
260#endif
261                             )
262{
263  if ((_value == NULL) || (_type == NULL))
264    return;
265
266  switch (*_type) {
267    case _C_ID:
268    case _C_CLASS:
269      [_callback deserializeObjectAt:(id *)_value
270                 ofObjCType:_type
271                 fromData:(NSData *)self
272                 atCursor:0];
273      break;
274
275    case _C_CHARPTR: { // malloced C-string
276      int len = -1;
277
278      NGStreamDeserializeObjC(self, &len, @encode(int), _callback);
279
280      if (len == -1) // NULL-string
281        *(char **)_value = NULL;
282      else {
283        char *result = NULL;
284
285#if LIB_FOUNDATION_LIBRARY
286        result = NSZoneMallocAtomic(NULL, len + 1);
287#else
288        result = NSZoneMalloc(NULL, len + 1);
289#endif
290        result[len] = '\0';
291
292        if (len > 0) [self safeReadBytes:result count:len];
293        *(char **)_value = result;
294      }
295      break;
296    }
297
298    case _C_ARY_B: {
299      int i, offset, itemSize, count;
300
301      count = atoi(_type + 1); // skip '[' and get dimension
302
303      while (isdigit((int)*++_type)) ; // skip '[' and dimension
304      itemSize = objc_sizeof_type(_type);
305
306      for (i = offset = 0; i < count; i++, offset += itemSize)
307        NGStreamDeserializeObjC(self, (char *)_value + offset, _type, _callback);
308
309      break;
310    }
311
312    case _C_STRUCT_B: {
313      int offset = 0;
314
315      while ((*_type != _C_STRUCT_E) && (*_type++ != '=')) ; // skip '<name>='
316
317      while (YES) {
318        NGStreamDeserializeObjC(self, (char *)_value + offset, _type, _callback);
319
320        offset += objc_sizeof_type(_type);
321        _type  =  objc_skip_typespec(_type);
322
323        if (*_type != _C_STRUCT_E) {
324          int align, remainder;
325
326          align = objc_alignof_type(_type);
327          if ((remainder = offset % align))
328            offset += align - remainder;
329        }
330        else // done with structure
331          break;
332      }
333      break;
334    }
335
336    case _C_PTR: {
337       // skip '^', type of the value the ptr points to
338      void *result = NULL;
339
340      result = NSZoneMalloc(NULL, objc_sizeof_type(_type + 1));
341
342      NGStreamDeserializeObjC(self, result, _type + 1, _callback);
343
344      *(char **)_value = result;
345      result = NULL;
346
347      break;
348    }
349
350    case _C_CHR:
351    case _C_UCHR:
352      [self safeReadBytes:_value count:1];
353      break;
354
355    case _C_SHT:
356    case _C_USHT:
357      [self safeReadBytes:_value count:2];
358      *(short *)_value = ntohs(*(short *)_value);
359      break;
360
361    case _C_INT:
362    case _C_UINT:
363      [self safeReadBytes:_value count:4];
364      *(int *)_value = ntohl(*(int *)_value);
365      break;
366
367    case _C_LNG:
368    case _C_ULNG:
369      [self safeReadBytes:_value count:4];
370      *(long *)_value = ntohl(*(long *)_value);
371      break;
372
373    case _C_FLT: {
374      [self safeReadBytes:_value count:4];
375      *(long *)_value = ntohl(*(long *)_value);
376      break;
377    }
378    case _C_DBL: {
379      [self safeReadBytes:_value count:8];
380      break;
381    }
382
383    default:
384      NSLog(@"unsupported C type %s ..", _type);
385      break;
386  }
387}
388
389void __link_NGStream_serialization(void) {
390  __link_NGStream_serialization();
391}
392