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