OSDN Git Service

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