OSDN Git Service

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