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