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