source: vendor/gcc/3.2.2/libobjc/archive.c

Last change on this file was 2, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 38.8 KB
Line 
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
Note: See TracBrowser for help on using the repository browser.