Makefile.in, [...]: Replace "GNU CC" with "GCC".
[gcc.git] / libobjc / archive.c
1 /* GNU Objective C Runtime archiving
2 Copyright (C) 1993, 1995, 1996, 1997, 2002 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, 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, 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, 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, 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, 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, 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, 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, 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, buf, len) != 0)
294 return (*stream->write) (stream->physical, 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, buf, len + 1);
327 }
328 else
329 {
330 buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
331 return (*stream->write) (stream->physical, 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, buf, 2);
345 }
346 else
347 {
348 buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
349 return (*stream->write) (stream->physical, 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, &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, &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, (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, "", 0);
470 sel_name = sel_get_name (selector);
471 return objc_write_string (stream, 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, &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, &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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, buf, 1);
886 }
887
888 if (buf[0] == (_B_EXT | _BX_CLASS))
889 {
890 char *class_name;
891 unsigned long version;
892
893 /* get class */
894 len = objc_read_string (stream, &class_name);
895 (*class) = objc_get_class (class_name);
896 objc_free (class_name);
897
898 /* register */
899 if (key)
900 hash_add (&stream->stream_table, LONG2PTR(key), *class);
901
902 objc_read_unsigned_long (stream, &version);
903 hash_add (&stream->class_table, (*class)->name, (void *)version);
904 }
905
906 else if ((buf[0]&_B_CODE) == _B_UCOMM)
907 {
908 if (key)
909 objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
910 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
911 *class = hash_value_for_key (stream->stream_table, LONG2PTR(key));
912 if (! *class)
913 objc_error (nil, OBJC_ERR_BAD_CLASS,
914 "cannot find class for key %lu", key);
915 }
916
917 else
918 objc_error (nil, OBJC_ERR_BAD_DATA,
919 "expected class, got opcode %c", buf[0]);
920 }
921 return len;
922 }
923
924 int
925 objc_read_selector (struct objc_typed_stream *stream, SEL* selector)
926 {
927 unsigned char buf[sizeof (unsigned int)];
928 int len;
929 if ((len = (*stream->read) (stream->physical, buf, 1)))
930 {
931 unsigned long key = 0;
932
933 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
934 {
935 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
936 len = (*stream->read) (stream->physical, buf, 1);
937 }
938
939 if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
940 {
941 char *selector_name;
942
943 /* get selector */
944 len = objc_read_string (stream, &selector_name);
945 /* To handle NULL selectors */
946 if (0 == strlen (selector_name))
947 {
948 (*selector) = (SEL)0;
949 return 0;
950 }
951 else
952 (*selector) = sel_get_any_uid (selector_name);
953 objc_free (selector_name);
954
955 /* register */
956 if (key)
957 hash_add (&stream->stream_table, LONG2PTR(key), (void *) *selector);
958 }
959
960 else if ((buf[0]&_B_CODE) == _B_UCOMM)
961 {
962 if (key)
963 objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
964 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
965 (*selector) = hash_value_for_key (stream->stream_table,
966 LONG2PTR(key));
967 }
968
969 else
970 objc_error (nil, OBJC_ERR_BAD_DATA,
971 "expected selector, got opcode %c", buf[0]);
972 }
973 return len;
974 }
975
976 /*
977 ** USER LEVEL FUNCTIONS
978 */
979
980 /*
981 ** Write one object, encoded in TYPE and pointed to by DATA to the
982 ** typed stream STREAM.
983 */
984
985 int
986 objc_write_type (TypedStream *stream, const char *type, const void *data)
987 {
988 switch (*type) {
989 case _C_ID:
990 return objc_write_object (stream, *(id *) data);
991 break;
992
993 case _C_CLASS:
994 return objc_write_class (stream, *(Class *) data);
995 break;
996
997 case _C_SEL:
998 return objc_write_selector (stream, *(SEL *) data);
999 break;
1000
1001 case _C_CHR:
1002 return objc_write_char (stream, *(signed char *) data);
1003 break;
1004
1005 case _C_UCHR:
1006 return objc_write_unsigned_char (stream, *(unsigned char *) data);
1007 break;
1008
1009 case _C_SHT:
1010 return objc_write_short (stream, *(short *) data);
1011 break;
1012
1013 case _C_USHT:
1014 return objc_write_unsigned_short (stream, *(unsigned short *) data);
1015 break;
1016
1017 case _C_INT:
1018 return objc_write_int (stream, *(int *) data);
1019 break;
1020
1021 case _C_UINT:
1022 return objc_write_unsigned_int (stream, *(unsigned int *) data);
1023 break;
1024
1025 case _C_LNG:
1026 return objc_write_long (stream, *(long *) data);
1027 break;
1028
1029 case _C_ULNG:
1030 return objc_write_unsigned_long (stream, *(unsigned long *) data);
1031 break;
1032
1033 case _C_CHARPTR:
1034 return objc_write_string (stream,
1035 *(char **) data, strlen (*(char **) data));
1036 break;
1037
1038 case _C_ATOM:
1039 return objc_write_string_atomic (stream, *(char **) data,
1040 strlen (*(char **) data));
1041 break;
1042
1043 case _C_ARY_B:
1044 {
1045 int len = atoi (type + 1);
1046 while (isdigit ((unsigned char) *++type))
1047 ;
1048 return objc_write_array (stream, type, len, data);
1049 }
1050 break;
1051
1052 case _C_STRUCT_B:
1053 {
1054 int acc_size = 0;
1055 int align;
1056 while (*type != _C_STRUCT_E && *type++ != '=')
1057 ; /* skip "<name>=" */
1058 while (*type != _C_STRUCT_E)
1059 {
1060 align = objc_alignof_type (type); /* padd to alignment */
1061 acc_size += ROUND (acc_size, align);
1062 objc_write_type (stream, type, ((char *) data) + acc_size);
1063 acc_size += objc_sizeof_type (type); /* add component size */
1064 type = objc_skip_typespec (type); /* skip component */
1065 }
1066 return 1;
1067 }
1068
1069 default:
1070 {
1071 objc_error (nil, OBJC_ERR_BAD_TYPE,
1072 "objc_write_type: cannot parse typespec: %s\n", type);
1073 return 0;
1074 }
1075 }
1076 }
1077
1078 /*
1079 ** Read one object, encoded in TYPE and pointed to by DATA to the
1080 ** typed stream STREAM. DATA specifies the address of the types to
1081 ** read. Expected type is checked against the type actually present
1082 ** on the stream.
1083 */
1084
1085 int
1086 objc_read_type(TypedStream *stream, const char *type, void *data)
1087 {
1088 char c;
1089 switch (c = *type) {
1090 case _C_ID:
1091 return objc_read_object (stream, (id*)data);
1092 break;
1093
1094 case _C_CLASS:
1095 return objc_read_class (stream, (Class*)data);
1096 break;
1097
1098 case _C_SEL:
1099 return objc_read_selector (stream, (SEL*)data);
1100 break;
1101
1102 case _C_CHR:
1103 return objc_read_char (stream, (char*)data);
1104 break;
1105
1106 case _C_UCHR:
1107 return objc_read_unsigned_char (stream, (unsigned char*)data);
1108 break;
1109
1110 case _C_SHT:
1111 return objc_read_short (stream, (short*)data);
1112 break;
1113
1114 case _C_USHT:
1115 return objc_read_unsigned_short (stream, (unsigned short*)data);
1116 break;
1117
1118 case _C_INT:
1119 return objc_read_int (stream, (int*)data);
1120 break;
1121
1122 case _C_UINT:
1123 return objc_read_unsigned_int (stream, (unsigned int*)data);
1124 break;
1125
1126 case _C_LNG:
1127 return objc_read_long (stream, (long*)data);
1128 break;
1129
1130 case _C_ULNG:
1131 return objc_read_unsigned_long (stream, (unsigned long*)data);
1132 break;
1133
1134 case _C_CHARPTR:
1135 case _C_ATOM:
1136 return objc_read_string (stream, (char**)data);
1137 break;
1138
1139 case _C_ARY_B:
1140 {
1141 int len = atoi (type + 1);
1142 while (isdigit ((unsigned char) *++type))
1143 ;
1144 return objc_read_array (stream, type, len, data);
1145 }
1146 break;
1147
1148 case _C_STRUCT_B:
1149 {
1150 int acc_size = 0;
1151 int align;
1152 while (*type != _C_STRUCT_E && *type++ != '=')
1153 ; /* skip "<name>=" */
1154 while (*type != _C_STRUCT_E)
1155 {
1156 align = objc_alignof_type (type); /* padd to alignment */
1157 acc_size += ROUND (acc_size, align);
1158 objc_read_type (stream, type, ((char*)data)+acc_size);
1159 acc_size += objc_sizeof_type (type); /* add component size */
1160 type = objc_skip_typespec (type); /* skip component */
1161 }
1162 return 1;
1163 }
1164
1165 default:
1166 {
1167 objc_error (nil, OBJC_ERR_BAD_TYPE,
1168 "objc_read_type: cannot parse typespec: %s\n", type);
1169 return 0;
1170 }
1171 }
1172 }
1173
1174 /*
1175 ** Write the object specified by the template TYPE to STREAM. Last
1176 ** arguments specify addresses of values to be written. It might
1177 ** seem surprising to specify values by address, but this is extremely
1178 ** convenient for copy-paste with objc_read_types calls. A more
1179 ** down-to-the-earth cause for this passing of addresses is that values
1180 ** of arbitrary size is not well supported in ANSI C for functions with
1181 ** variable number of arguments.
1182 */
1183
1184 int
1185 objc_write_types (TypedStream *stream, const char *type, ...)
1186 {
1187 va_list args;
1188 const char *c;
1189 int res = 0;
1190
1191 va_start(args, type);
1192
1193 for (c = type; *c; c = objc_skip_typespec (c))
1194 {
1195 switch (*c) {
1196 case _C_ID:
1197 res = objc_write_object (stream, *va_arg (args, id*));
1198 break;
1199
1200 case _C_CLASS:
1201 res = objc_write_class (stream, *va_arg (args, Class*));
1202 break;
1203
1204 case _C_SEL:
1205 res = objc_write_selector (stream, *va_arg (args, SEL*));
1206 break;
1207
1208 case _C_CHR:
1209 res = objc_write_char (stream, *va_arg (args, char*));
1210 break;
1211
1212 case _C_UCHR:
1213 res = objc_write_unsigned_char (stream,
1214 *va_arg (args, unsigned char*));
1215 break;
1216
1217 case _C_SHT:
1218 res = objc_write_short (stream, *va_arg (args, short*));
1219 break;
1220
1221 case _C_USHT:
1222 res = objc_write_unsigned_short (stream,
1223 *va_arg (args, unsigned short*));
1224 break;
1225
1226 case _C_INT:
1227 res = objc_write_int(stream, *va_arg (args, int*));
1228 break;
1229
1230 case _C_UINT:
1231 res = objc_write_unsigned_int(stream, *va_arg (args, unsigned int*));
1232 break;
1233
1234 case _C_LNG:
1235 res = objc_write_long(stream, *va_arg (args, long*));
1236 break;
1237
1238 case _C_ULNG:
1239 res = objc_write_unsigned_long(stream, *va_arg (args, unsigned long*));
1240 break;
1241
1242 case _C_CHARPTR:
1243 {
1244 char **str = va_arg (args, char **);
1245 res = objc_write_string (stream, *str, strlen (*str));
1246 }
1247 break;
1248
1249 case _C_ATOM:
1250 {
1251 char **str = va_arg (args, char **);
1252 res = objc_write_string_atomic (stream, *str, strlen (*str));
1253 }
1254 break;
1255
1256 case _C_ARY_B:
1257 {
1258 int len = atoi (c + 1);
1259 const char *t = c;
1260 while (isdigit ((unsigned char) *++t))
1261 ;
1262 res = objc_write_array (stream, t, len, va_arg (args, void *));
1263 t = objc_skip_typespec (t);
1264 if (*t != _C_ARY_E)
1265 objc_error (nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t);
1266 }
1267 break;
1268
1269 default:
1270 objc_error (nil, OBJC_ERR_BAD_TYPE,
1271 "objc_write_types: cannot parse typespec: %s\n", type);
1272 }
1273 }
1274 va_end(args);
1275 return res;
1276 }
1277
1278
1279 /*
1280 ** Last arguments specify addresses of values to be read. Expected
1281 ** type is checked against the type actually present on the stream.
1282 */
1283
1284 int
1285 objc_read_types(TypedStream *stream, const char *type, ...)
1286 {
1287 va_list args;
1288 const char *c;
1289 int res = 0;
1290
1291 va_start (args, type);
1292
1293 for (c = type; *c; c = objc_skip_typespec(c))
1294 {
1295 switch (*c) {
1296 case _C_ID:
1297 res = objc_read_object(stream, va_arg (args, id*));
1298 break;
1299
1300 case _C_CLASS:
1301 res = objc_read_class(stream, va_arg (args, Class*));
1302 break;
1303
1304 case _C_SEL:
1305 res = objc_read_selector(stream, va_arg (args, SEL*));
1306 break;
1307
1308 case _C_CHR:
1309 res = objc_read_char(stream, va_arg (args, char*));
1310 break;
1311
1312 case _C_UCHR:
1313 res = objc_read_unsigned_char(stream, va_arg (args, unsigned char*));
1314 break;
1315
1316 case _C_SHT:
1317 res = objc_read_short(stream, va_arg (args, short*));
1318 break;
1319
1320 case _C_USHT:
1321 res = objc_read_unsigned_short(stream, va_arg (args, unsigned short*));
1322 break;
1323
1324 case _C_INT:
1325 res = objc_read_int(stream, va_arg (args, int*));
1326 break;
1327
1328 case _C_UINT:
1329 res = objc_read_unsigned_int(stream, va_arg (args, unsigned int*));
1330 break;
1331
1332 case _C_LNG:
1333 res = objc_read_long(stream, va_arg (args, long*));
1334 break;
1335
1336 case _C_ULNG:
1337 res = objc_read_unsigned_long(stream, va_arg (args, unsigned long*));
1338 break;
1339
1340 case _C_CHARPTR:
1341 case _C_ATOM:
1342 {
1343 char **str = va_arg (args, char **);
1344 res = objc_read_string (stream, str);
1345 }
1346 break;
1347
1348 case _C_ARY_B:
1349 {
1350 int len = atoi (c + 1);
1351 const char *t = c;
1352 while (isdigit ((unsigned char) *++t))
1353 ;
1354 res = objc_read_array (stream, t, len, va_arg (args, void *));
1355 t = objc_skip_typespec (t);
1356 if (*t != _C_ARY_E)
1357 objc_error (nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t);
1358 }
1359 break;
1360
1361 default:
1362 objc_error (nil, OBJC_ERR_BAD_TYPE,
1363 "objc_read_types: cannot parse typespec: %s\n", type);
1364 }
1365 }
1366 va_end (args);
1367 return res;
1368 }
1369
1370 /*
1371 ** Write an array of COUNT elements of TYPE from the memory address DATA.
1372 ** This is equivalent of objc_write_type (stream, "[N<type>]", data)
1373 */
1374
1375 int
1376 objc_write_array (TypedStream *stream, const char *type,
1377 int count, const void *data)
1378 {
1379 int off = objc_sizeof_type(type);
1380 const char *where = data;
1381
1382 while (count-- > 0)
1383 {
1384 objc_write_type(stream, type, where);
1385 where += off;
1386 }
1387 return 1;
1388 }
1389
1390 /*
1391 ** Read an array of COUNT elements of TYPE into the memory address
1392 ** DATA. The memory pointed to by data is supposed to be allocated
1393 ** by the callee. This is equivalent of
1394 ** objc_read_type (stream, "[N<type>]", data)
1395 */
1396
1397 int
1398 objc_read_array (TypedStream *stream, const char *type,
1399 int count, void *data)
1400 {
1401 int off = objc_sizeof_type(type);
1402 char *where = (char*)data;
1403
1404 while (count-- > 0)
1405 {
1406 objc_read_type(stream, type, where);
1407 where += off;
1408 }
1409 return 1;
1410 }
1411
1412 static int
1413 __objc_fread (FILE *file, char *data, int len)
1414 {
1415 return fread(data, len, 1, file);
1416 }
1417
1418 static int
1419 __objc_fwrite (FILE *file, char *data, int len)
1420 {
1421 return fwrite(data, len, 1, file);
1422 }
1423
1424 static int
1425 __objc_feof (FILE *file)
1426 {
1427 return feof(file);
1428 }
1429
1430 static int
1431 __objc_no_write (FILE *file __attribute__ ((__unused__)),
1432 const char *data __attribute__ ((__unused__)),
1433 int len __attribute__ ((__unused__)))
1434 {
1435 objc_error (nil, OBJC_ERR_NO_WRITE, "TypedStream not open for writing");
1436 return 0;
1437 }
1438
1439 static int
1440 __objc_no_read (FILE *file __attribute__ ((__unused__)),
1441 const char *data __attribute__ ((__unused__)),
1442 int len __attribute__ ((__unused__)))
1443 {
1444 objc_error (nil, OBJC_ERR_NO_READ, "TypedStream not open for reading");
1445 return 0;
1446 }
1447
1448 static int
1449 __objc_read_typed_stream_signature (TypedStream *stream)
1450 {
1451 char buffer[80];
1452 int pos = 0;
1453 do
1454 (*stream->read) (stream->physical, buffer+pos, 1);
1455 while (buffer[pos++] != '\0')
1456 ;
1457 sscanf (buffer, "GNU TypedStream %d", &stream->version);
1458 if (stream->version != OBJC_TYPED_STREAM_VERSION)
1459 objc_error (nil, OBJC_ERR_STREAM_VERSION,
1460 "cannot handle TypedStream version %d", stream->version);
1461 return 1;
1462 }
1463
1464 static int
1465 __objc_write_typed_stream_signature (TypedStream *stream)
1466 {
1467 char buffer[80];
1468 sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
1469 stream->version = OBJC_TYPED_STREAM_VERSION;
1470 (*stream->write) (stream->physical, buffer, strlen (buffer) + 1);
1471 return 1;
1472 }
1473
1474 static void __objc_finish_write_root_object(struct objc_typed_stream *stream)
1475 {
1476 hash_delete (stream->object_table);
1477 stream->object_table = hash_new(64,
1478 (hash_func_type)hash_ptr,
1479 (compare_func_type)compare_ptrs);
1480 }
1481
1482 static void __objc_finish_read_root_object(struct objc_typed_stream *stream)
1483 {
1484 node_ptr node;
1485 SEL awake_sel = sel_get_any_uid ("awake");
1486 cache_ptr free_list = hash_new (64,
1487 (hash_func_type) hash_ptr,
1488 (compare_func_type) compare_ptrs);
1489
1490 /* resolve object forward references */
1491 for (node = hash_next (stream->object_refs, NULL); node;
1492 node = hash_next (stream->object_refs, node))
1493 {
1494 struct objc_list *reflist = node->value;
1495 const void *key = node->key;
1496 id object = hash_value_for_key (stream->object_table, key);
1497 while (reflist)
1498 {
1499 *((id*) reflist->head) = object;
1500 if (hash_value_for_key (free_list,reflist) == NULL)
1501 hash_add (&free_list,reflist,reflist);
1502
1503 reflist = reflist->tail;
1504 }
1505 }
1506
1507 /* apply __objc_free to all objects stored in free_list */
1508 for (node = hash_next (free_list, NULL); node;
1509 node = hash_next (free_list, node))
1510 objc_free ((void *) node->key);
1511
1512 hash_delete (free_list);
1513
1514 /* empty object reference table */
1515 hash_delete (stream->object_refs);
1516 stream->object_refs = hash_new(8, (hash_func_type)hash_ptr,
1517 (compare_func_type)compare_ptrs);
1518
1519 /* call -awake for all objects read */
1520 if (awake_sel)
1521 {
1522 for (node = hash_next (stream->object_table, NULL); node;
1523 node = hash_next (stream->object_table, node))
1524 {
1525 id object = node->value;
1526 if (__objc_responds_to (object, awake_sel))
1527 (*objc_msg_lookup (object, awake_sel)) (object, awake_sel);
1528 }
1529 }
1530
1531 /* empty object table */
1532 hash_delete (stream->object_table);
1533 stream->object_table = hash_new(64,
1534 (hash_func_type)hash_ptr,
1535 (compare_func_type)compare_ptrs);
1536 }
1537
1538 /*
1539 ** Open the stream PHYSICAL in MODE
1540 */
1541
1542 TypedStream *
1543 objc_open_typed_stream (FILE *physical, int mode)
1544 {
1545 TypedStream *s = (TypedStream *) objc_malloc (sizeof (TypedStream));
1546
1547 s->mode = mode;
1548 s->physical = physical;
1549 s->stream_table = hash_new (64,
1550 (hash_func_type) hash_ptr,
1551 (compare_func_type) compare_ptrs);
1552 s->object_table = hash_new (64,
1553 (hash_func_type) hash_ptr,
1554 (compare_func_type) compare_ptrs);
1555 s->eof = (objc_typed_eof_func) __objc_feof;
1556 s->flush = (objc_typed_flush_func) fflush;
1557 s->writing_root_p = 0;
1558 if (mode == OBJC_READONLY)
1559 {
1560 s->class_table = hash_new (8, (hash_func_type) hash_string,
1561 (compare_func_type) compare_strings);
1562 s->object_refs = hash_new (8, (hash_func_type) hash_ptr,
1563 (compare_func_type) compare_ptrs);
1564 s->read = (objc_typed_read_func) __objc_fread;
1565 s->write = (objc_typed_write_func) __objc_no_write;
1566 __objc_read_typed_stream_signature (s);
1567 }
1568 else if (mode == OBJC_WRITEONLY)
1569 {
1570 s->class_table = 0;
1571 s->object_refs = 0;
1572 s->read = (objc_typed_read_func) __objc_no_read;
1573 s->write = (objc_typed_write_func) __objc_fwrite;
1574 __objc_write_typed_stream_signature (s);
1575 }
1576 else
1577 {
1578 objc_close_typed_stream (s);
1579 return NULL;
1580 }
1581 s->type = OBJC_FILE_STREAM;
1582 return s;
1583 }
1584
1585 /*
1586 ** Open the file named by FILE_NAME in MODE
1587 */
1588
1589 TypedStream*
1590 objc_open_typed_stream_for_file (const char *file_name, int mode)
1591 {
1592 FILE *file = NULL;
1593 TypedStream *s;
1594
1595 if (mode == OBJC_READONLY)
1596 file = fopen (file_name, "r");
1597 else
1598 file = fopen (file_name, "w");
1599
1600 if (file)
1601 {
1602 s = objc_open_typed_stream (file, mode);
1603 if (s)
1604 s->type |= OBJC_MANAGED_STREAM;
1605 return s;
1606 }
1607 else
1608 return NULL;
1609 }
1610
1611 /*
1612 ** Close STREAM freeing the structure it self. If it was opened with
1613 ** objc_open_typed_stream_for_file, the file will also be closed.
1614 */
1615
1616 void
1617 objc_close_typed_stream (TypedStream *stream)
1618 {
1619 if (stream->mode == OBJC_READONLY)
1620 {
1621 __objc_finish_read_root_object (stream); /* Just in case... */
1622 hash_delete (stream->class_table);
1623 hash_delete (stream->object_refs);
1624 }
1625
1626 hash_delete (stream->stream_table);
1627 hash_delete (stream->object_table);
1628
1629 if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
1630 fclose ((FILE *)stream->physical);
1631
1632 objc_free(stream);
1633 }
1634
1635 BOOL
1636 objc_end_of_typed_stream (TypedStream *stream)
1637 {
1638 return (*stream->eof) (stream->physical);
1639 }
1640
1641 void
1642 objc_flush_typed_stream (TypedStream *stream)
1643 {
1644 (*stream->flush) (stream->physical);
1645 }
1646
1647 long
1648 objc_get_stream_class_version (TypedStream *stream, Class class)
1649 {
1650 if (stream->class_table)
1651 return PTR2LONG(hash_value_for_key (stream->class_table, class->name));
1652 else
1653 return class_get_version (class);
1654 }
1655