OSDN Git Service

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