]>
Commit | Line | Data |
---|---|---|
40165636 | 1 | /* GNU Objective C Runtime archiving |
748086b7 | 2 | Copyright (C) 1993, 1995, 1996, 1997, 2002, 2004, 2009 Free Software Foundation, Inc. |
88e17b57 BE |
3 | Contributed by Kresten Krab Thorup |
4 | ||
6c82ad25 | 5 | This file is part of GCC. |
88e17b57 | 6 | |
6c82ad25 | 7 | GCC is free software; you can redistribute it and/or modify it under the |
88e17b57 | 8 | terms of the GNU General Public License as published by the Free Software |
748086b7 | 9 | Foundation; either version 3, or (at your option) any later version. |
88e17b57 | 10 | |
6c82ad25 | 11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
88e17b57 BE |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
13 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |
14 | details. | |
15 | ||
748086b7 JJ |
16 | Under Section 7 of GPL version 3, you are granted additional |
17 | permissions described in the GCC Runtime Library Exception, version | |
18 | 3.1, as published by the Free Software Foundation. | |
88e17b57 | 19 | |
748086b7 JJ |
20 | You should have received a copy of the GNU General Public License and |
21 | a copy of the GCC Runtime Library Exception along with this program; | |
22 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | <http://www.gnu.org/licenses/>. */ | |
88e17b57 | 24 | |
6dead247 | 25 | #include "objc-private/common.h" |
4102f627 | 26 | #include "tconfig.h" |
a19fac96 NP |
27 | #include "objc/objc.h" |
28 | #include "objc/objc-api.h" | |
a19fac96 NP |
29 | #include "objc/hash.h" |
30 | #include "objc/objc-list.h" | |
31 | #include "objc-private/runtime.h" | |
348a3445 DA |
32 | #include "objc/typedstream.h" |
33 | #include "objc/encoding.h" | |
88e17b57 | 34 | #include <stdlib.h> |
88e17b57 | 35 | |
40165636 | 36 | extern int fflush (FILE *); |
88e17b57 BE |
37 | |
38 | #define ROUND(V, A) \ | |
40165636 RB |
39 | ({ typeof (V) __v = (V); typeof (A) __a = (A); \ |
40 | __a * ((__v + __a - 1)/__a); }) | |
88e17b57 | 41 | |
40165636 RB |
42 | #define PTR2LONG(P) (((char *) (P))-(char *) 0) |
43 | #define LONG2PTR(L) (((char *) 0) + (L)) | |
88e17b57 BE |
44 | |
45 | /* Declare some functions... */ | |
46 | ||
47 | static int | |
40165636 | 48 | objc_read_class (struct objc_typed_stream *stream, Class *class); |
88e17b57 | 49 | |
40165636 | 50 | int objc_sizeof_type (const char *type); |
88e17b57 BE |
51 | |
52 | static int | |
40165636 | 53 | objc_write_use_common (struct objc_typed_stream *stream, unsigned long key); |
88e17b57 BE |
54 | |
55 | static int | |
40165636 | 56 | objc_write_register_common (struct objc_typed_stream *stream, |
88e17b57 BE |
57 | unsigned long key); |
58 | ||
59 | static int | |
40165636 RB |
60 | objc_write_class (struct objc_typed_stream *stream, |
61 | struct objc_class *class); | |
88e17b57 | 62 | |
40165636 | 63 | const char *objc_skip_type (const char *type); |
88e17b57 | 64 | |
40165636 RB |
65 | static void __objc_finish_write_root_object (struct objc_typed_stream *); |
66 | static void __objc_finish_read_root_object (struct objc_typed_stream *); | |
88e17b57 | 67 | |
435317e2 | 68 | static inline int |
40165636 | 69 | __objc_code_unsigned_char (unsigned char *buf, unsigned char val) |
88e17b57 BE |
70 | { |
71 | if ((val&_B_VALUE) == val) | |
72 | { | |
73 | buf[0] = val|_B_SINT; | |
74 | return 1; | |
75 | } | |
76 | else | |
77 | { | |
78 | buf[0] = _B_NINT|0x01; | |
79 | buf[1] = val; | |
80 | return 2; | |
81 | } | |
82 | } | |
83 | ||
84 | int | |
40165636 | 85 | objc_write_unsigned_char (struct objc_typed_stream *stream, |
88e17b57 BE |
86 | unsigned char value) |
87 | { | |
40165636 | 88 | unsigned char buf[sizeof (unsigned char) + 1]; |
88e17b57 | 89 | int len = __objc_code_unsigned_char (buf, value); |
8d488306 | 90 | return (*stream->write) (stream->physical, (char*)buf, len); |
88e17b57 BE |
91 | } |
92 | ||
435317e2 | 93 | static inline int |
40165636 | 94 | __objc_code_char (unsigned char *buf, signed char val) |
88e17b57 BE |
95 | { |
96 | if (val >= 0) | |
97 | return __objc_code_unsigned_char (buf, val); | |
98 | else | |
99 | { | |
100 | buf[0] = _B_NINT|_B_SIGN|0x01; | |
101 | buf[1] = -val; | |
102 | return 2; | |
103 | } | |
104 | } | |
105 | ||
106 | int | |
40165636 | 107 | objc_write_char (struct objc_typed_stream *stream, signed char value) |
88e17b57 | 108 | { |
40165636 | 109 | unsigned char buf[sizeof (char) + 1]; |
88e17b57 | 110 | int len = __objc_code_char (buf, value); |
8d488306 | 111 | return (*stream->write) (stream->physical, (char*)buf, len); |
88e17b57 BE |
112 | } |
113 | ||
435317e2 | 114 | static inline int |
40165636 | 115 | __objc_code_unsigned_short (unsigned char *buf, unsigned short val) |
88e17b57 BE |
116 | { |
117 | if ((val&_B_VALUE) == val) | |
118 | { | |
119 | buf[0] = val|_B_SINT; | |
120 | return 1; | |
121 | } | |
122 | else | |
123 | { | |
124 | int c, b; | |
125 | ||
126 | buf[0] = _B_NINT; | |
127 | ||
40165636 RB |
128 | for (c = sizeof (short); c != 0; c -= 1) |
129 | if (((val >> (8*(c - 1)))%0x100) != 0) | |
88e17b57 BE |
130 | break; |
131 | ||
132 | buf[0] |= c; | |
133 | ||
134 | for (b = 1; c != 0; c--, b++) | |
135 | { | |
40165636 | 136 | buf[b] = (val >> (8*(c - 1)))%0x100; |
88e17b57 BE |
137 | } |
138 | ||
139 | return b; | |
140 | } | |
141 | } | |
142 | ||
143 | int | |
40165636 | 144 | objc_write_unsigned_short (struct objc_typed_stream *stream, |
88e17b57 BE |
145 | unsigned short value) |
146 | { | |
40165636 | 147 | unsigned char buf[sizeof (unsigned short) + 1]; |
88e17b57 | 148 | int len = __objc_code_unsigned_short (buf, value); |
8d488306 | 149 | return (*stream->write) (stream->physical, (char*)buf, len); |
88e17b57 BE |
150 | } |
151 | ||
435317e2 | 152 | static inline int |
40165636 | 153 | __objc_code_short (unsigned char *buf, short val) |
88e17b57 BE |
154 | { |
155 | int sign = (val < 0); | |
156 | int size = __objc_code_unsigned_short (buf, sign ? -val : val); | |
157 | if (sign) | |
158 | buf[0] |= _B_SIGN; | |
159 | return size; | |
160 | } | |
161 | ||
162 | int | |
40165636 | 163 | objc_write_short (struct objc_typed_stream *stream, short value) |
88e17b57 | 164 | { |
40165636 | 165 | unsigned char buf[sizeof (short) + 1]; |
88e17b57 | 166 | int len = __objc_code_short (buf, value); |
8d488306 | 167 | return (*stream->write) (stream->physical, (char*)buf, len); |
88e17b57 BE |
168 | } |
169 | ||
170 | ||
435317e2 | 171 | static inline int |
40165636 | 172 | __objc_code_unsigned_int (unsigned char *buf, unsigned int val) |
88e17b57 BE |
173 | { |
174 | if ((val&_B_VALUE) == val) | |
175 | { | |
176 | buf[0] = val|_B_SINT; | |
177 | return 1; | |
178 | } | |
179 | else | |
180 | { | |
181 | int c, b; | |
182 | ||
183 | buf[0] = _B_NINT; | |
184 | ||
40165636 RB |
185 | for (c = sizeof (int); c != 0; c -= 1) |
186 | if (((val >> (8*(c - 1)))%0x100) != 0) | |
88e17b57 BE |
187 | break; |
188 | ||
189 | buf[0] |= c; | |
190 | ||
191 | for (b = 1; c != 0; c--, b++) | |
192 | { | |
193 | buf[b] = (val >> (8*(c-1)))%0x100; | |
194 | } | |
195 | ||
196 | return b; | |
197 | } | |
198 | } | |
199 | ||
200 | int | |
40165636 | 201 | objc_write_unsigned_int (struct objc_typed_stream *stream, unsigned int value) |
88e17b57 | 202 | { |
40165636 | 203 | unsigned char buf[sizeof (unsigned int) + 1]; |
88e17b57 | 204 | int len = __objc_code_unsigned_int (buf, value); |
8d488306 | 205 | return (*stream->write) (stream->physical, (char*)buf, len); |
88e17b57 BE |
206 | } |
207 | ||
435317e2 | 208 | static inline int |
40165636 | 209 | __objc_code_int (unsigned char *buf, int val) |
88e17b57 BE |
210 | { |
211 | int sign = (val < 0); | |
212 | int size = __objc_code_unsigned_int (buf, sign ? -val : val); | |
213 | if (sign) | |
214 | buf[0] |= _B_SIGN; | |
215 | return size; | |
216 | } | |
217 | ||
218 | int | |
40165636 | 219 | objc_write_int (struct objc_typed_stream *stream, int value) |
88e17b57 | 220 | { |
40165636 | 221 | unsigned char buf[sizeof (int) + 1]; |
88e17b57 | 222 | int len = __objc_code_int (buf, value); |
8d488306 | 223 | return (*stream->write) (stream->physical, (char*)buf, len); |
88e17b57 BE |
224 | } |
225 | ||
435317e2 | 226 | static inline int |
40165636 | 227 | __objc_code_unsigned_long (unsigned char *buf, unsigned long val) |
88e17b57 BE |
228 | { |
229 | if ((val&_B_VALUE) == val) | |
230 | { | |
231 | buf[0] = val|_B_SINT; | |
232 | return 1; | |
233 | } | |
234 | else | |
235 | { | |
236 | int c, b; | |
237 | ||
238 | buf[0] = _B_NINT; | |
239 | ||
40165636 RB |
240 | for (c = sizeof (long); c != 0; c -= 1) |
241 | if (((val >> (8*(c - 1)))%0x100) != 0) | |
88e17b57 BE |
242 | break; |
243 | ||
244 | buf[0] |= c; | |
245 | ||
246 | for (b = 1; c != 0; c--, b++) | |
247 | { | |
40165636 | 248 | buf[b] = (val >> (8*(c - 1)))%0x100; |
88e17b57 BE |
249 | } |
250 | ||
251 | return b; | |
252 | } | |
253 | } | |
254 | ||
255 | int | |
40165636 | 256 | objc_write_unsigned_long (struct objc_typed_stream *stream, |
88e17b57 BE |
257 | unsigned long value) |
258 | { | |
40165636 | 259 | unsigned char buf[sizeof (unsigned long) + 1]; |
88e17b57 | 260 | int len = __objc_code_unsigned_long (buf, value); |
8d488306 | 261 | return (*stream->write) (stream->physical, (char*)buf, len); |
88e17b57 BE |
262 | } |
263 | ||
435317e2 | 264 | static inline int |
40165636 | 265 | __objc_code_long (unsigned char *buf, long val) |
88e17b57 BE |
266 | { |
267 | int sign = (val < 0); | |
268 | int size = __objc_code_unsigned_long (buf, sign ? -val : val); | |
269 | if (sign) | |
270 | buf[0] |= _B_SIGN; | |
271 | return size; | |
272 | } | |
273 | ||
274 | int | |
40165636 | 275 | objc_write_long (struct objc_typed_stream *stream, long value) |
88e17b57 | 276 | { |
40165636 | 277 | unsigned char buf[sizeof (long) + 1]; |
88e17b57 | 278 | int len = __objc_code_long (buf, value); |
8d488306 | 279 | return (*stream->write) (stream->physical, (char*)buf, len); |
88e17b57 BE |
280 | } |
281 | ||
282 | ||
283 | int | |
40165636 RB |
284 | objc_write_string (struct objc_typed_stream *stream, |
285 | const unsigned char *string, unsigned int nbytes) | |
88e17b57 | 286 | { |
40165636 | 287 | unsigned char buf[sizeof (unsigned int) + 1]; |
88e17b57 BE |
288 | int len = __objc_code_unsigned_int (buf, nbytes); |
289 | ||
290 | if ((buf[0]&_B_CODE) == _B_SINT) | |
291 | buf[0] = (buf[0]&_B_VALUE)|_B_SSTR; | |
292 | ||
293 | else /* _B_NINT */ | |
294 | buf[0] = (buf[0]&_B_VALUE)|_B_NSTR; | |
295 | ||
8d488306 AP |
296 | if ((*stream->write) (stream->physical, (char*)buf, len) != 0) |
297 | return (*stream->write) (stream->physical, (char*)string, nbytes); | |
88e17b57 BE |
298 | else |
299 | return 0; | |
300 | } | |
301 | ||
302 | int | |
40165636 RB |
303 | objc_write_string_atomic (struct objc_typed_stream *stream, |
304 | unsigned char *string, unsigned int nbytes) | |
88e17b57 BE |
305 | { |
306 | unsigned long key; | |
270a1283 | 307 | if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, string)))) |
88e17b57 BE |
308 | return objc_write_use_common (stream, key); |
309 | else | |
310 | { | |
311 | int length; | |
270a1283 DA |
312 | objc_hash_add (&stream->stream_table, |
313 | LONG2PTR(key=PTR2LONG(string)), string); | |
88e17b57 BE |
314 | if ((length = objc_write_register_common (stream, key))) |
315 | return objc_write_string (stream, string, nbytes); | |
316 | return length; | |
317 | } | |
318 | } | |
319 | ||
320 | static int | |
40165636 | 321 | objc_write_register_common (struct objc_typed_stream *stream, |
88e17b57 BE |
322 | unsigned long key) |
323 | { | |
324 | unsigned char buf[sizeof (unsigned long)+2]; | |
40165636 | 325 | int len = __objc_code_unsigned_long (buf + 1, key); |
88e17b57 BE |
326 | if (len == 1) |
327 | { | |
328 | buf[0] = _B_RCOMM|0x01; | |
329 | buf[1] &= _B_VALUE; | |
8d488306 | 330 | return (*stream->write) (stream->physical, (char*)buf, len + 1); |
88e17b57 BE |
331 | } |
332 | else | |
333 | { | |
334 | buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM; | |
8d488306 | 335 | return (*stream->write) (stream->physical, (char*)buf + 1, len); |
88e17b57 BE |
336 | } |
337 | } | |
338 | ||
339 | static int | |
40165636 | 340 | objc_write_use_common (struct objc_typed_stream *stream, unsigned long key) |
88e17b57 BE |
341 | { |
342 | unsigned char buf[sizeof (unsigned long)+2]; | |
40165636 | 343 | int len = __objc_code_unsigned_long (buf + 1, key); |
88e17b57 BE |
344 | if (len == 1) |
345 | { | |
346 | buf[0] = _B_UCOMM|0x01; | |
347 | buf[1] &= _B_VALUE; | |
8d488306 | 348 | return (*stream->write) (stream->physical, (char*)buf, 2); |
88e17b57 BE |
349 | } |
350 | else | |
351 | { | |
352 | buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM; | |
8d488306 | 353 | return (*stream->write) (stream->physical, (char*)buf + 1, len); |
88e17b57 BE |
354 | } |
355 | } | |
356 | ||
435317e2 | 357 | static inline int |
40165636 | 358 | __objc_write_extension (struct objc_typed_stream *stream, unsigned char code) |
88e17b57 BE |
359 | { |
360 | if (code <= _B_VALUE) | |
361 | { | |
362 | unsigned char buf = code|_B_EXT; | |
8d488306 | 363 | return (*stream->write) (stream->physical, (char*)&buf, 1); |
88e17b57 BE |
364 | } |
365 | else | |
366 | { | |
40165636 RB |
367 | objc_error (nil, OBJC_ERR_BAD_OPCODE, |
368 | "__objc_write_extension: bad opcode %c\n", code); | |
88e17b57 BE |
369 | return -1; |
370 | } | |
371 | } | |
372 | ||
435317e2 | 373 | inline int |
40165636 | 374 | __objc_write_object (struct objc_typed_stream *stream, id object) |
88e17b57 BE |
375 | { |
376 | unsigned char buf = '\0'; | |
377 | SEL write_sel = sel_get_any_uid ("write:"); | |
378 | if (object) | |
379 | { | |
380 | __objc_write_extension (stream, _BX_OBJECT); | |
381 | objc_write_class (stream, object->class_pointer); | |
40165636 | 382 | (*objc_msg_lookup (object, write_sel)) (object, write_sel, stream); |
8d488306 | 383 | return (*stream->write) (stream->physical, (char*)&buf, 1); |
88e17b57 BE |
384 | } |
385 | else | |
40165636 | 386 | return objc_write_use_common (stream, 0); |
88e17b57 BE |
387 | } |
388 | ||
389 | int | |
40165636 | 390 | objc_write_object_reference (struct objc_typed_stream *stream, id object) |
88e17b57 BE |
391 | { |
392 | unsigned long key; | |
270a1283 | 393 | if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object)))) |
88e17b57 BE |
394 | return objc_write_use_common (stream, key); |
395 | ||
396 | __objc_write_extension (stream, _BX_OBJREF); | |
397 | return objc_write_unsigned_long (stream, PTR2LONG (object)); | |
398 | } | |
399 | ||
400 | int | |
40165636 | 401 | objc_write_root_object (struct objc_typed_stream *stream, id object) |
88e17b57 BE |
402 | { |
403 | int len = 0; | |
404 | if (stream->writing_root_p) | |
405 | objc_error (nil, OBJC_ERR_RECURSE_ROOT, | |
406 | "objc_write_root_object called recursively"); | |
407 | else | |
408 | { | |
409 | stream->writing_root_p = 1; | |
410 | __objc_write_extension (stream, _BX_OBJROOT); | |
40165636 RB |
411 | if ((len = objc_write_object (stream, object))) |
412 | __objc_finish_write_root_object (stream); | |
88e17b57 BE |
413 | stream->writing_root_p = 0; |
414 | } | |
415 | return len; | |
416 | } | |
417 | ||
418 | int | |
40165636 | 419 | objc_write_object (struct objc_typed_stream *stream, id object) |
88e17b57 BE |
420 | { |
421 | unsigned long key; | |
270a1283 | 422 | if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object)))) |
88e17b57 BE |
423 | return objc_write_use_common (stream, key); |
424 | ||
425 | else if (object == nil) | |
40165636 | 426 | return objc_write_use_common (stream, 0); |
88e17b57 BE |
427 | |
428 | else | |
429 | { | |
430 | int length; | |
270a1283 DA |
431 | objc_hash_add (&stream->object_table, |
432 | LONG2PTR(key=PTR2LONG(object)), object); | |
88e17b57 BE |
433 | if ((length = objc_write_register_common (stream, key))) |
434 | return __objc_write_object (stream, object); | |
435 | return length; | |
436 | } | |
437 | } | |
438 | ||
435317e2 | 439 | inline int |
40165636 | 440 | __objc_write_class (struct objc_typed_stream *stream, struct objc_class *class) |
88e17b57 BE |
441 | { |
442 | __objc_write_extension (stream, _BX_CLASS); | |
8d488306 | 443 | objc_write_string_atomic (stream, (unsigned char *) class->name, |
40165636 | 444 | strlen ((char *) class->name)); |
88e17b57 BE |
445 | return objc_write_unsigned_long (stream, class->version); |
446 | } | |
447 | ||
448 | ||
449 | static int | |
40165636 RB |
450 | objc_write_class (struct objc_typed_stream *stream, |
451 | struct objc_class *class) | |
88e17b57 BE |
452 | { |
453 | unsigned long key; | |
270a1283 | 454 | if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, class)))) |
88e17b57 BE |
455 | return objc_write_use_common (stream, key); |
456 | else | |
457 | { | |
458 | int length; | |
270a1283 DA |
459 | objc_hash_add (&stream->stream_table, |
460 | LONG2PTR(key = PTR2LONG(class)), class); | |
88e17b57 BE |
461 | if ((length = objc_write_register_common (stream, key))) |
462 | return __objc_write_class (stream, class); | |
463 | return length; | |
464 | } | |
465 | } | |
466 | ||
467 | ||
435317e2 | 468 | inline int |
40165636 | 469 | __objc_write_selector (struct objc_typed_stream *stream, SEL selector) |
88e17b57 | 470 | { |
40165636 | 471 | const char *sel_name; |
88e17b57 BE |
472 | __objc_write_extension (stream, _BX_SEL); |
473 | /* to handle NULL selectors */ | |
474 | if ((SEL)0 == selector) | |
8d488306 | 475 | return objc_write_string (stream, (unsigned char*)"", 0); |
88e17b57 | 476 | sel_name = sel_get_name (selector); |
8d488306 | 477 | return objc_write_string (stream, (unsigned char*)sel_name, strlen ((char*)sel_name)); |
88e17b57 BE |
478 | } |
479 | ||
480 | int | |
40165636 | 481 | objc_write_selector (struct objc_typed_stream *stream, SEL selector) |
88e17b57 | 482 | { |
40165636 | 483 | const char *sel_name; |
88e17b57 BE |
484 | unsigned long key; |
485 | ||
486 | /* to handle NULL selectors */ | |
487 | if ((SEL)0 == selector) | |
488 | return __objc_write_selector (stream, selector); | |
489 | ||
490 | sel_name = sel_get_name (selector); | |
270a1283 DA |
491 | if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, |
492 | sel_name)))) | |
88e17b57 BE |
493 | return objc_write_use_common (stream, key); |
494 | else | |
495 | { | |
496 | int length; | |
270a1283 | 497 | objc_hash_add (&stream->stream_table, |
40165636 | 498 | LONG2PTR(key = PTR2LONG(sel_name)), (char *) sel_name); |
88e17b57 BE |
499 | if ((length = objc_write_register_common (stream, key))) |
500 | return __objc_write_selector (stream, selector); | |
501 | return length; | |
502 | } | |
503 | } | |
504 | ||
505 | ||
506 | ||
507 | /* | |
508 | ** Read operations | |
509 | */ | |
510 | ||
435317e2 | 511 | inline int |
40165636 | 512 | objc_read_char (struct objc_typed_stream *stream, char *val) |
88e17b57 BE |
513 | { |
514 | unsigned char buf; | |
515 | int len; | |
8d488306 | 516 | len = (*stream->read) (stream->physical, (char*)&buf, 1); |
88e17b57 BE |
517 | if (len != 0) |
518 | { | |
519 | if ((buf & _B_CODE) == _B_SINT) | |
520 | (*val) = (buf & _B_VALUE); | |
521 | ||
522 | else if ((buf & _B_NUMBER) == 1) | |
523 | { | |
40165636 | 524 | len = (*stream->read) (stream->physical, val, 1); |
88e17b57 | 525 | if (buf&_B_SIGN) |
40165636 | 526 | (*val) = -1 * (*val); |
88e17b57 BE |
527 | } |
528 | ||
529 | else | |
40165636 RB |
530 | objc_error (nil, OBJC_ERR_BAD_DATA, |
531 | "expected 8bit signed int, got %dbit int", | |
532 | (int) (buf&_B_NUMBER)*8); | |
88e17b57 BE |
533 | } |
534 | return len; | |
535 | } | |
536 | ||
537 | ||
435317e2 | 538 | inline int |
40165636 | 539 | objc_read_unsigned_char (struct objc_typed_stream *stream, unsigned char *val) |
88e17b57 BE |
540 | { |
541 | unsigned char buf; | |
542 | int len; | |
8d488306 | 543 | if ((len = (*stream->read) (stream->physical, (char*)&buf, 1))) |
88e17b57 BE |
544 | { |
545 | if ((buf & _B_CODE) == _B_SINT) | |
546 | (*val) = (buf & _B_VALUE); | |
547 | ||
548 | else if ((buf & _B_NUMBER) == 1) | |
8d488306 | 549 | len = (*stream->read) (stream->physical, (char*)val, 1); |
88e17b57 BE |
550 | |
551 | else | |
40165636 RB |
552 | objc_error (nil, OBJC_ERR_BAD_DATA, |
553 | "expected 8bit unsigned int, got %dbit int", | |
554 | (int) (buf&_B_NUMBER)*8); | |
88e17b57 BE |
555 | } |
556 | return len; | |
557 | } | |
558 | ||
435317e2 | 559 | inline int |
40165636 | 560 | objc_read_short (struct objc_typed_stream *stream, short *value) |
88e17b57 | 561 | { |
40165636 | 562 | unsigned char buf[sizeof (short) + 1]; |
88e17b57 | 563 | int len; |
8d488306 | 564 | if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) |
88e17b57 BE |
565 | { |
566 | if ((buf[0] & _B_CODE) == _B_SINT) | |
567 | (*value) = (buf[0] & _B_VALUE); | |
568 | ||
569 | else | |
570 | { | |
571 | int pos = 1; | |
572 | int nbytes = buf[0] & _B_NUMBER; | |
8f8c44cb | 573 | if (nbytes > (int) sizeof (short)) |
40165636 RB |
574 | objc_error (nil, OBJC_ERR_BAD_DATA, |
575 | "expected short, got bigger (%dbits)", nbytes*8); | |
8d488306 | 576 | len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes); |
88e17b57 BE |
577 | (*value) = 0; |
578 | while (pos <= nbytes) | |
579 | (*value) = ((*value)*0x100) + buf[pos++]; | |
580 | if (buf[0] & _B_SIGN) | |
581 | (*value) = -(*value); | |
582 | } | |
583 | } | |
584 | return len; | |
585 | } | |
586 | ||
435317e2 | 587 | inline int |
40165636 RB |
588 | objc_read_unsigned_short (struct objc_typed_stream *stream, |
589 | unsigned short *value) | |
88e17b57 | 590 | { |
40165636 | 591 | unsigned char buf[sizeof (unsigned short) + 1]; |
88e17b57 | 592 | int len; |
8d488306 | 593 | if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) |
88e17b57 BE |
594 | { |
595 | if ((buf[0] & _B_CODE) == _B_SINT) | |
596 | (*value) = (buf[0] & _B_VALUE); | |
597 | ||
598 | else | |
599 | { | |
600 | int pos = 1; | |
601 | int nbytes = buf[0] & _B_NUMBER; | |
8f8c44cb | 602 | if (nbytes > (int) sizeof (short)) |
40165636 RB |
603 | objc_error (nil, OBJC_ERR_BAD_DATA, |
604 | "expected short, got int or bigger"); | |
8d488306 | 605 | len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes); |
88e17b57 BE |
606 | (*value) = 0; |
607 | while (pos <= nbytes) | |
608 | (*value) = ((*value)*0x100) + buf[pos++]; | |
609 | } | |
610 | } | |
611 | return len; | |
612 | } | |
613 | ||
614 | ||
435317e2 | 615 | inline int |
40165636 | 616 | objc_read_int (struct objc_typed_stream *stream, int *value) |
88e17b57 | 617 | { |
40165636 | 618 | unsigned char buf[sizeof (int) + 1]; |
88e17b57 | 619 | int len; |
8d488306 | 620 | if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) |
88e17b57 BE |
621 | { |
622 | if ((buf[0] & _B_CODE) == _B_SINT) | |
623 | (*value) = (buf[0] & _B_VALUE); | |
624 | ||
625 | else | |
626 | { | |
627 | int pos = 1; | |
628 | int nbytes = buf[0] & _B_NUMBER; | |
8f8c44cb | 629 | if (nbytes > (int) sizeof (int)) |
40165636 | 630 | objc_error (nil, OBJC_ERR_BAD_DATA, "expected int, got bigger"); |
8d488306 | 631 | len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes); |
88e17b57 BE |
632 | (*value) = 0; |
633 | while (pos <= nbytes) | |
634 | (*value) = ((*value)*0x100) + buf[pos++]; | |
635 | if (buf[0] & _B_SIGN) | |
636 | (*value) = -(*value); | |
637 | } | |
638 | } | |
639 | return len; | |
640 | } | |
641 | ||
435317e2 | 642 | inline int |
40165636 | 643 | objc_read_long (struct objc_typed_stream *stream, long *value) |
88e17b57 | 644 | { |
40165636 | 645 | unsigned char buf[sizeof (long) + 1]; |
88e17b57 | 646 | int len; |
8d488306 | 647 | if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) |
88e17b57 BE |
648 | { |
649 | if ((buf[0] & _B_CODE) == _B_SINT) | |
650 | (*value) = (buf[0] & _B_VALUE); | |
651 | ||
652 | else | |
653 | { | |
654 | int pos = 1; | |
655 | int nbytes = buf[0] & _B_NUMBER; | |
8f8c44cb | 656 | if (nbytes > (int) sizeof (long)) |
40165636 | 657 | objc_error (nil, OBJC_ERR_BAD_DATA, "expected long, got bigger"); |
8d488306 | 658 | len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes); |
88e17b57 BE |
659 | (*value) = 0; |
660 | while (pos <= nbytes) | |
661 | (*value) = ((*value)*0x100) + buf[pos++]; | |
662 | if (buf[0] & _B_SIGN) | |
663 | (*value) = -(*value); | |
664 | } | |
665 | } | |
666 | return len; | |
667 | } | |
668 | ||
435317e2 | 669 | inline int |
40165636 RB |
670 | __objc_read_nbyte_uint (struct objc_typed_stream *stream, |
671 | unsigned int nbytes, unsigned int *val) | |
88e17b57 | 672 | { |
8f8c44cb KG |
673 | int len; |
674 | unsigned int pos = 0; | |
40165636 | 675 | unsigned char buf[sizeof (unsigned int) + 1]; |
88e17b57 BE |
676 | |
677 | if (nbytes > sizeof (int)) | |
40165636 | 678 | objc_error (nil, OBJC_ERR_BAD_DATA, "expected int, got bigger"); |
88e17b57 | 679 | |
8d488306 | 680 | len = (*stream->read) (stream->physical, (char*)buf, nbytes); |
88e17b57 BE |
681 | (*val) = 0; |
682 | while (pos < nbytes) | |
683 | (*val) = ((*val)*0x100) + buf[pos++]; | |
684 | return len; | |
685 | } | |
686 | ||
687 | ||
435317e2 | 688 | inline int |
40165636 RB |
689 | objc_read_unsigned_int (struct objc_typed_stream *stream, |
690 | unsigned int *value) | |
88e17b57 | 691 | { |
40165636 | 692 | unsigned char buf[sizeof (unsigned int) + 1]; |
88e17b57 | 693 | int len; |
8d488306 | 694 | if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) |
88e17b57 BE |
695 | { |
696 | if ((buf[0] & _B_CODE) == _B_SINT) | |
697 | (*value) = (buf[0] & _B_VALUE); | |
698 | ||
699 | else | |
700 | len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value); | |
701 | ||
702 | } | |
703 | return len; | |
704 | } | |
705 | ||
706 | int | |
40165636 RB |
707 | __objc_read_nbyte_ulong (struct objc_typed_stream *stream, |
708 | unsigned int nbytes, unsigned long *val) | |
88e17b57 | 709 | { |
8f8c44cb KG |
710 | int len; |
711 | unsigned int pos = 0; | |
40165636 | 712 | unsigned char buf[sizeof (unsigned long) + 1]; |
88e17b57 BE |
713 | |
714 | if (nbytes > sizeof (long)) | |
40165636 | 715 | objc_error (nil, OBJC_ERR_BAD_DATA, "expected long, got bigger"); |
88e17b57 | 716 | |
8d488306 | 717 | len = (*stream->read) (stream->physical, (char*)buf, nbytes); |
88e17b57 BE |
718 | (*val) = 0; |
719 | while (pos < nbytes) | |
720 | (*val) = ((*val)*0x100) + buf[pos++]; | |
721 | return len; | |
722 | } | |
723 | ||
724 | ||
435317e2 | 725 | inline int |
40165636 RB |
726 | objc_read_unsigned_long (struct objc_typed_stream *stream, |
727 | unsigned long *value) | |
88e17b57 | 728 | { |
40165636 | 729 | unsigned char buf[sizeof (unsigned long) + 1]; |
88e17b57 | 730 | int len; |
8d488306 | 731 | if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) |
88e17b57 BE |
732 | { |
733 | if ((buf[0] & _B_CODE) == _B_SINT) | |
734 | (*value) = (buf[0] & _B_VALUE); | |
735 | ||
736 | else | |
737 | len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value); | |
738 | ||
739 | } | |
740 | return len; | |
741 | } | |
742 | ||
435317e2 | 743 | inline int |
40165636 RB |
744 | objc_read_string (struct objc_typed_stream *stream, |
745 | char **string) | |
88e17b57 | 746 | { |
40165636 | 747 | unsigned char buf[sizeof (unsigned int) + 1]; |
88e17b57 | 748 | int len; |
8d488306 | 749 | if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) |
88e17b57 BE |
750 | { |
751 | unsigned long key = 0; | |
752 | ||
753 | if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ | |
754 | { | |
40165636 | 755 | len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); |
8d488306 | 756 | len = (*stream->read) (stream->physical, (char*)buf, 1); |
88e17b57 BE |
757 | } |
758 | ||
759 | switch (buf[0]&_B_CODE) { | |
760 | case _B_SSTR: | |
761 | { | |
762 | int length = buf[0]&_B_VALUE; | |
40165636 | 763 | (*string) = (char*)objc_malloc (length + 1); |
88e17b57 | 764 | if (key) |
270a1283 | 765 | objc_hash_add (&stream->stream_table, LONG2PTR(key), *string); |
40165636 | 766 | len = (*stream->read) (stream->physical, *string, length); |
88e17b57 BE |
767 | (*string)[length] = '\0'; |
768 | } | |
769 | break; | |
770 | ||
771 | case _B_UCOMM: | |
772 | { | |
773 | char *tmp; | |
40165636 | 774 | len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); |
270a1283 | 775 | tmp = objc_hash_value_for_key (stream->stream_table, LONG2PTR (key)); |
40165636 | 776 | *string = objc_malloc (strlen (tmp) + 1); |
88e17b57 BE |
777 | strcpy (*string, tmp); |
778 | } | |
779 | break; | |
780 | ||
781 | case _B_NSTR: | |
782 | { | |
783 | unsigned int nbytes = buf[0]&_B_VALUE; | |
40165636 | 784 | len = __objc_read_nbyte_uint (stream, nbytes, &nbytes); |
88e17b57 | 785 | if (len) { |
40165636 | 786 | (*string) = (char*)objc_malloc (nbytes + 1); |
88e17b57 | 787 | if (key) |
270a1283 | 788 | objc_hash_add (&stream->stream_table, LONG2PTR(key), *string); |
40165636 | 789 | len = (*stream->read) (stream->physical, *string, nbytes); |
88e17b57 BE |
790 | (*string)[nbytes] = '\0'; |
791 | } | |
792 | } | |
793 | break; | |
794 | ||
795 | default: | |
40165636 RB |
796 | objc_error (nil, OBJC_ERR_BAD_DATA, |
797 | "expected string, got opcode %c\n", (buf[0]&_B_CODE)); | |
88e17b57 BE |
798 | } |
799 | } | |
800 | ||
801 | return len; | |
802 | } | |
803 | ||
804 | ||
805 | int | |
40165636 | 806 | objc_read_object (struct objc_typed_stream *stream, id *object) |
88e17b57 BE |
807 | { |
808 | unsigned char buf[sizeof (unsigned int)]; | |
809 | int len; | |
8d488306 | 810 | if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) |
88e17b57 BE |
811 | { |
812 | SEL read_sel = sel_get_any_uid ("read:"); | |
813 | unsigned long key = 0; | |
814 | ||
815 | if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */ | |
816 | { | |
40165636 | 817 | len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); |
8d488306 | 818 | len = (*stream->read) (stream->physical, (char*)buf, 1); |
88e17b57 BE |
819 | } |
820 | ||
821 | if (buf[0] == (_B_EXT | _BX_OBJECT)) | |
822 | { | |
823 | Class class; | |
824 | ||
825 | /* get class */ | |
826 | len = objc_read_class (stream, &class); | |
827 | ||
828 | /* create instance */ | |
40165636 | 829 | (*object) = class_create_instance (class); |
88e17b57 BE |
830 | |
831 | /* register? */ | |
832 | if (key) | |
270a1283 | 833 | objc_hash_add (&stream->object_table, LONG2PTR(key), *object); |
88e17b57 BE |
834 | |
835 | /* send -read: */ | |
836 | if (__objc_responds_to (*object, read_sel)) | |
40165636 | 837 | (*get_imp (class, read_sel)) (*object, read_sel, stream); |
88e17b57 BE |
838 | |
839 | /* check null-byte */ | |
8d488306 | 840 | len = (*stream->read) (stream->physical, (char*)buf, 1); |
88e17b57 | 841 | if (buf[0] != '\0') |
40165636 RB |
842 | objc_error (nil, OBJC_ERR_BAD_DATA, |
843 | "expected null-byte, got opcode %c", buf[0]); | |
88e17b57 BE |
844 | } |
845 | ||
846 | else if ((buf[0]&_B_CODE) == _B_UCOMM) | |
847 | { | |
848 | if (key) | |
40165636 RB |
849 | objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); |
850 | len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); | |
270a1283 DA |
851 | (*object) = objc_hash_value_for_key (stream->object_table, |
852 | LONG2PTR(key)); | |
88e17b57 BE |
853 | } |
854 | ||
855 | else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */ | |
856 | { | |
40165636 | 857 | struct objc_list *other; |
88e17b57 | 858 | len = objc_read_unsigned_long (stream, &key); |
270a1283 DA |
859 | other |
860 | = (struct objc_list *) objc_hash_value_for_key (stream->object_refs, | |
40165636 | 861 | LONG2PTR(key)); |
270a1283 DA |
862 | objc_hash_add (&stream->object_refs, LONG2PTR(key), |
863 | (void *)list_cons (object, other)); | |
88e17b57 BE |
864 | } |
865 | ||
866 | else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */ | |
867 | { | |
868 | if (key) | |
40165636 RB |
869 | objc_error (nil, OBJC_ERR_BAD_KEY, |
870 | "cannot register root object..."); | |
88e17b57 BE |
871 | len = objc_read_object (stream, object); |
872 | __objc_finish_read_root_object (stream); | |
873 | } | |
874 | ||
875 | else | |
40165636 RB |
876 | objc_error (nil, OBJC_ERR_BAD_DATA, |
877 | "expected object, got opcode %c", buf[0]); | |
88e17b57 BE |
878 | } |
879 | return len; | |
880 | } | |
881 | ||
882 | static int | |
40165636 | 883 | objc_read_class (struct objc_typed_stream *stream, Class *class) |
88e17b57 BE |
884 | { |
885 | unsigned char buf[sizeof (unsigned int)]; | |
886 | int len; | |
8d488306 | 887 | if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) |
88e17b57 BE |
888 | { |
889 | unsigned long key = 0; | |
890 | ||
891 | if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ | |
892 | { | |
40165636 | 893 | len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); |
8d488306 | 894 | len = (*stream->read) (stream->physical, (char*)buf, 1); |
88e17b57 BE |
895 | } |
896 | ||
897 | if (buf[0] == (_B_EXT | _BX_CLASS)) | |
898 | { | |
8d488306 AP |
899 | char temp[1] = ""; |
900 | char *class_name = temp; | |
88e17b57 BE |
901 | unsigned long version; |
902 | ||
903 | /* get class */ | |
904 | len = objc_read_string (stream, &class_name); | |
40165636 RB |
905 | (*class) = objc_get_class (class_name); |
906 | objc_free (class_name); | |
88e17b57 BE |
907 | |
908 | /* register */ | |
909 | if (key) | |
270a1283 | 910 | objc_hash_add (&stream->stream_table, LONG2PTR(key), *class); |
88e17b57 | 911 | |
40165636 | 912 | objc_read_unsigned_long (stream, &version); |
270a1283 | 913 | objc_hash_add (&stream->class_table, |
c24aadf3 | 914 | (*class)->name, (void *) ((size_t) version)); |
88e17b57 BE |
915 | } |
916 | ||
917 | else if ((buf[0]&_B_CODE) == _B_UCOMM) | |
918 | { | |
919 | if (key) | |
40165636 RB |
920 | objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); |
921 | len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); | |
270a1283 DA |
922 | *class = objc_hash_value_for_key (stream->stream_table, |
923 | LONG2PTR(key)); | |
40165636 RB |
924 | if (! *class) |
925 | objc_error (nil, OBJC_ERR_BAD_CLASS, | |
926 | "cannot find class for key %lu", key); | |
88e17b57 BE |
927 | } |
928 | ||
929 | else | |
40165636 RB |
930 | objc_error (nil, OBJC_ERR_BAD_DATA, |
931 | "expected class, got opcode %c", buf[0]); | |
88e17b57 BE |
932 | } |
933 | return len; | |
934 | } | |
935 | ||
936 | int | |
40165636 | 937 | objc_read_selector (struct objc_typed_stream *stream, SEL* selector) |
88e17b57 BE |
938 | { |
939 | unsigned char buf[sizeof (unsigned int)]; | |
940 | int len; | |
8d488306 | 941 | if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) |
88e17b57 BE |
942 | { |
943 | unsigned long key = 0; | |
944 | ||
945 | if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ | |
946 | { | |
40165636 | 947 | len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); |
8d488306 | 948 | len = (*stream->read) (stream->physical, (char*)buf, 1); |
88e17b57 BE |
949 | } |
950 | ||
951 | if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */ | |
952 | { | |
8d488306 AP |
953 | char temp[1] = ""; |
954 | char *selector_name = temp; | |
88e17b57 BE |
955 | |
956 | /* get selector */ | |
957 | len = objc_read_string (stream, &selector_name); | |
958 | /* To handle NULL selectors */ | |
40165636 | 959 | if (0 == strlen (selector_name)) |
88e17b57 BE |
960 | { |
961 | (*selector) = (SEL)0; | |
962 | return 0; | |
963 | } | |
964 | else | |
40165636 RB |
965 | (*selector) = sel_get_any_uid (selector_name); |
966 | objc_free (selector_name); | |
88e17b57 BE |
967 | |
968 | /* register */ | |
969 | if (key) | |
270a1283 DA |
970 | objc_hash_add (&stream->stream_table, |
971 | LONG2PTR(key), (void *) *selector); | |
88e17b57 BE |
972 | } |
973 | ||
974 | else if ((buf[0]&_B_CODE) == _B_UCOMM) | |
975 | { | |
976 | if (key) | |
40165636 RB |
977 | objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); |
978 | len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); | |
270a1283 DA |
979 | (*selector) = objc_hash_value_for_key (stream->stream_table, |
980 | LONG2PTR(key)); | |
88e17b57 BE |
981 | } |
982 | ||
983 | else | |
40165636 RB |
984 | objc_error (nil, OBJC_ERR_BAD_DATA, |
985 | "expected selector, got opcode %c", buf[0]); | |
88e17b57 BE |
986 | } |
987 | return len; | |
988 | } | |
989 | ||
990 | /* | |
991 | ** USER LEVEL FUNCTIONS | |
992 | */ | |
993 | ||
994 | /* | |
995 | ** Write one object, encoded in TYPE and pointed to by DATA to the | |
996 | ** typed stream STREAM. | |
997 | */ | |
998 | ||
999 | int | |
40165636 | 1000 | objc_write_type (TypedStream *stream, const char *type, const void *data) |
88e17b57 | 1001 | { |
40165636 | 1002 | switch (*type) { |
88e17b57 | 1003 | case _C_ID: |
40165636 | 1004 | return objc_write_object (stream, *(id *) data); |
88e17b57 BE |
1005 | break; |
1006 | ||
1007 | case _C_CLASS: | |
40165636 | 1008 | return objc_write_class (stream, *(Class *) data); |
88e17b57 BE |
1009 | break; |
1010 | ||
1011 | case _C_SEL: | |
40165636 | 1012 | return objc_write_selector (stream, *(SEL *) data); |
88e17b57 BE |
1013 | break; |
1014 | ||
1015 | case _C_CHR: | |
40165636 | 1016 | return objc_write_char (stream, *(signed char *) data); |
88e17b57 BE |
1017 | break; |
1018 | ||
1019 | case _C_UCHR: | |
40165636 | 1020 | return objc_write_unsigned_char (stream, *(unsigned char *) data); |
88e17b57 BE |
1021 | break; |
1022 | ||
1023 | case _C_SHT: | |
40165636 | 1024 | return objc_write_short (stream, *(short *) data); |
88e17b57 BE |
1025 | break; |
1026 | ||
1027 | case _C_USHT: | |
40165636 | 1028 | return objc_write_unsigned_short (stream, *(unsigned short *) data); |
88e17b57 BE |
1029 | break; |
1030 | ||
1031 | case _C_INT: | |
40165636 | 1032 | return objc_write_int (stream, *(int *) data); |
88e17b57 BE |
1033 | break; |
1034 | ||
1035 | case _C_UINT: | |
40165636 | 1036 | return objc_write_unsigned_int (stream, *(unsigned int *) data); |
88e17b57 BE |
1037 | break; |
1038 | ||
1039 | case _C_LNG: | |
40165636 | 1040 | return objc_write_long (stream, *(long *) data); |
88e17b57 BE |
1041 | break; |
1042 | ||
1043 | case _C_ULNG: | |
40165636 | 1044 | return objc_write_unsigned_long (stream, *(unsigned long *) data); |
88e17b57 BE |
1045 | break; |
1046 | ||
1047 | case _C_CHARPTR: | |
40165636 | 1048 | return objc_write_string (stream, |
8d488306 | 1049 | *(unsigned char **) data, strlen (*(char **) data)); |
88e17b57 BE |
1050 | break; |
1051 | ||
1052 | case _C_ATOM: | |
8d488306 | 1053 | return objc_write_string_atomic (stream, *(unsigned char **) data, |
40165636 | 1054 | strlen (*(char **) data)); |
88e17b57 BE |
1055 | break; |
1056 | ||
1057 | case _C_ARY_B: | |
1058 | { | |
40165636 RB |
1059 | int len = atoi (type + 1); |
1060 | while (isdigit ((unsigned char) *++type)) | |
88e17b57 BE |
1061 | ; |
1062 | return objc_write_array (stream, type, len, data); | |
1063 | } | |
1064 | break; | |
1065 | ||
1066 | case _C_STRUCT_B: | |
1067 | { | |
1068 | int acc_size = 0; | |
1069 | int align; | |
1070 | while (*type != _C_STRUCT_E && *type++ != '=') | |
1071 | ; /* skip "<name>=" */ | |
1072 | while (*type != _C_STRUCT_E) | |
1073 | { | |
1074 | align = objc_alignof_type (type); /* padd to alignment */ | |
ca59f04b | 1075 | acc_size = ROUND (acc_size, align); |
40165636 | 1076 | objc_write_type (stream, type, ((char *) data) + acc_size); |
88e17b57 BE |
1077 | acc_size += objc_sizeof_type (type); /* add component size */ |
1078 | type = objc_skip_typespec (type); /* skip component */ | |
1079 | } | |
1080 | return 1; | |
1081 | } | |
1082 | ||
1083 | default: | |
1084 | { | |
40165636 RB |
1085 | objc_error (nil, OBJC_ERR_BAD_TYPE, |
1086 | "objc_write_type: cannot parse typespec: %s\n", type); | |
88e17b57 BE |
1087 | return 0; |
1088 | } | |
1089 | } | |
1090 | } | |
1091 | ||
1092 | /* | |
1093 | ** Read one object, encoded in TYPE and pointed to by DATA to the | |
1094 | ** typed stream STREAM. DATA specifies the address of the types to | |
1095 | ** read. Expected type is checked against the type actually present | |
1096 | ** on the stream. | |
1097 | */ | |
1098 | ||
1099 | int | |
40165636 | 1100 | objc_read_type(TypedStream *stream, const char *type, void *data) |
88e17b57 BE |
1101 | { |
1102 | char c; | |
40165636 | 1103 | switch (c = *type) { |
88e17b57 BE |
1104 | case _C_ID: |
1105 | return objc_read_object (stream, (id*)data); | |
1106 | break; | |
1107 | ||
1108 | case _C_CLASS: | |
1109 | return objc_read_class (stream, (Class*)data); | |
1110 | break; | |
1111 | ||
1112 | case _C_SEL: | |
1113 | return objc_read_selector (stream, (SEL*)data); | |
1114 | break; | |
1115 | ||
1116 | case _C_CHR: | |
1117 | return objc_read_char (stream, (char*)data); | |
1118 | break; | |
1119 | ||
1120 | case _C_UCHR: | |
1121 | return objc_read_unsigned_char (stream, (unsigned char*)data); | |
1122 | break; | |
1123 | ||
1124 | case _C_SHT: | |
1125 | return objc_read_short (stream, (short*)data); | |
1126 | break; | |
1127 | ||
1128 | case _C_USHT: | |
1129 | return objc_read_unsigned_short (stream, (unsigned short*)data); | |
1130 | break; | |
1131 | ||
1132 | case _C_INT: | |
1133 | return objc_read_int (stream, (int*)data); | |
1134 | break; | |
1135 | ||
1136 | case _C_UINT: | |
1137 | return objc_read_unsigned_int (stream, (unsigned int*)data); | |
1138 | break; | |
1139 | ||
1140 | case _C_LNG: | |
1141 | return objc_read_long (stream, (long*)data); | |
1142 | break; | |
1143 | ||
1144 | case _C_ULNG: | |
1145 | return objc_read_unsigned_long (stream, (unsigned long*)data); | |
1146 | break; | |
1147 | ||
1148 | case _C_CHARPTR: | |
1149 | case _C_ATOM: | |
1150 | return objc_read_string (stream, (char**)data); | |
1151 | break; | |
1152 | ||
1153 | case _C_ARY_B: | |
1154 | { | |
40165636 RB |
1155 | int len = atoi (type + 1); |
1156 | while (isdigit ((unsigned char) *++type)) | |
88e17b57 BE |
1157 | ; |
1158 | return objc_read_array (stream, type, len, data); | |
1159 | } | |
1160 | break; | |
1161 | ||
1162 | case _C_STRUCT_B: | |
1163 | { | |
1164 | int acc_size = 0; | |
1165 | int align; | |
1166 | while (*type != _C_STRUCT_E && *type++ != '=') | |
1167 | ; /* skip "<name>=" */ | |
1168 | while (*type != _C_STRUCT_E) | |
1169 | { | |
1170 | align = objc_alignof_type (type); /* padd to alignment */ | |
ca59f04b | 1171 | acc_size = ROUND (acc_size, align); |
88e17b57 BE |
1172 | objc_read_type (stream, type, ((char*)data)+acc_size); |
1173 | acc_size += objc_sizeof_type (type); /* add component size */ | |
1174 | type = objc_skip_typespec (type); /* skip component */ | |
1175 | } | |
1176 | return 1; | |
1177 | } | |
1178 | ||
1179 | default: | |
1180 | { | |
40165636 RB |
1181 | objc_error (nil, OBJC_ERR_BAD_TYPE, |
1182 | "objc_read_type: cannot parse typespec: %s\n", type); | |
88e17b57 BE |
1183 | return 0; |
1184 | } | |
1185 | } | |
1186 | } | |
1187 | ||
1188 | /* | |
1189 | ** Write the object specified by the template TYPE to STREAM. Last | |
1190 | ** arguments specify addresses of values to be written. It might | |
1191 | ** seem surprising to specify values by address, but this is extremely | |
1192 | ** convenient for copy-paste with objc_read_types calls. A more | |
1193 | ** down-to-the-earth cause for this passing of addresses is that values | |
1194 | ** of arbitrary size is not well supported in ANSI C for functions with | |
1195 | ** variable number of arguments. | |
1196 | */ | |
1197 | ||
1198 | int | |
40165636 | 1199 | objc_write_types (TypedStream *stream, const char *type, ...) |
88e17b57 BE |
1200 | { |
1201 | va_list args; | |
1202 | const char *c; | |
1203 | int res = 0; | |
1204 | ||
1205 | va_start(args, type); | |
1206 | ||
1207 | for (c = type; *c; c = objc_skip_typespec (c)) | |
1208 | { | |
40165636 | 1209 | switch (*c) { |
88e17b57 BE |
1210 | case _C_ID: |
1211 | res = objc_write_object (stream, *va_arg (args, id*)); | |
1212 | break; | |
1213 | ||
1214 | case _C_CLASS: | |
40165636 | 1215 | res = objc_write_class (stream, *va_arg (args, Class*)); |
88e17b57 BE |
1216 | break; |
1217 | ||
1218 | case _C_SEL: | |
40165636 | 1219 | res = objc_write_selector (stream, *va_arg (args, SEL*)); |
88e17b57 BE |
1220 | break; |
1221 | ||
1222 | case _C_CHR: | |
1223 | res = objc_write_char (stream, *va_arg (args, char*)); | |
1224 | break; | |
1225 | ||
1226 | case _C_UCHR: | |
1227 | res = objc_write_unsigned_char (stream, | |
1228 | *va_arg (args, unsigned char*)); | |
1229 | break; | |
1230 | ||
1231 | case _C_SHT: | |
40165636 | 1232 | res = objc_write_short (stream, *va_arg (args, short*)); |
88e17b57 BE |
1233 | break; |
1234 | ||
1235 | case _C_USHT: | |
1236 | res = objc_write_unsigned_short (stream, | |
40165636 | 1237 | *va_arg (args, unsigned short*)); |
88e17b57 BE |
1238 | break; |
1239 | ||
1240 | case _C_INT: | |
40165636 | 1241 | res = objc_write_int(stream, *va_arg (args, int*)); |
88e17b57 BE |
1242 | break; |
1243 | ||
1244 | case _C_UINT: | |
40165636 | 1245 | res = objc_write_unsigned_int(stream, *va_arg (args, unsigned int*)); |
88e17b57 BE |
1246 | break; |
1247 | ||
1248 | case _C_LNG: | |
40165636 | 1249 | res = objc_write_long(stream, *va_arg (args, long*)); |
88e17b57 BE |
1250 | break; |
1251 | ||
1252 | case _C_ULNG: | |
40165636 | 1253 | res = objc_write_unsigned_long(stream, *va_arg (args, unsigned long*)); |
88e17b57 BE |
1254 | break; |
1255 | ||
1256 | case _C_CHARPTR: | |
1257 | { | |
8d488306 AP |
1258 | unsigned char **str = va_arg (args, unsigned char **); |
1259 | res = objc_write_string (stream, *str, strlen ((char*)*str)); | |
88e17b57 BE |
1260 | } |
1261 | break; | |
1262 | ||
1263 | case _C_ATOM: | |
1264 | { | |
8d488306 AP |
1265 | unsigned char **str = va_arg (args, unsigned char **); |
1266 | res = objc_write_string_atomic (stream, *str, strlen ((char*)*str)); | |
88e17b57 BE |
1267 | } |
1268 | break; | |
1269 | ||
1270 | case _C_ARY_B: | |
1271 | { | |
40165636 RB |
1272 | int len = atoi (c + 1); |
1273 | const char *t = c; | |
1274 | while (isdigit ((unsigned char) *++t)) | |
88e17b57 | 1275 | ; |
40165636 | 1276 | res = objc_write_array (stream, t, len, va_arg (args, void *)); |
88e17b57 BE |
1277 | t = objc_skip_typespec (t); |
1278 | if (*t != _C_ARY_E) | |
40165636 | 1279 | objc_error (nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t); |
88e17b57 BE |
1280 | } |
1281 | break; | |
1282 | ||
1283 | default: | |
40165636 RB |
1284 | objc_error (nil, OBJC_ERR_BAD_TYPE, |
1285 | "objc_write_types: cannot parse typespec: %s\n", type); | |
88e17b57 BE |
1286 | } |
1287 | } | |
1288 | va_end(args); | |
1289 | return res; | |
1290 | } | |
1291 | ||
1292 | ||
1293 | /* | |
1294 | ** Last arguments specify addresses of values to be read. Expected | |
1295 | ** type is checked against the type actually present on the stream. | |
1296 | */ | |
1297 | ||
1298 | int | |
40165636 | 1299 | objc_read_types(TypedStream *stream, const char *type, ...) |
88e17b57 BE |
1300 | { |
1301 | va_list args; | |
1302 | const char *c; | |
1303 | int res = 0; | |
1304 | ||
40165636 | 1305 | va_start (args, type); |
88e17b57 BE |
1306 | |
1307 | for (c = type; *c; c = objc_skip_typespec(c)) | |
1308 | { | |
40165636 | 1309 | switch (*c) { |
88e17b57 | 1310 | case _C_ID: |
40165636 | 1311 | res = objc_read_object(stream, va_arg (args, id*)); |
88e17b57 BE |
1312 | break; |
1313 | ||
1314 | case _C_CLASS: | |
40165636 | 1315 | res = objc_read_class(stream, va_arg (args, Class*)); |
88e17b57 BE |
1316 | break; |
1317 | ||
1318 | case _C_SEL: | |
40165636 | 1319 | res = objc_read_selector(stream, va_arg (args, SEL*)); |
88e17b57 BE |
1320 | break; |
1321 | ||
1322 | case _C_CHR: | |
40165636 | 1323 | res = objc_read_char(stream, va_arg (args, char*)); |
88e17b57 BE |
1324 | break; |
1325 | ||
1326 | case _C_UCHR: | |
40165636 | 1327 | res = objc_read_unsigned_char(stream, va_arg (args, unsigned char*)); |
88e17b57 BE |
1328 | break; |
1329 | ||
1330 | case _C_SHT: | |
40165636 | 1331 | res = objc_read_short(stream, va_arg (args, short*)); |
88e17b57 BE |
1332 | break; |
1333 | ||
1334 | case _C_USHT: | |
40165636 | 1335 | res = objc_read_unsigned_short(stream, va_arg (args, unsigned short*)); |
88e17b57 BE |
1336 | break; |
1337 | ||
1338 | case _C_INT: | |
40165636 | 1339 | res = objc_read_int(stream, va_arg (args, int*)); |
88e17b57 BE |
1340 | break; |
1341 | ||
1342 | case _C_UINT: | |
40165636 | 1343 | res = objc_read_unsigned_int(stream, va_arg (args, unsigned int*)); |
88e17b57 BE |
1344 | break; |
1345 | ||
1346 | case _C_LNG: | |
40165636 | 1347 | res = objc_read_long(stream, va_arg (args, long*)); |
88e17b57 BE |
1348 | break; |
1349 | ||
1350 | case _C_ULNG: | |
40165636 | 1351 | res = objc_read_unsigned_long(stream, va_arg (args, unsigned long*)); |
88e17b57 BE |
1352 | break; |
1353 | ||
1354 | case _C_CHARPTR: | |
1355 | case _C_ATOM: | |
1356 | { | |
40165636 | 1357 | char **str = va_arg (args, char **); |
88e17b57 BE |
1358 | res = objc_read_string (stream, str); |
1359 | } | |
1360 | break; | |
1361 | ||
1362 | case _C_ARY_B: | |
1363 | { | |
40165636 RB |
1364 | int len = atoi (c + 1); |
1365 | const char *t = c; | |
1366 | while (isdigit ((unsigned char) *++t)) | |
88e17b57 | 1367 | ; |
40165636 | 1368 | res = objc_read_array (stream, t, len, va_arg (args, void *)); |
88e17b57 BE |
1369 | t = objc_skip_typespec (t); |
1370 | if (*t != _C_ARY_E) | |
40165636 | 1371 | objc_error (nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t); |
88e17b57 BE |
1372 | } |
1373 | break; | |
1374 | ||
1375 | default: | |
40165636 RB |
1376 | objc_error (nil, OBJC_ERR_BAD_TYPE, |
1377 | "objc_read_types: cannot parse typespec: %s\n", type); | |
88e17b57 BE |
1378 | } |
1379 | } | |
40165636 | 1380 | va_end (args); |
88e17b57 BE |
1381 | return res; |
1382 | } | |
1383 | ||
1384 | /* | |
1385 | ** Write an array of COUNT elements of TYPE from the memory address DATA. | |
1386 | ** This is equivalent of objc_write_type (stream, "[N<type>]", data) | |
1387 | */ | |
1388 | ||
1389 | int | |
40165636 RB |
1390 | objc_write_array (TypedStream *stream, const char *type, |
1391 | int count, const void *data) | |
88e17b57 BE |
1392 | { |
1393 | int off = objc_sizeof_type(type); | |
40165636 | 1394 | const char *where = data; |
88e17b57 BE |
1395 | |
1396 | while (count-- > 0) | |
1397 | { | |
1398 | objc_write_type(stream, type, where); | |
1399 | where += off; | |
1400 | } | |
1401 | return 1; | |
1402 | } | |
1403 | ||
1404 | /* | |
1405 | ** Read an array of COUNT elements of TYPE into the memory address | |
1406 | ** DATA. The memory pointed to by data is supposed to be allocated | |
1407 | ** by the callee. This is equivalent of | |
1408 | ** objc_read_type (stream, "[N<type>]", data) | |
1409 | */ | |
1410 | ||
1411 | int | |
40165636 RB |
1412 | objc_read_array (TypedStream *stream, const char *type, |
1413 | int count, void *data) | |
88e17b57 BE |
1414 | { |
1415 | int off = objc_sizeof_type(type); | |
40165636 | 1416 | char *where = (char*)data; |
88e17b57 BE |
1417 | |
1418 | while (count-- > 0) | |
1419 | { | |
1420 | objc_read_type(stream, type, where); | |
1421 | where += off; | |
1422 | } | |
1423 | return 1; | |
1424 | } | |
1425 | ||
1426 | static int | |
40165636 | 1427 | __objc_fread (FILE *file, char *data, int len) |
88e17b57 BE |
1428 | { |
1429 | return fread(data, len, 1, file); | |
1430 | } | |
1431 | ||
1432 | static int | |
40165636 | 1433 | __objc_fwrite (FILE *file, char *data, int len) |
88e17b57 BE |
1434 | { |
1435 | return fwrite(data, len, 1, file); | |
1436 | } | |
1437 | ||
1438 | static int | |
40165636 | 1439 | __objc_feof (FILE *file) |
88e17b57 BE |
1440 | { |
1441 | return feof(file); | |
1442 | } | |
1443 | ||
1444 | static int | |
40165636 RB |
1445 | __objc_no_write (FILE *file __attribute__ ((__unused__)), |
1446 | const char *data __attribute__ ((__unused__)), | |
1447 | int len __attribute__ ((__unused__))) | |
88e17b57 BE |
1448 | { |
1449 | objc_error (nil, OBJC_ERR_NO_WRITE, "TypedStream not open for writing"); | |
1450 | return 0; | |
1451 | } | |
1452 | ||
1453 | static int | |
40165636 RB |
1454 | __objc_no_read (FILE *file __attribute__ ((__unused__)), |
1455 | const char *data __attribute__ ((__unused__)), | |
1456 | int len __attribute__ ((__unused__))) | |
88e17b57 BE |
1457 | { |
1458 | objc_error (nil, OBJC_ERR_NO_READ, "TypedStream not open for reading"); | |
1459 | return 0; | |
1460 | } | |
1461 | ||
1462 | static int | |
40165636 | 1463 | __objc_read_typed_stream_signature (TypedStream *stream) |
88e17b57 BE |
1464 | { |
1465 | char buffer[80]; | |
1466 | int pos = 0; | |
1467 | do | |
40165636 | 1468 | (*stream->read) (stream->physical, buffer+pos, 1); |
88e17b57 BE |
1469 | while (buffer[pos++] != '\0') |
1470 | ; | |
1471 | sscanf (buffer, "GNU TypedStream %d", &stream->version); | |
1472 | if (stream->version != OBJC_TYPED_STREAM_VERSION) | |
1473 | objc_error (nil, OBJC_ERR_STREAM_VERSION, | |
1474 | "cannot handle TypedStream version %d", stream->version); | |
1475 | return 1; | |
1476 | } | |
1477 | ||
1478 | static int | |
40165636 | 1479 | __objc_write_typed_stream_signature (TypedStream *stream) |
88e17b57 BE |
1480 | { |
1481 | char buffer[80]; | |
1482 | sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION); | |
1483 | stream->version = OBJC_TYPED_STREAM_VERSION; | |
40165636 | 1484 | (*stream->write) (stream->physical, buffer, strlen (buffer) + 1); |
88e17b57 BE |
1485 | return 1; |
1486 | } | |
1487 | ||
40165636 | 1488 | static void __objc_finish_write_root_object(struct objc_typed_stream *stream) |
88e17b57 | 1489 | { |
270a1283 DA |
1490 | objc_hash_delete (stream->object_table); |
1491 | stream->object_table = objc_hash_new (64, | |
1492 | (hash_func_type) objc_hash_ptr, | |
1493 | (compare_func_type) objc_compare_ptrs); | |
88e17b57 BE |
1494 | } |
1495 | ||
40165636 | 1496 | static void __objc_finish_read_root_object(struct objc_typed_stream *stream) |
88e17b57 BE |
1497 | { |
1498 | node_ptr node; | |
1499 | SEL awake_sel = sel_get_any_uid ("awake"); | |
270a1283 DA |
1500 | cache_ptr free_list = objc_hash_new (64, |
1501 | (hash_func_type) objc_hash_ptr, | |
1502 | (compare_func_type) objc_compare_ptrs); | |
88e17b57 BE |
1503 | |
1504 | /* resolve object forward references */ | |
270a1283 DA |
1505 | for (node = objc_hash_next (stream->object_refs, NULL); node; |
1506 | node = objc_hash_next (stream->object_refs, node)) | |
88e17b57 | 1507 | { |
40165636 RB |
1508 | struct objc_list *reflist = node->value; |
1509 | const void *key = node->key; | |
270a1283 | 1510 | id object = objc_hash_value_for_key (stream->object_table, key); |
40165636 | 1511 | while (reflist) |
88e17b57 | 1512 | { |
40165636 | 1513 | *((id*) reflist->head) = object; |
270a1283 DA |
1514 | if (objc_hash_value_for_key (free_list,reflist) == NULL) |
1515 | objc_hash_add (&free_list,reflist,reflist); | |
88e17b57 BE |
1516 | |
1517 | reflist = reflist->tail; | |
1518 | } | |
1519 | } | |
1520 | ||
1521 | /* apply __objc_free to all objects stored in free_list */ | |
270a1283 DA |
1522 | for (node = objc_hash_next (free_list, NULL); node; |
1523 | node = objc_hash_next (free_list, node)) | |
88e17b57 BE |
1524 | objc_free ((void *) node->key); |
1525 | ||
270a1283 | 1526 | objc_hash_delete (free_list); |
88e17b57 BE |
1527 | |
1528 | /* empty object reference table */ | |
270a1283 DA |
1529 | objc_hash_delete (stream->object_refs); |
1530 | stream->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr, | |
1531 | (compare_func_type) objc_compare_ptrs); | |
88e17b57 BE |
1532 | |
1533 | /* call -awake for all objects read */ | |
1534 | if (awake_sel) | |
1535 | { | |
270a1283 DA |
1536 | for (node = objc_hash_next (stream->object_table, NULL); node; |
1537 | node = objc_hash_next (stream->object_table, node)) | |
88e17b57 BE |
1538 | { |
1539 | id object = node->value; | |
1540 | if (__objc_responds_to (object, awake_sel)) | |
40165636 | 1541 | (*objc_msg_lookup (object, awake_sel)) (object, awake_sel); |
88e17b57 BE |
1542 | } |
1543 | } | |
1544 | ||
1545 | /* empty object table */ | |
270a1283 DA |
1546 | objc_hash_delete (stream->object_table); |
1547 | stream->object_table = objc_hash_new(64, | |
1548 | (hash_func_type)objc_hash_ptr, | |
1549 | (compare_func_type)objc_compare_ptrs); | |
88e17b57 BE |
1550 | } |
1551 | ||
1552 | /* | |
1553 | ** Open the stream PHYSICAL in MODE | |
1554 | */ | |
1555 | ||
40165636 RB |
1556 | TypedStream * |
1557 | objc_open_typed_stream (FILE *physical, int mode) | |
88e17b57 | 1558 | { |
40165636 | 1559 | TypedStream *s = (TypedStream *) objc_malloc (sizeof (TypedStream)); |
88e17b57 BE |
1560 | |
1561 | s->mode = mode; | |
1562 | s->physical = physical; | |
270a1283 DA |
1563 | s->stream_table = objc_hash_new (64, |
1564 | (hash_func_type) objc_hash_ptr, | |
1565 | (compare_func_type) objc_compare_ptrs); | |
1566 | s->object_table = objc_hash_new (64, | |
1567 | (hash_func_type) objc_hash_ptr, | |
1568 | (compare_func_type) objc_compare_ptrs); | |
40165636 RB |
1569 | s->eof = (objc_typed_eof_func) __objc_feof; |
1570 | s->flush = (objc_typed_flush_func) fflush; | |
88e17b57 BE |
1571 | s->writing_root_p = 0; |
1572 | if (mode == OBJC_READONLY) | |
1573 | { | |
270a1283 DA |
1574 | s->class_table |
1575 | = objc_hash_new (8, (hash_func_type) objc_hash_string, | |
1576 | (compare_func_type) objc_compare_strings); | |
1577 | s->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr, | |
1578 | (compare_func_type) objc_compare_ptrs); | |
40165636 RB |
1579 | s->read = (objc_typed_read_func) __objc_fread; |
1580 | s->write = (objc_typed_write_func) __objc_no_write; | |
88e17b57 BE |
1581 | __objc_read_typed_stream_signature (s); |
1582 | } | |
1583 | else if (mode == OBJC_WRITEONLY) | |
1584 | { | |
1585 | s->class_table = 0; | |
1586 | s->object_refs = 0; | |
40165636 RB |
1587 | s->read = (objc_typed_read_func) __objc_no_read; |
1588 | s->write = (objc_typed_write_func) __objc_fwrite; | |
88e17b57 BE |
1589 | __objc_write_typed_stream_signature (s); |
1590 | } | |
1591 | else | |
1592 | { | |
1593 | objc_close_typed_stream (s); | |
1594 | return NULL; | |
1595 | } | |
1596 | s->type = OBJC_FILE_STREAM; | |
1597 | return s; | |
1598 | } | |
1599 | ||
1600 | /* | |
1601 | ** Open the file named by FILE_NAME in MODE | |
1602 | */ | |
1603 | ||
1604 | TypedStream* | |
40165636 | 1605 | objc_open_typed_stream_for_file (const char *file_name, int mode) |
88e17b57 | 1606 | { |
40165636 RB |
1607 | FILE *file = NULL; |
1608 | TypedStream *s; | |
88e17b57 BE |
1609 | |
1610 | if (mode == OBJC_READONLY) | |
1611 | file = fopen (file_name, "r"); | |
1612 | else | |
1613 | file = fopen (file_name, "w"); | |
1614 | ||
1615 | if (file) | |
1616 | { | |
1617 | s = objc_open_typed_stream (file, mode); | |
1618 | if (s) | |
1619 | s->type |= OBJC_MANAGED_STREAM; | |
1620 | return s; | |
1621 | } | |
1622 | else | |
1623 | return NULL; | |
1624 | } | |
1625 | ||
1626 | /* | |
1627 | ** Close STREAM freeing the structure it self. If it was opened with | |
1628 | ** objc_open_typed_stream_for_file, the file will also be closed. | |
1629 | */ | |
1630 | ||
1631 | void | |
40165636 | 1632 | objc_close_typed_stream (TypedStream *stream) |
88e17b57 BE |
1633 | { |
1634 | if (stream->mode == OBJC_READONLY) | |
1635 | { | |
1636 | __objc_finish_read_root_object (stream); /* Just in case... */ | |
270a1283 DA |
1637 | objc_hash_delete (stream->class_table); |
1638 | objc_hash_delete (stream->object_refs); | |
88e17b57 BE |
1639 | } |
1640 | ||
270a1283 DA |
1641 | objc_hash_delete (stream->stream_table); |
1642 | objc_hash_delete (stream->object_table); | |
88e17b57 BE |
1643 | |
1644 | if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM)) | |
40165636 | 1645 | fclose ((FILE *)stream->physical); |
88e17b57 BE |
1646 | |
1647 | objc_free(stream); | |
1648 | } | |
1649 | ||
1650 | BOOL | |
40165636 | 1651 | objc_end_of_typed_stream (TypedStream *stream) |
88e17b57 | 1652 | { |
40165636 | 1653 | return (*stream->eof) (stream->physical); |
88e17b57 BE |
1654 | } |
1655 | ||
1656 | void | |
40165636 | 1657 | objc_flush_typed_stream (TypedStream *stream) |
88e17b57 | 1658 | { |
40165636 | 1659 | (*stream->flush) (stream->physical); |
88e17b57 BE |
1660 | } |
1661 | ||
1662 | long | |
40165636 | 1663 | objc_get_stream_class_version (TypedStream *stream, Class class) |
88e17b57 BE |
1664 | { |
1665 | if (stream->class_table) | |
270a1283 DA |
1666 | return PTR2LONG(objc_hash_value_for_key (stream->class_table, |
1667 | class->name)); | |
88e17b57 BE |
1668 | else |
1669 | return class_get_version (class); | |
1670 | } | |
1671 |