OSDN Git Service

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