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