source: trunk/third/gcc/libobjc/archive.c @ 21199

Revision 21199, 39.5 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21198, which included commits to RCS files with non-trunk default branches.
Line 
1 /* GNU Objective C Runtime archiving
2   Copyright (C) 1993, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
3   Contributed by Kresten Krab Thorup
4
5This file is part of GCC.
6
7GCC 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
11GCC 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
17GCC; 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#include <stdlib.h>
32
33extern int fflush (FILE *);
34
35#define ROUND(V, A) \
36  ({ typeof (V) __v = (V); typeof (A) __a = (A);  \
37     __a * ((__v + __a - 1)/__a); })
38
39#define PTR2LONG(P) (((char *) (P))-(char *) 0)
40#define LONG2PTR(L) (((char *) 0) + (L))
41
42/* Declare some functions... */
43
44static int
45objc_read_class (struct objc_typed_stream *stream, Class *class);
46
47int objc_sizeof_type (const char *type);
48
49static int
50objc_write_use_common (struct objc_typed_stream *stream, unsigned long key);
51
52static int
53objc_write_register_common (struct objc_typed_stream *stream,
54                            unsigned long key);
55
56static int
57objc_write_class (struct objc_typed_stream *stream,
58                         struct objc_class *class);
59
60const char *objc_skip_type (const char *type);
61
62static void __objc_finish_write_root_object (struct objc_typed_stream *);
63static void __objc_finish_read_root_object (struct objc_typed_stream *);
64
65static __inline__ int
66__objc_code_unsigned_char (unsigned char *buf, unsigned char val)
67{
68  if ((val&_B_VALUE) == val)
69    {
70      buf[0] = val|_B_SINT;
71      return 1;
72    }
73  else
74    {
75      buf[0] = _B_NINT|0x01;
76      buf[1] = val;
77      return 2;
78    }
79}
80
81int
82objc_write_unsigned_char (struct objc_typed_stream *stream,
83                          unsigned char value)
84{
85  unsigned char buf[sizeof (unsigned char) + 1];
86  int len = __objc_code_unsigned_char (buf, value);
87  return (*stream->write) (stream->physical, buf, len);
88}
89
90static __inline__ int
91__objc_code_char (unsigned char *buf, signed char val)
92{
93  if (val >= 0)
94    return __objc_code_unsigned_char (buf, val);
95  else
96    {
97      buf[0] = _B_NINT|_B_SIGN|0x01;
98      buf[1] = -val;
99      return 2;
100    }
101}
102
103int
104objc_write_char (struct objc_typed_stream *stream, signed char value)
105{
106  unsigned char buf[sizeof (char) + 1];
107  int len = __objc_code_char (buf, value);
108  return (*stream->write) (stream->physical, buf, len);
109}
110
111static __inline__ int
112__objc_code_unsigned_short (unsigned char *buf, unsigned short val)
113{
114  if ((val&_B_VALUE) == val)
115    {
116      buf[0] = val|_B_SINT;
117      return 1;
118    }
119  else
120    {
121      int c, b;
122
123      buf[0] = _B_NINT;
124
125      for (c = sizeof (short); c != 0; c -= 1)
126        if (((val >> (8*(c - 1)))%0x100) != 0)
127          break;
128
129      buf[0] |= c;
130
131      for (b = 1; c != 0; c--, b++)
132        {
133          buf[b] = (val >> (8*(c - 1)))%0x100;
134        }
135
136      return b;
137    }
138}
139
140int
141objc_write_unsigned_short (struct objc_typed_stream *stream,
142                           unsigned short value)
143{
144  unsigned char buf[sizeof (unsigned short) + 1];
145  int len = __objc_code_unsigned_short (buf, value);
146  return (*stream->write) (stream->physical, buf, len);
147}
148     
149static __inline__ int
150__objc_code_short (unsigned char *buf, short val)
151{
152  int sign = (val < 0);
153  int size = __objc_code_unsigned_short (buf, sign ? -val : val);
154  if (sign)
155    buf[0] |= _B_SIGN;
156  return size;
157}
158
159int
160objc_write_short (struct objc_typed_stream *stream, short value)
161{
162  unsigned char buf[sizeof (short) + 1];
163  int len = __objc_code_short (buf, value);
164  return (*stream->write) (stream->physical, buf, len);
165}
166     
167
168static __inline__ int
169__objc_code_unsigned_int (unsigned char *buf, unsigned int val)
170{
171  if ((val&_B_VALUE) == val)
172    {
173      buf[0] = val|_B_SINT;
174      return 1;
175    }
176  else
177    {
178      int c, b;
179
180      buf[0] = _B_NINT;
181
182      for (c = sizeof (int); c != 0; c -= 1)
183        if (((val >> (8*(c - 1)))%0x100) != 0)
184          break;
185
186      buf[0] |= c;
187
188      for (b = 1; c != 0; c--, b++)
189        {
190          buf[b] = (val >> (8*(c-1)))%0x100;
191        }
192
193      return b;
194    }
195}
196
197int
198objc_write_unsigned_int (struct objc_typed_stream *stream, unsigned int value)
199{
200  unsigned char buf[sizeof (unsigned int) + 1];
201  int len = __objc_code_unsigned_int (buf, value);
202  return (*stream->write) (stream->physical, buf, len);
203}
204
205static __inline__ int
206__objc_code_int (unsigned char *buf, int val)
207{
208  int sign = (val < 0);
209  int size = __objc_code_unsigned_int (buf, sign ? -val : val);
210  if (sign)
211    buf[0] |= _B_SIGN;
212  return size;
213}
214
215int
216objc_write_int (struct objc_typed_stream *stream, int value)
217{
218  unsigned char buf[sizeof (int) + 1];
219  int len = __objc_code_int (buf, value);
220  return (*stream->write) (stream->physical, buf, len);
221}
222
223static __inline__ int
224__objc_code_unsigned_long (unsigned char *buf, unsigned long val)
225{
226  if ((val&_B_VALUE) == val)
227    {
228      buf[0] = val|_B_SINT;
229      return 1;
230    }
231  else
232    {
233      int c, b;
234
235      buf[0] = _B_NINT;
236
237      for (c = sizeof (long); c != 0; c -= 1)
238        if (((val >> (8*(c - 1)))%0x100) != 0)
239          break;
240
241      buf[0] |= c;
242
243      for (b = 1; c != 0; c--, b++)
244        {
245          buf[b] = (val >> (8*(c - 1)))%0x100;
246        }
247
248      return b;
249    }
250}
251
252int
253objc_write_unsigned_long (struct objc_typed_stream *stream,
254                          unsigned long value)
255{
256  unsigned char buf[sizeof (unsigned long) + 1];
257  int len = __objc_code_unsigned_long (buf, value);
258  return (*stream->write) (stream->physical, buf, len);
259}
260
261static __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
271int
272objc_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
280int
281objc_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
299int
300objc_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
316static int
317objc_write_register_common (struct objc_typed_stream *stream,
318                            unsigned long key)
319{
320  unsigned char buf[sizeof (unsigned long)+2];
321  int len = __objc_code_unsigned_long (buf + 1, key);
322  if (len == 1)
323    {
324      buf[0] = _B_RCOMM|0x01;
325      buf[1] &= _B_VALUE;
326      return (*stream->write) (stream->physical, buf, len + 1);
327    }
328  else
329    {
330      buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
331      return (*stream->write) (stream->physical, buf + 1, len);
332    }
333}
334
335static int
336objc_write_use_common (struct objc_typed_stream *stream, unsigned long key)
337{
338  unsigned char buf[sizeof (unsigned long)+2];
339  int len = __objc_code_unsigned_long (buf + 1, key);
340  if (len == 1)
341    {
342      buf[0] = _B_UCOMM|0x01;
343      buf[1] &= _B_VALUE;
344      return (*stream->write) (stream->physical, buf, 2);
345    }
346  else
347    {
348      buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
349      return (*stream->write) (stream->physical, buf + 1, len);
350    }
351}
352
353static __inline__ int
354__objc_write_extension (struct objc_typed_stream *stream, unsigned char code)
355{
356  if (code <= _B_VALUE)
357    {
358      unsigned char buf = code|_B_EXT;
359      return (*stream->write) (stream->physical, &buf, 1);
360    }
361  else
362    {
363      objc_error (nil, OBJC_ERR_BAD_OPCODE,
364                  "__objc_write_extension: bad opcode %c\n", code);
365      return -1;
366    }
367}
368
369__inline__ int
370__objc_write_object (struct objc_typed_stream *stream, id object)
371{
372  unsigned char buf = '\0';
373  SEL write_sel = sel_get_any_uid ("write:");
374  if (object)
375    {
376      __objc_write_extension (stream, _BX_OBJECT);
377      objc_write_class (stream, object->class_pointer);
378      (*objc_msg_lookup (object, write_sel)) (object, write_sel, stream);
379      return (*stream->write) (stream->physical, &buf, 1);
380    }
381  else
382    return objc_write_use_common (stream, 0);
383}
384
385int
386objc_write_object_reference (struct objc_typed_stream *stream, id object)
387{
388  unsigned long key;
389  if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object))))
390    return objc_write_use_common (stream, key);
391
392  __objc_write_extension (stream, _BX_OBJREF);
393  return objc_write_unsigned_long (stream, PTR2LONG (object));
394}
395
396int
397objc_write_root_object (struct objc_typed_stream *stream, id object)
398{
399  int len = 0;
400  if (stream->writing_root_p)
401    objc_error (nil, OBJC_ERR_RECURSE_ROOT,
402                "objc_write_root_object called recursively");
403  else
404    {
405      stream->writing_root_p = 1;
406      __objc_write_extension (stream, _BX_OBJROOT);
407      if ((len = objc_write_object (stream, object)))
408        __objc_finish_write_root_object (stream);
409      stream->writing_root_p = 0;
410    }
411  return len;
412}
413
414int
415objc_write_object (struct objc_typed_stream *stream, id object)
416{
417  unsigned long key;
418  if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object))))
419    return objc_write_use_common (stream, key);
420
421  else if (object == nil)
422    return objc_write_use_common (stream, 0);
423
424  else
425    {
426      int length;
427      hash_add (&stream->object_table, LONG2PTR(key=PTR2LONG(object)), object);
428      if ((length = objc_write_register_common (stream, key)))
429        return __objc_write_object (stream, object);
430      return length;
431    }
432}
433
434__inline__ int
435__objc_write_class (struct objc_typed_stream *stream, struct objc_class *class)
436{
437  __objc_write_extension (stream, _BX_CLASS);
438  objc_write_string_atomic (stream, (char *) class->name,
439                           strlen ((char *) class->name));
440  return objc_write_unsigned_long (stream, class->version);
441}
442
443
444static int
445objc_write_class (struct objc_typed_stream *stream,
446                         struct objc_class *class)
447{
448  unsigned long key;
449  if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, class))))
450    return objc_write_use_common (stream, key);
451  else
452    {
453      int length;
454      hash_add (&stream->stream_table, LONG2PTR(key = PTR2LONG(class)), class);
455      if ((length = objc_write_register_common (stream, key)))
456        return __objc_write_class (stream, class);
457      return length;
458    }
459}
460
461
462__inline__ int
463__objc_write_selector (struct objc_typed_stream *stream, SEL selector)
464{
465  const char *sel_name;
466  __objc_write_extension (stream, _BX_SEL);
467  /* to handle NULL selectors */
468  if ((SEL)0 == selector)
469    return objc_write_string (stream, "", 0);
470  sel_name = sel_get_name (selector);
471  return objc_write_string (stream, sel_name, strlen ((char*)sel_name));
472}
473
474int
475objc_write_selector (struct objc_typed_stream *stream, SEL selector)
476{
477  const char *sel_name;
478  unsigned long key;
479
480  /* to handle NULL selectors */
481  if ((SEL)0 == selector)
482    return __objc_write_selector (stream, selector);
483
484  sel_name = sel_get_name (selector);
485  if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, sel_name))))
486    return objc_write_use_common (stream, key);
487  else
488    {
489      int length;
490      hash_add (&stream->stream_table,
491                LONG2PTR(key = PTR2LONG(sel_name)), (char *) sel_name);
492      if ((length = objc_write_register_common (stream, key)))
493        return __objc_write_selector (stream, selector);
494      return length;
495    }
496}
497
498
499
500/*
501** Read operations
502*/
503
504__inline__ int
505objc_read_char (struct objc_typed_stream *stream, char *val)
506{
507  unsigned char buf;
508  int len;
509  len = (*stream->read) (stream->physical, &buf, 1);
510  if (len != 0)
511    {
512      if ((buf & _B_CODE) == _B_SINT)
513        (*val) = (buf & _B_VALUE);
514
515      else if ((buf & _B_NUMBER) == 1)
516        {
517          len = (*stream->read) (stream->physical, val, 1);
518          if (buf&_B_SIGN)
519            (*val) = -1 * (*val);
520        }
521
522      else
523        objc_error (nil, OBJC_ERR_BAD_DATA,
524                    "expected 8bit signed int, got %dbit int",
525                    (int) (buf&_B_NUMBER)*8);
526    }
527  return len;
528}
529
530
531__inline__ int
532objc_read_unsigned_char (struct objc_typed_stream *stream, unsigned char *val)
533{
534  unsigned char buf;
535  int len;
536  if ((len = (*stream->read) (stream->physical, &buf, 1)))
537    {
538      if ((buf & _B_CODE) == _B_SINT)
539        (*val) = (buf & _B_VALUE);
540
541      else if ((buf & _B_NUMBER) == 1)
542        len = (*stream->read) (stream->physical, val, 1);
543
544      else
545        objc_error (nil, OBJC_ERR_BAD_DATA,
546                    "expected 8bit unsigned int, got %dbit int",
547                    (int) (buf&_B_NUMBER)*8);
548    }
549  return len;
550}
551
552__inline__ int
553objc_read_short (struct objc_typed_stream *stream, short *value)
554{
555  unsigned char buf[sizeof (short) + 1];
556  int len;
557  if ((len = (*stream->read) (stream->physical, buf, 1)))
558    {
559      if ((buf[0] & _B_CODE) == _B_SINT)
560        (*value) = (buf[0] & _B_VALUE);
561
562      else
563        {
564          int pos = 1;
565          int nbytes = buf[0] & _B_NUMBER;
566          if (nbytes > (int) sizeof (short))
567            objc_error (nil, OBJC_ERR_BAD_DATA,
568                        "expected short, got bigger (%dbits)", nbytes*8);
569          len = (*stream->read) (stream->physical, buf + 1, nbytes);
570          (*value) = 0;
571          while (pos <= nbytes)
572            (*value) = ((*value)*0x100) + buf[pos++];
573          if (buf[0] & _B_SIGN)
574            (*value) = -(*value);
575        }
576    }
577  return len;
578}
579
580__inline__ int
581objc_read_unsigned_short (struct objc_typed_stream *stream,
582                          unsigned short *value)
583{
584  unsigned char buf[sizeof (unsigned short) + 1];
585  int len;
586  if ((len = (*stream->read) (stream->physical, buf, 1)))
587    {
588      if ((buf[0] & _B_CODE) == _B_SINT)
589        (*value) = (buf[0] & _B_VALUE);
590
591      else
592        {
593          int pos = 1;
594          int nbytes = buf[0] & _B_NUMBER;
595          if (nbytes > (int) sizeof (short))
596            objc_error (nil, OBJC_ERR_BAD_DATA,
597                        "expected short, got int or bigger");
598          len = (*stream->read) (stream->physical, buf + 1, nbytes);
599          (*value) = 0;
600          while (pos <= nbytes)
601            (*value) = ((*value)*0x100) + buf[pos++];
602        }
603    }
604  return len;
605}
606
607
608__inline__ int
609objc_read_int (struct objc_typed_stream *stream, int *value)
610{
611  unsigned char buf[sizeof (int) + 1];
612  int len;
613  if ((len = (*stream->read) (stream->physical, buf, 1)))
614    {
615      if ((buf[0] & _B_CODE) == _B_SINT)
616        (*value) = (buf[0] & _B_VALUE);
617
618      else
619        {
620          int pos = 1;
621          int nbytes = buf[0] & _B_NUMBER;
622          if (nbytes > (int) sizeof (int))
623            objc_error (nil, OBJC_ERR_BAD_DATA, "expected int, got bigger");
624          len = (*stream->read) (stream->physical, buf + 1, nbytes);
625          (*value) = 0;
626          while (pos <= nbytes)
627            (*value) = ((*value)*0x100) + buf[pos++];
628          if (buf[0] & _B_SIGN)
629            (*value) = -(*value);
630        }
631    }
632  return len;
633}
634
635__inline__ int
636objc_read_long (struct objc_typed_stream *stream, long *value)
637{
638  unsigned char buf[sizeof (long) + 1];
639  int len;
640  if ((len = (*stream->read) (stream->physical, buf, 1)))
641    {
642      if ((buf[0] & _B_CODE) == _B_SINT)
643        (*value) = (buf[0] & _B_VALUE);
644
645      else
646        {
647          int pos = 1;
648          int nbytes = buf[0] & _B_NUMBER;
649          if (nbytes > (int) sizeof (long))
650            objc_error (nil, OBJC_ERR_BAD_DATA, "expected long, got bigger");
651          len = (*stream->read) (stream->physical, buf + 1, nbytes);
652          (*value) = 0;
653          while (pos <= nbytes)
654            (*value) = ((*value)*0x100) + buf[pos++];
655          if (buf[0] & _B_SIGN)
656            (*value) = -(*value);
657        }
658    }
659  return len;
660}
661
662__inline__ int
663__objc_read_nbyte_uint (struct objc_typed_stream *stream,
664                        unsigned int nbytes, unsigned int *val)
665{
666  int len;
667  unsigned int pos = 0;
668  unsigned char buf[sizeof (unsigned int) + 1];
669
670  if (nbytes > sizeof (int))
671    objc_error (nil, OBJC_ERR_BAD_DATA, "expected int, got bigger");
672
673  len = (*stream->read) (stream->physical, buf, nbytes);
674  (*val) = 0;
675  while (pos < nbytes)
676    (*val) = ((*val)*0x100) + buf[pos++];
677  return len;
678}
679 
680
681__inline__ int
682objc_read_unsigned_int (struct objc_typed_stream *stream,
683                        unsigned int *value)
684{
685  unsigned char buf[sizeof (unsigned int) + 1];
686  int len;
687  if ((len = (*stream->read) (stream->physical, buf, 1)))
688    {
689      if ((buf[0] & _B_CODE) == _B_SINT)
690        (*value) = (buf[0] & _B_VALUE);
691
692      else
693        len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value);
694
695    }
696  return len;
697}
698
699int
700__objc_read_nbyte_ulong (struct objc_typed_stream *stream,
701                       unsigned int nbytes, unsigned long *val)
702{
703  int len;
704  unsigned int pos = 0;
705  unsigned char buf[sizeof (unsigned long) + 1];
706
707  if (nbytes > sizeof (long))
708    objc_error (nil, OBJC_ERR_BAD_DATA, "expected long, got bigger");
709
710  len = (*stream->read) (stream->physical, buf, nbytes);
711  (*val) = 0;
712  while (pos < nbytes)
713    (*val) = ((*val)*0x100) + buf[pos++];
714  return len;
715}
716 
717
718__inline__ int
719objc_read_unsigned_long (struct objc_typed_stream *stream,
720                         unsigned long *value)
721{
722  unsigned char buf[sizeof (unsigned long) + 1];
723  int len;
724  if ((len = (*stream->read) (stream->physical, buf, 1)))
725    {
726      if ((buf[0] & _B_CODE) == _B_SINT)
727        (*value) = (buf[0] & _B_VALUE);
728
729      else
730        len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value);
731
732    }
733  return len;
734}
735
736__inline__ int
737objc_read_string (struct objc_typed_stream *stream,
738                  char **string)
739{
740  unsigned char buf[sizeof (unsigned int) + 1];
741  int len;
742  if ((len = (*stream->read) (stream->physical, buf, 1)))
743    {
744      unsigned long key = 0;
745
746      if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
747        {
748          len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
749          len = (*stream->read) (stream->physical, buf, 1);
750        }
751
752      switch (buf[0]&_B_CODE) {
753      case _B_SSTR:
754        {
755          int length = buf[0]&_B_VALUE;
756          (*string) = (char*)objc_malloc (length + 1);
757          if (key)
758            hash_add (&stream->stream_table, LONG2PTR(key), *string);
759          len = (*stream->read) (stream->physical, *string, length);
760          (*string)[length] = '\0';
761        }
762        break;
763
764      case _B_UCOMM:
765        {
766          char *tmp;
767          len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
768          tmp = hash_value_for_key (stream->stream_table, LONG2PTR (key));
769          *string = objc_malloc (strlen (tmp) + 1);
770          strcpy (*string, tmp);
771        }
772        break;
773
774      case _B_NSTR:
775        {
776          unsigned int nbytes = buf[0]&_B_VALUE;
777          len = __objc_read_nbyte_uint (stream, nbytes, &nbytes);
778          if (len) {
779            (*string) = (char*)objc_malloc (nbytes + 1);
780            if (key)
781              hash_add (&stream->stream_table, LONG2PTR(key), *string);
782            len = (*stream->read) (stream->physical, *string, nbytes);
783            (*string)[nbytes] = '\0';
784          }
785        }
786        break;
787       
788      default:
789        objc_error (nil, OBJC_ERR_BAD_DATA,
790                    "expected string, got opcode %c\n", (buf[0]&_B_CODE));
791      }
792    }
793
794  return len;
795}
796
797
798int
799objc_read_object (struct objc_typed_stream *stream, id *object)
800{
801  unsigned char buf[sizeof (unsigned int)];
802  int len;
803  if ((len = (*stream->read) (stream->physical, buf, 1)))
804    {
805      SEL read_sel = sel_get_any_uid ("read:");
806      unsigned long key = 0;
807
808      if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */
809        {
810          len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
811          len = (*stream->read) (stream->physical, buf, 1);
812        }
813
814      if (buf[0] == (_B_EXT | _BX_OBJECT))
815        {
816          Class class;
817
818          /* get class */
819          len = objc_read_class (stream, &class);
820
821          /* create instance */
822          (*object) = class_create_instance (class);
823
824          /* register? */
825          if (key)
826            hash_add (&stream->object_table, LONG2PTR(key), *object);
827
828          /* send -read: */
829          if (__objc_responds_to (*object, read_sel))
830            (*get_imp (class, read_sel)) (*object, read_sel, stream);
831
832          /* check null-byte */
833          len = (*stream->read) (stream->physical, buf, 1);
834          if (buf[0] != '\0')
835            objc_error (nil, OBJC_ERR_BAD_DATA,
836                        "expected null-byte, got opcode %c", buf[0]);
837        }
838
839      else if ((buf[0]&_B_CODE) == _B_UCOMM)
840        {
841          if (key)
842            objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
843          len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
844          (*object) = hash_value_for_key (stream->object_table, LONG2PTR(key));
845        }
846
847      else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */
848        {
849          struct objc_list *other;
850          len = objc_read_unsigned_long (stream, &key);
851          other = (struct objc_list *) hash_value_for_key (stream->object_refs,
852                                                           LONG2PTR(key));
853          hash_add (&stream->object_refs, LONG2PTR(key),
854                    (void *)list_cons (object, other));
855        }
856
857      else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */
858        {
859          if (key)
860            objc_error (nil, OBJC_ERR_BAD_KEY,
861                        "cannot register root object...");
862          len = objc_read_object (stream, object);
863          __objc_finish_read_root_object (stream);
864        }
865
866      else
867        objc_error (nil, OBJC_ERR_BAD_DATA,
868                    "expected object, got opcode %c", buf[0]);
869    }
870  return len;
871}
872
873static int
874objc_read_class (struct objc_typed_stream *stream, Class *class)
875{
876  unsigned char buf[sizeof (unsigned int)];
877  int len;
878  if ((len = (*stream->read) (stream->physical, buf, 1)))
879    {
880      unsigned long key = 0;
881
882      if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
883        {
884          len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
885          len = (*stream->read) (stream->physical, buf, 1);
886        }
887
888      if (buf[0] == (_B_EXT | _BX_CLASS))
889        {
890          char *class_name;
891          unsigned long version;
892
893          /* get class */
894          len = objc_read_string (stream, &class_name);
895          (*class) = objc_get_class (class_name);
896          objc_free (class_name);
897
898          /* register */
899          if (key)
900            hash_add (&stream->stream_table, LONG2PTR(key), *class);
901
902          objc_read_unsigned_long (stream, &version);
903          hash_add (&stream->class_table, (*class)->name, (void *)version);
904        }
905
906      else if ((buf[0]&_B_CODE) == _B_UCOMM)
907        {
908          if (key)
909            objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
910          len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
911          *class = hash_value_for_key (stream->stream_table, LONG2PTR(key));
912          if (! *class)
913            objc_error (nil, OBJC_ERR_BAD_CLASS,
914                        "cannot find class for key %lu", key);
915        }
916
917      else
918        objc_error (nil, OBJC_ERR_BAD_DATA,
919                    "expected class, got opcode %c", buf[0]);
920    }
921  return len;
922}
923
924int
925objc_read_selector (struct objc_typed_stream *stream, SEL* selector)
926{
927  unsigned char buf[sizeof (unsigned int)];
928  int len;
929  if ((len = (*stream->read) (stream->physical, buf, 1)))
930    {
931      unsigned long key = 0;
932
933      if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
934        {
935          len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
936          len = (*stream->read) (stream->physical, buf, 1);
937        }
938
939      if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
940        {
941          char *selector_name;
942
943          /* get selector */
944          len = objc_read_string (stream, &selector_name);
945          /* To handle NULL selectors */
946          if (0 == strlen (selector_name))
947            {
948              (*selector) = (SEL)0;
949              return 0;
950            }
951          else
952            (*selector) = sel_get_any_uid (selector_name);
953          objc_free (selector_name);
954
955          /* register */
956          if (key)
957            hash_add (&stream->stream_table, LONG2PTR(key), (void *) *selector);
958        }
959
960      else if ((buf[0]&_B_CODE) == _B_UCOMM)
961        {
962          if (key)
963            objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
964          len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
965          (*selector) = hash_value_for_key (stream->stream_table,
966                                            LONG2PTR(key));
967        }
968
969      else
970        objc_error (nil, OBJC_ERR_BAD_DATA,
971                    "expected selector, got opcode %c", buf[0]);
972    }
973  return len;
974}
975
976/*
977** USER LEVEL FUNCTIONS
978*/
979
980/*
981** Write one object, encoded in TYPE and pointed to by DATA to the
982** typed stream STREAM. 
983*/
984
985int
986objc_write_type (TypedStream *stream, const char *type, const void *data)
987{
988  switch (*type) {
989  case _C_ID:
990    return objc_write_object (stream, *(id *) data);
991    break;
992
993  case _C_CLASS:
994    return objc_write_class (stream, *(Class *) data);
995    break;
996
997  case _C_SEL:
998    return objc_write_selector (stream, *(SEL *) data);
999    break;
1000
1001  case _C_CHR:
1002    return objc_write_char (stream, *(signed char *) data);
1003    break;
1004   
1005  case _C_UCHR:
1006    return objc_write_unsigned_char (stream, *(unsigned char *) data);
1007    break;
1008
1009  case _C_SHT:
1010    return objc_write_short (stream, *(short *) data);
1011    break;
1012
1013  case _C_USHT:
1014    return objc_write_unsigned_short (stream, *(unsigned short *) data);
1015    break;
1016
1017  case _C_INT:
1018    return objc_write_int (stream, *(int *) data);
1019    break;
1020
1021  case _C_UINT:
1022    return objc_write_unsigned_int (stream, *(unsigned int *) data);
1023    break;
1024
1025  case _C_LNG:
1026    return objc_write_long (stream, *(long *) data);
1027    break;
1028
1029  case _C_ULNG:
1030    return objc_write_unsigned_long (stream, *(unsigned long *) data);
1031    break;
1032
1033  case _C_CHARPTR:
1034    return objc_write_string (stream,
1035                              *(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 ((unsigned char) *++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 ((unsigned char) *++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 ((unsigned char) *++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 ((unsigned char) *++t))
1353            ;
1354          res = objc_read_array (stream, t, len, va_arg (args, void *));
1355          t = objc_skip_typespec (t);
1356          if (*t != _C_ARY_E)
1357            objc_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 __attribute__ ((__unused__)),
1432                 const char *data __attribute__ ((__unused__)),
1433                 int len __attribute__ ((__unused__)))
1434{
1435  objc_error (nil, OBJC_ERR_NO_WRITE, "TypedStream not open for writing");
1436  return 0;
1437}
1438
1439static int
1440__objc_no_read (FILE *file __attribute__ ((__unused__)),
1441                const char *data __attribute__ ((__unused__)),
1442                int len __attribute__ ((__unused__)))
1443{
1444  objc_error (nil, OBJC_ERR_NO_READ, "TypedStream not open for reading");
1445  return 0;
1446}
1447
1448static int
1449__objc_read_typed_stream_signature (TypedStream *stream)
1450{
1451  char buffer[80];
1452  int pos = 0;
1453  do
1454    (*stream->read) (stream->physical, buffer+pos, 1);
1455  while (buffer[pos++] != '\0')
1456    ;
1457  sscanf (buffer, "GNU TypedStream %d", &stream->version);
1458  if (stream->version != OBJC_TYPED_STREAM_VERSION)
1459    objc_error (nil, OBJC_ERR_STREAM_VERSION,
1460                "cannot handle TypedStream version %d", stream->version);
1461  return 1;
1462}
1463
1464static int
1465__objc_write_typed_stream_signature (TypedStream *stream)
1466{
1467  char buffer[80];
1468  sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
1469  stream->version = OBJC_TYPED_STREAM_VERSION;
1470  (*stream->write) (stream->physical, buffer, strlen (buffer) + 1);
1471  return 1;
1472}
1473
1474static void __objc_finish_write_root_object(struct objc_typed_stream *stream)
1475{
1476  hash_delete (stream->object_table);
1477  stream->object_table = hash_new(64,
1478                                  (hash_func_type)hash_ptr,
1479                                  (compare_func_type)compare_ptrs);
1480}
1481
1482static void __objc_finish_read_root_object(struct objc_typed_stream *stream)
1483{
1484  node_ptr node;
1485  SEL awake_sel = sel_get_any_uid ("awake");
1486  cache_ptr free_list = hash_new (64,
1487                                  (hash_func_type) hash_ptr,
1488                                  (compare_func_type) compare_ptrs);
1489
1490  /* resolve object forward references */
1491  for (node = hash_next (stream->object_refs, NULL); node;
1492       node = hash_next (stream->object_refs, node))
1493    {
1494      struct objc_list *reflist = node->value;
1495      const void *key = node->key;
1496      id object = hash_value_for_key (stream->object_table, key);
1497      while (reflist)
1498        {
1499          *((id*) reflist->head) = object;
1500          if (hash_value_for_key (free_list,reflist) == NULL)
1501            hash_add (&free_list,reflist,reflist);
1502
1503          reflist = reflist->tail;
1504        }
1505    }
1506   
1507  /* apply __objc_free to all objects stored in free_list */
1508  for (node = hash_next (free_list, NULL); node;
1509       node = hash_next (free_list, node))
1510    objc_free ((void *) node->key);
1511
1512  hash_delete (free_list);
1513
1514  /* empty object reference table */
1515  hash_delete (stream->object_refs);
1516  stream->object_refs = hash_new(8, (hash_func_type)hash_ptr,
1517                                 (compare_func_type)compare_ptrs);
1518 
1519  /* call -awake for all objects read  */
1520  if (awake_sel)
1521    {
1522      for (node = hash_next (stream->object_table, NULL); node;
1523           node = hash_next (stream->object_table, node))
1524        {
1525          id object = node->value;
1526          if (__objc_responds_to (object, awake_sel))
1527            (*objc_msg_lookup (object, awake_sel)) (object, awake_sel);
1528        }
1529    }
1530
1531  /* empty object table */
1532  hash_delete (stream->object_table);
1533  stream->object_table = hash_new(64,
1534                                  (hash_func_type)hash_ptr,
1535                                  (compare_func_type)compare_ptrs);
1536}
1537
1538/*
1539** Open the stream PHYSICAL in MODE
1540*/
1541
1542TypedStream *
1543objc_open_typed_stream (FILE *physical, int mode)
1544{
1545  TypedStream *s = (TypedStream *) objc_malloc (sizeof (TypedStream));
1546
1547  s->mode = mode;
1548  s->physical = physical;
1549  s->stream_table = hash_new (64,
1550                              (hash_func_type) hash_ptr,
1551                              (compare_func_type) compare_ptrs);
1552  s->object_table = hash_new (64,
1553                              (hash_func_type) hash_ptr,
1554                              (compare_func_type) compare_ptrs);
1555  s->eof = (objc_typed_eof_func) __objc_feof;
1556  s->flush = (objc_typed_flush_func) fflush;
1557  s->writing_root_p = 0;
1558  if (mode == OBJC_READONLY)
1559    {
1560      s->class_table = hash_new (8, (hash_func_type) hash_string,
1561                                 (compare_func_type) compare_strings);
1562      s->object_refs = hash_new (8, (hash_func_type) hash_ptr,
1563                                 (compare_func_type) compare_ptrs);
1564      s->read = (objc_typed_read_func) __objc_fread;
1565      s->write = (objc_typed_write_func) __objc_no_write;
1566      __objc_read_typed_stream_signature (s);
1567    }
1568  else if (mode == OBJC_WRITEONLY)
1569    {
1570      s->class_table = 0;
1571      s->object_refs = 0;
1572      s->read = (objc_typed_read_func) __objc_no_read;
1573      s->write = (objc_typed_write_func) __objc_fwrite;
1574      __objc_write_typed_stream_signature (s);
1575    }     
1576  else
1577    {
1578      objc_close_typed_stream (s);
1579      return NULL;
1580    }
1581  s->type = OBJC_FILE_STREAM;
1582  return s;
1583}
1584
1585/*
1586** Open the file named by FILE_NAME in MODE
1587*/
1588
1589TypedStream*
1590objc_open_typed_stream_for_file (const char *file_name, int mode)
1591{
1592  FILE *file = NULL;
1593  TypedStream *s;
1594
1595  if (mode == OBJC_READONLY)
1596    file = fopen (file_name, "r");
1597  else
1598    file = fopen (file_name, "w");
1599
1600  if (file)
1601    {
1602      s = objc_open_typed_stream (file, mode);
1603      if (s)
1604        s->type |= OBJC_MANAGED_STREAM;
1605      return s;
1606    }
1607  else
1608    return NULL;
1609}
1610
1611/*
1612** Close STREAM freeing the structure it self.  If it was opened with
1613** objc_open_typed_stream_for_file, the file will also be closed.
1614*/
1615
1616void
1617objc_close_typed_stream (TypedStream *stream)
1618{
1619  if (stream->mode == OBJC_READONLY)
1620    {
1621      __objc_finish_read_root_object (stream); /* Just in case... */
1622      hash_delete (stream->class_table);
1623      hash_delete (stream->object_refs);
1624    }
1625
1626  hash_delete (stream->stream_table);
1627  hash_delete (stream->object_table);
1628
1629  if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
1630    fclose ((FILE *)stream->physical);
1631
1632  objc_free(stream);
1633}
1634
1635BOOL
1636objc_end_of_typed_stream (TypedStream *stream)
1637{
1638  return (*stream->eof) (stream->physical);
1639}
1640
1641void
1642objc_flush_typed_stream (TypedStream *stream)
1643{
1644  (*stream->flush) (stream->physical);
1645}
1646
1647long
1648objc_get_stream_class_version (TypedStream *stream, Class class)
1649{
1650  if (stream->class_table)
1651    return PTR2LONG(hash_value_for_key (stream->class_table, class->name));
1652  else
1653    return class_get_version (class);
1654}
1655
Note: See TracBrowser for help on using the repository browser.