OSDN Git Service

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