OSDN Git Service

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