OSDN Git Service

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