OSDN Git Service

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