OSDN Git Service

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