PR lto/49123
[official-gcc.git] / libobjc / archive.c
blobf691b13b601f893a624247cdc6c0e578b592f4c2
1 /* GNU Objective C Runtime archiving
2 Copyright (C) 1993, 1995, 1996, 1997, 2002, 2004, 2009,
3 2010 Free Software Foundation, Inc.
4 Contributed by Kresten Krab Thorup
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under the
9 terms of the GNU General Public License as published by the Free Software
10 Foundation; either version 3, or (at your option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15 details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 /* This file is entirely deprecated and will be removed. */
28 #include "objc-private/common.h"
29 #include "objc-private/error.h"
30 #include "tconfig.h"
31 #include "objc/objc-api.h"
32 #include "objc/hash.h"
33 #include "objc/objc-list.h"
34 #include "objc-private/runtime.h"
35 #include "objc/typedstream.h"
36 #include "objc/encoding.h"
37 #include <stdlib.h>
39 extern int fflush (FILE *);
41 #define ROUND(V, A) \
42 ({ typeof (V) __v = (V); typeof (A) __a = (A); \
43 __a * ((__v + __a - 1)/__a); })
45 #define PTR2LONG(P) (((char *) (P))-(char *) 0)
46 #define LONG2PTR(L) (((char *) 0) + (L))
48 /* Declare some functions... */
50 static int
51 objc_read_class (struct objc_typed_stream *stream, Class *class);
53 int objc_sizeof_type (const char *type);
55 static int
56 objc_write_use_common (struct objc_typed_stream *stream, unsigned long key);
58 static int
59 objc_write_register_common (struct objc_typed_stream *stream,
60 unsigned long key);
62 static int
63 objc_write_class (struct objc_typed_stream *stream,
64 struct objc_class *class);
66 const char *objc_skip_type (const char *type);
68 static void __objc_finish_write_root_object (struct objc_typed_stream *);
69 static void __objc_finish_read_root_object (struct objc_typed_stream *);
71 static inline int
72 __objc_code_unsigned_char (unsigned char *buf, unsigned char val)
74 if ((val&_B_VALUE) == val)
76 buf[0] = val|_B_SINT;
77 return 1;
79 else
81 buf[0] = _B_NINT|0x01;
82 buf[1] = val;
83 return 2;
87 int
88 objc_write_unsigned_char (struct objc_typed_stream *stream,
89 unsigned char value)
91 unsigned char buf[sizeof (unsigned char) + 1];
92 int len = __objc_code_unsigned_char (buf, value);
93 return (*stream->write) (stream->physical, (char*)buf, len);
96 static inline int
97 __objc_code_char (unsigned char *buf, signed char val)
99 if (val >= 0)
100 return __objc_code_unsigned_char (buf, val);
101 else
103 buf[0] = _B_NINT|_B_SIGN|0x01;
104 buf[1] = -val;
105 return 2;
110 objc_write_char (struct objc_typed_stream *stream, signed char value)
112 unsigned char buf[sizeof (char) + 1];
113 int len = __objc_code_char (buf, value);
114 return (*stream->write) (stream->physical, (char*)buf, len);
117 static inline int
118 __objc_code_unsigned_short (unsigned char *buf, unsigned short val)
120 if ((val&_B_VALUE) == val)
122 buf[0] = val|_B_SINT;
123 return 1;
125 else
127 int c, b;
129 buf[0] = _B_NINT;
131 for (c = sizeof (short); c != 0; c -= 1)
132 if (((val >> (8*(c - 1)))%0x100) != 0)
133 break;
135 buf[0] |= c;
137 for (b = 1; c != 0; c--, b++)
139 buf[b] = (val >> (8*(c - 1)))%0x100;
142 return b;
147 objc_write_unsigned_short (struct objc_typed_stream *stream,
148 unsigned short value)
150 unsigned char buf[sizeof (unsigned short) + 1];
151 int len = __objc_code_unsigned_short (buf, value);
152 return (*stream->write) (stream->physical, (char*)buf, len);
155 static inline int
156 __objc_code_short (unsigned char *buf, short val)
158 int sign = (val < 0);
159 int size = __objc_code_unsigned_short (buf, sign ? -val : val);
160 if (sign)
161 buf[0] |= _B_SIGN;
162 return size;
166 objc_write_short (struct objc_typed_stream *stream, short value)
168 unsigned char buf[sizeof (short) + 1];
169 int len = __objc_code_short (buf, value);
170 return (*stream->write) (stream->physical, (char*)buf, len);
174 static inline int
175 __objc_code_unsigned_int (unsigned char *buf, unsigned int val)
177 if ((val&_B_VALUE) == val)
179 buf[0] = val|_B_SINT;
180 return 1;
182 else
184 int c, b;
186 buf[0] = _B_NINT;
188 for (c = sizeof (int); c != 0; c -= 1)
189 if (((val >> (8*(c - 1)))%0x100) != 0)
190 break;
192 buf[0] |= c;
194 for (b = 1; c != 0; c--, b++)
196 buf[b] = (val >> (8*(c-1)))%0x100;
199 return b;
204 objc_write_unsigned_int (struct objc_typed_stream *stream, unsigned int value)
206 unsigned char buf[sizeof (unsigned int) + 1];
207 int len = __objc_code_unsigned_int (buf, value);
208 return (*stream->write) (stream->physical, (char*)buf, len);
211 static inline int
212 __objc_code_int (unsigned char *buf, int val)
214 int sign = (val < 0);
215 int size = __objc_code_unsigned_int (buf, sign ? -val : val);
216 if (sign)
217 buf[0] |= _B_SIGN;
218 return size;
222 objc_write_int (struct objc_typed_stream *stream, int value)
224 unsigned char buf[sizeof (int) + 1];
225 int len = __objc_code_int (buf, value);
226 return (*stream->write) (stream->physical, (char*)buf, len);
229 static inline int
230 __objc_code_unsigned_long (unsigned char *buf, unsigned long val)
232 if ((val&_B_VALUE) == val)
234 buf[0] = val|_B_SINT;
235 return 1;
237 else
239 int c, b;
241 buf[0] = _B_NINT;
243 for (c = sizeof (long); c != 0; c -= 1)
244 if (((val >> (8*(c - 1)))%0x100) != 0)
245 break;
247 buf[0] |= c;
249 for (b = 1; c != 0; c--, b++)
251 buf[b] = (val >> (8*(c - 1)))%0x100;
254 return b;
259 objc_write_unsigned_long (struct objc_typed_stream *stream,
260 unsigned long value)
262 unsigned char buf[sizeof (unsigned long) + 1];
263 int len = __objc_code_unsigned_long (buf, value);
264 return (*stream->write) (stream->physical, (char*)buf, len);
267 static inline int
268 __objc_code_long (unsigned char *buf, long val)
270 int sign = (val < 0);
271 int size = __objc_code_unsigned_long (buf, sign ? -val : val);
272 if (sign)
273 buf[0] |= _B_SIGN;
274 return size;
278 objc_write_long (struct objc_typed_stream *stream, long value)
280 unsigned char buf[sizeof (long) + 1];
281 int len = __objc_code_long (buf, value);
282 return (*stream->write) (stream->physical, (char*)buf, len);
287 objc_write_string (struct objc_typed_stream *stream,
288 const unsigned char *string, unsigned int nbytes)
290 unsigned char buf[sizeof (unsigned int) + 1];
291 int len = __objc_code_unsigned_int (buf, nbytes);
293 if ((buf[0]&_B_CODE) == _B_SINT)
294 buf[0] = (buf[0]&_B_VALUE)|_B_SSTR;
296 else /* _B_NINT */
297 buf[0] = (buf[0]&_B_VALUE)|_B_NSTR;
299 if ((*stream->write) (stream->physical, (char*)buf, len) != 0)
300 return (*stream->write) (stream->physical, (char*)string, nbytes);
301 else
302 return 0;
306 objc_write_string_atomic (struct objc_typed_stream *stream,
307 unsigned char *string, unsigned int nbytes)
309 unsigned long key;
310 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, string))))
311 return objc_write_use_common (stream, key);
312 else
314 int length;
315 objc_hash_add (&stream->stream_table,
316 LONG2PTR(key=PTR2LONG(string)), string);
317 if ((length = objc_write_register_common (stream, key)))
318 return objc_write_string (stream, string, nbytes);
319 return length;
323 static int
324 objc_write_register_common (struct objc_typed_stream *stream,
325 unsigned long key)
327 unsigned char buf[sizeof (unsigned long)+2];
328 int len = __objc_code_unsigned_long (buf + 1, key);
329 if (len == 1)
331 buf[0] = _B_RCOMM|0x01;
332 buf[1] &= _B_VALUE;
333 return (*stream->write) (stream->physical, (char*)buf, len + 1);
335 else
337 buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
338 return (*stream->write) (stream->physical, (char*)buf + 1, len);
342 static int
343 objc_write_use_common (struct objc_typed_stream *stream, unsigned long key)
345 unsigned char buf[sizeof (unsigned long)+2];
346 int len = __objc_code_unsigned_long (buf + 1, key);
347 if (len == 1)
349 buf[0] = _B_UCOMM|0x01;
350 buf[1] &= _B_VALUE;
351 return (*stream->write) (stream->physical, (char*)buf, 2);
353 else
355 buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
356 return (*stream->write) (stream->physical, (char*)buf + 1, len);
360 static inline int
361 __objc_write_extension (struct objc_typed_stream *stream, unsigned char code)
363 if (code <= _B_VALUE)
365 unsigned char buf = code|_B_EXT;
366 return (*stream->write) (stream->physical, (char*)&buf, 1);
368 else
370 _objc_abort ("__objc_write_extension: bad opcode %c\n", code);
371 return -1;
376 __objc_write_object (struct objc_typed_stream *stream, id object)
378 unsigned char buf = '\0';
379 SEL write_sel = sel_get_any_uid ("write:");
380 if (object)
382 __objc_write_extension (stream, _BX_OBJECT);
383 objc_write_class (stream, object->class_pointer);
384 (*objc_msg_lookup (object, write_sel)) (object, write_sel, stream);
385 return (*stream->write) (stream->physical, (char*)&buf, 1);
387 else
388 return objc_write_use_common (stream, 0);
391 int
392 objc_write_object_reference (struct objc_typed_stream *stream, id object)
394 unsigned long key;
395 if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object))))
396 return objc_write_use_common (stream, key);
398 __objc_write_extension (stream, _BX_OBJREF);
399 return objc_write_unsigned_long (stream, PTR2LONG (object));
402 int
403 objc_write_root_object (struct objc_typed_stream *stream, id object)
405 int len = 0;
406 if (stream->writing_root_p)
407 _objc_abort ("objc_write_root_object called recursively");
408 else
410 stream->writing_root_p = 1;
411 __objc_write_extension (stream, _BX_OBJROOT);
412 if ((len = objc_write_object (stream, object)))
413 __objc_finish_write_root_object (stream);
414 stream->writing_root_p = 0;
416 return len;
419 int
420 objc_write_object (struct objc_typed_stream *stream, id object)
422 unsigned long key;
423 if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object))))
424 return objc_write_use_common (stream, key);
426 else if (object == nil)
427 return objc_write_use_common (stream, 0);
429 else
431 int length;
432 objc_hash_add (&stream->object_table,
433 LONG2PTR(key=PTR2LONG(object)), object);
434 if ((length = objc_write_register_common (stream, key)))
435 return __objc_write_object (stream, object);
436 return length;
441 __objc_write_class (struct objc_typed_stream *stream, struct objc_class *class)
443 __objc_write_extension (stream, _BX_CLASS);
444 objc_write_string_atomic (stream, (unsigned char *) class->name,
445 strlen ((char *) class->name));
446 return objc_write_unsigned_long (stream, class->version);
450 static int
451 objc_write_class (struct objc_typed_stream *stream,
452 struct objc_class *class)
454 unsigned long key;
455 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, class))))
456 return objc_write_use_common (stream, key);
457 else
459 int length;
460 objc_hash_add (&stream->stream_table,
461 LONG2PTR(key = PTR2LONG(class)), class);
462 if ((length = objc_write_register_common (stream, key)))
463 return __objc_write_class (stream, class);
464 return length;
469 int
470 __objc_write_selector (struct objc_typed_stream *stream, SEL selector)
472 const char *sel_name;
473 __objc_write_extension (stream, _BX_SEL);
474 /* to handle NULL selectors */
475 if ((SEL)0 == selector)
476 return objc_write_string (stream, (unsigned char*)"", 0);
477 sel_name = sel_get_name (selector);
478 return objc_write_string (stream, (unsigned char*)sel_name, strlen ((char*)sel_name));
481 int
482 objc_write_selector (struct objc_typed_stream *stream, SEL selector)
484 const char *sel_name;
485 unsigned long key;
487 /* to handle NULL selectors */
488 if ((SEL)0 == selector)
489 return __objc_write_selector (stream, selector);
491 sel_name = sel_get_name (selector);
492 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table,
493 sel_name))))
494 return objc_write_use_common (stream, key);
495 else
497 int length;
498 objc_hash_add (&stream->stream_table,
499 LONG2PTR(key = PTR2LONG(sel_name)), (char *) sel_name);
500 if ((length = objc_write_register_common (stream, key)))
501 return __objc_write_selector (stream, selector);
502 return length;
509 ** Read operations
513 objc_read_char (struct objc_typed_stream *stream, char *val)
515 unsigned char buf;
516 int len;
517 len = (*stream->read) (stream->physical, (char*)&buf, 1);
518 if (len != 0)
520 if ((buf & _B_CODE) == _B_SINT)
521 (*val) = (buf & _B_VALUE);
523 else if ((buf & _B_NUMBER) == 1)
525 len = (*stream->read) (stream->physical, val, 1);
526 if (buf&_B_SIGN)
527 (*val) = -1 * (*val);
530 else
531 _objc_abort ("expected 8bit signed int, got %dbit int",
532 (int) (buf&_B_NUMBER)*8);
534 return len;
539 objc_read_unsigned_char (struct objc_typed_stream *stream, unsigned char *val)
541 unsigned char buf;
542 int len;
543 if ((len = (*stream->read) (stream->physical, (char*)&buf, 1)))
545 if ((buf & _B_CODE) == _B_SINT)
546 (*val) = (buf & _B_VALUE);
548 else if ((buf & _B_NUMBER) == 1)
549 len = (*stream->read) (stream->physical, (char*)val, 1);
551 else
552 _objc_abort ("expected 8bit unsigned int, got %dbit int",
553 (int) (buf&_B_NUMBER)*8);
555 return len;
559 objc_read_short (struct objc_typed_stream *stream, short *value)
561 unsigned char buf[sizeof (short) + 1];
562 int len;
563 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
565 if ((buf[0] & _B_CODE) == _B_SINT)
566 (*value) = (buf[0] & _B_VALUE);
568 else
570 int pos = 1;
571 int nbytes = buf[0] & _B_NUMBER;
572 if (nbytes > (int) sizeof (short))
573 _objc_abort ("expected short, got bigger (%dbits)", nbytes*8);
574 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
575 (*value) = 0;
576 while (pos <= nbytes)
577 (*value) = ((*value)*0x100) + buf[pos++];
578 if (buf[0] & _B_SIGN)
579 (*value) = -(*value);
582 return len;
586 objc_read_unsigned_short (struct objc_typed_stream *stream,
587 unsigned short *value)
589 unsigned char buf[sizeof (unsigned short) + 1];
590 int len;
591 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
593 if ((buf[0] & _B_CODE) == _B_SINT)
594 (*value) = (buf[0] & _B_VALUE);
596 else
598 int pos = 1;
599 int nbytes = buf[0] & _B_NUMBER;
600 if (nbytes > (int) sizeof (short))
601 _objc_abort ("expected short, got int or bigger");
602 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
603 (*value) = 0;
604 while (pos <= nbytes)
605 (*value) = ((*value)*0x100) + buf[pos++];
608 return len;
613 objc_read_int (struct objc_typed_stream *stream, int *value)
615 unsigned char buf[sizeof (int) + 1];
616 int len;
617 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
619 if ((buf[0] & _B_CODE) == _B_SINT)
620 (*value) = (buf[0] & _B_VALUE);
622 else
624 int pos = 1;
625 int nbytes = buf[0] & _B_NUMBER;
626 if (nbytes > (int) sizeof (int))
627 _objc_abort ("expected int, got bigger");
628 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
629 (*value) = 0;
630 while (pos <= nbytes)
631 (*value) = ((*value)*0x100) + buf[pos++];
632 if (buf[0] & _B_SIGN)
633 (*value) = -(*value);
636 return len;
640 objc_read_long (struct objc_typed_stream *stream, long *value)
642 unsigned char buf[sizeof (long) + 1];
643 int len;
644 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
646 if ((buf[0] & _B_CODE) == _B_SINT)
647 (*value) = (buf[0] & _B_VALUE);
649 else
651 int pos = 1;
652 int nbytes = buf[0] & _B_NUMBER;
653 if (nbytes > (int) sizeof (long))
654 _objc_abort ("expected long, got bigger");
655 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
656 (*value) = 0;
657 while (pos <= nbytes)
658 (*value) = ((*value)*0x100) + buf[pos++];
659 if (buf[0] & _B_SIGN)
660 (*value) = -(*value);
663 return len;
667 __objc_read_nbyte_uint (struct objc_typed_stream *stream,
668 unsigned int nbytes, unsigned int *val)
670 int len;
671 unsigned int pos = 0;
672 unsigned char buf[sizeof (unsigned int) + 1];
674 if (nbytes > sizeof (int))
675 _objc_abort ("expected int, got bigger");
677 len = (*stream->read) (stream->physical, (char*)buf, nbytes);
678 (*val) = 0;
679 while (pos < nbytes)
680 (*val) = ((*val)*0x100) + buf[pos++];
681 return len;
686 objc_read_unsigned_int (struct objc_typed_stream *stream,
687 unsigned int *value)
689 unsigned char buf[sizeof (unsigned int) + 1];
690 int len;
691 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
693 if ((buf[0] & _B_CODE) == _B_SINT)
694 (*value) = (buf[0] & _B_VALUE);
696 else
697 len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value);
700 return len;
704 __objc_read_nbyte_ulong (struct objc_typed_stream *stream,
705 unsigned int nbytes, unsigned long *val)
707 int len;
708 unsigned int pos = 0;
709 unsigned char buf[sizeof (unsigned long) + 1];
711 if (nbytes > sizeof (long))
712 _objc_abort ("expected long, got bigger");
714 len = (*stream->read) (stream->physical, (char*)buf, nbytes);
715 (*val) = 0;
716 while (pos < nbytes)
717 (*val) = ((*val)*0x100) + buf[pos++];
718 return len;
723 objc_read_unsigned_long (struct objc_typed_stream *stream,
724 unsigned long *value)
726 unsigned char buf[sizeof (unsigned long) + 1];
727 int len;
728 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
730 if ((buf[0] & _B_CODE) == _B_SINT)
731 (*value) = (buf[0] & _B_VALUE);
733 else
734 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value);
737 return len;
741 objc_read_string (struct objc_typed_stream *stream,
742 char **string)
744 unsigned char buf[sizeof (unsigned int) + 1];
745 int len;
746 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
748 unsigned long key = 0;
750 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
752 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
753 len = (*stream->read) (stream->physical, (char*)buf, 1);
756 switch (buf[0]&_B_CODE) {
757 case _B_SSTR:
759 int length = buf[0]&_B_VALUE;
760 (*string) = (char*)objc_malloc (length + 1);
761 if (key)
762 objc_hash_add (&stream->stream_table, LONG2PTR(key), *string);
763 len = (*stream->read) (stream->physical, *string, length);
764 (*string)[length] = '\0';
766 break;
768 case _B_UCOMM:
770 char *tmp;
771 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
772 tmp = objc_hash_value_for_key (stream->stream_table, LONG2PTR (key));
773 *string = objc_malloc (strlen (tmp) + 1);
774 strcpy (*string, tmp);
776 break;
778 case _B_NSTR:
780 unsigned int nbytes = buf[0]&_B_VALUE;
781 len = __objc_read_nbyte_uint (stream, nbytes, &nbytes);
782 if (len) {
783 (*string) = (char*)objc_malloc (nbytes + 1);
784 if (key)
785 objc_hash_add (&stream->stream_table, LONG2PTR(key), *string);
786 len = (*stream->read) (stream->physical, *string, nbytes);
787 (*string)[nbytes] = '\0';
790 break;
792 default:
793 _objc_abort ("expected string, got opcode %c\n", (buf[0]&_B_CODE));
797 return len;
802 objc_read_object (struct objc_typed_stream *stream, id *object)
804 unsigned char buf[sizeof (unsigned int)];
805 int len;
806 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
808 SEL read_sel = sel_get_any_uid ("read:");
809 unsigned long key = 0;
811 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */
813 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
814 len = (*stream->read) (stream->physical, (char*)buf, 1);
817 if (buf[0] == (_B_EXT | _BX_OBJECT))
819 Class class;
821 /* get class */
822 len = objc_read_class (stream, &class);
824 /* create instance */
825 (*object) = class_create_instance (class);
827 /* register? */
828 if (key)
829 objc_hash_add (&stream->object_table, LONG2PTR(key), *object);
831 /* send -read: */
832 if (__objc_responds_to (*object, read_sel))
833 (*get_imp (class, read_sel)) (*object, read_sel, stream);
835 /* check null-byte */
836 len = (*stream->read) (stream->physical, (char*)buf, 1);
837 if (buf[0] != '\0')
838 _objc_abort ("expected null-byte, got opcode %c", buf[0]);
841 else if ((buf[0]&_B_CODE) == _B_UCOMM)
843 if (key)
844 _objc_abort ("cannot register use upcode...");
845 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
846 (*object) = objc_hash_value_for_key (stream->object_table,
847 LONG2PTR(key));
850 else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */
852 struct objc_list *other;
853 len = objc_read_unsigned_long (stream, &key);
854 other
855 = (struct objc_list *) objc_hash_value_for_key (stream->object_refs,
856 LONG2PTR(key));
857 objc_hash_add (&stream->object_refs, LONG2PTR(key),
858 (void *)list_cons (object, other));
861 else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */
863 if (key)
864 _objc_abort ("cannot register root object...");
865 len = objc_read_object (stream, object);
866 __objc_finish_read_root_object (stream);
869 else
870 _objc_abort ("expected object, got opcode %c", buf[0]);
872 return len;
875 static int
876 objc_read_class (struct objc_typed_stream *stream, Class *class)
878 unsigned char buf[sizeof (unsigned int)];
879 int len;
880 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
882 unsigned long key = 0;
884 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
886 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
887 len = (*stream->read) (stream->physical, (char*)buf, 1);
890 if (buf[0] == (_B_EXT | _BX_CLASS))
892 char temp[1] = "";
893 char *class_name = temp;
894 unsigned long version;
896 /* get class */
897 len = objc_read_string (stream, &class_name);
898 (*class) = objc_get_class (class_name);
899 objc_free (class_name);
901 /* register */
902 if (key)
903 objc_hash_add (&stream->stream_table, LONG2PTR(key), *class);
905 objc_read_unsigned_long (stream, &version);
906 objc_hash_add (&stream->class_table,
907 (*class)->name, (void *) ((size_t) version));
910 else if ((buf[0]&_B_CODE) == _B_UCOMM)
912 if (key)
913 _objc_abort ("cannot register use upcode...");
914 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
915 *class = objc_hash_value_for_key (stream->stream_table,
916 LONG2PTR(key));
917 if (! *class)
918 _objc_abort ("cannot find class for key %lu", key);
921 else
922 _objc_abort ("expected class, got opcode %c", buf[0]);
924 return len;
928 objc_read_selector (struct objc_typed_stream *stream, SEL* selector)
930 unsigned char buf[sizeof (unsigned int)];
931 int len;
932 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
934 unsigned long key = 0;
936 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
938 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
939 len = (*stream->read) (stream->physical, (char*)buf, 1);
942 if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
944 char temp[1] = "";
945 char *selector_name = temp;
947 /* get selector */
948 len = objc_read_string (stream, &selector_name);
949 /* To handle NULL selectors */
950 if (0 == strlen (selector_name))
952 (*selector) = (SEL)0;
953 return 0;
955 else
956 (*selector) = sel_get_any_uid (selector_name);
957 objc_free (selector_name);
959 /* register */
960 if (key)
961 objc_hash_add (&stream->stream_table,
962 LONG2PTR(key), (void *) *selector);
965 else if ((buf[0]&_B_CODE) == _B_UCOMM)
967 if (key)
968 _objc_abort ("cannot register use upcode...");
969 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
970 (*selector) = objc_hash_value_for_key (stream->stream_table,
971 LONG2PTR(key));
974 else
975 _objc_abort ("expected selector, got opcode %c", buf[0]);
977 return len;
981 ** USER LEVEL FUNCTIONS
985 ** Write one object, encoded in TYPE and pointed to by DATA to the
986 ** typed stream STREAM.
990 objc_write_type (TypedStream *stream, const char *type, const void *data)
992 switch (*type) {
993 case _C_ID:
994 return objc_write_object (stream, *(id *) data);
995 break;
997 case _C_CLASS:
998 return objc_write_class (stream, *(Class *) data);
999 break;
1001 case _C_SEL:
1002 return objc_write_selector (stream, *(SEL *) data);
1003 break;
1005 case _C_CHR:
1006 return objc_write_char (stream, *(signed char *) data);
1007 break;
1009 case _C_UCHR:
1010 return objc_write_unsigned_char (stream, *(unsigned char *) data);
1011 break;
1013 case _C_SHT:
1014 return objc_write_short (stream, *(short *) data);
1015 break;
1017 case _C_USHT:
1018 return objc_write_unsigned_short (stream, *(unsigned short *) data);
1019 break;
1021 case _C_INT:
1022 return objc_write_int (stream, *(int *) data);
1023 break;
1025 case _C_UINT:
1026 return objc_write_unsigned_int (stream, *(unsigned int *) data);
1027 break;
1029 case _C_LNG:
1030 return objc_write_long (stream, *(long *) data);
1031 break;
1033 case _C_ULNG:
1034 return objc_write_unsigned_long (stream, *(unsigned long *) data);
1035 break;
1037 case _C_CHARPTR:
1038 return objc_write_string (stream,
1039 *(unsigned char **) data, strlen (*(char **) data));
1040 break;
1042 case _C_ATOM:
1043 return objc_write_string_atomic (stream, *(unsigned char **) data,
1044 strlen (*(char **) data));
1045 break;
1047 case _C_ARY_B:
1049 int len = atoi (type + 1);
1050 while (isdigit ((unsigned char) *++type))
1052 return objc_write_array (stream, type, len, data);
1054 break;
1056 case _C_STRUCT_B:
1058 int acc_size = 0;
1059 int align;
1060 while (*type != _C_STRUCT_E && *type++ != '=')
1061 ; /* skip "<name>=" */
1062 while (*type != _C_STRUCT_E)
1064 align = objc_alignof_type (type); /* padd to alignment */
1065 acc_size = ROUND (acc_size, align);
1066 objc_write_type (stream, type, ((char *) data) + acc_size);
1067 acc_size += objc_sizeof_type (type); /* add component size */
1068 type = objc_skip_typespec (type); /* skip component */
1070 return 1;
1073 default:
1075 _objc_abort ("objc_write_type: cannot parse typespec: %s\n", type);
1076 return 0;
1082 ** Read one object, encoded in TYPE and pointed to by DATA to the
1083 ** typed stream STREAM. DATA specifies the address of the types to
1084 ** read. Expected type is checked against the type actually present
1085 ** on the stream.
1089 objc_read_type(TypedStream *stream, const char *type, void *data)
1091 char c;
1092 switch (c = *type) {
1093 case _C_ID:
1094 return objc_read_object (stream, (id*)data);
1095 break;
1097 case _C_CLASS:
1098 return objc_read_class (stream, (Class*)data);
1099 break;
1101 case _C_SEL:
1102 return objc_read_selector (stream, (SEL*)data);
1103 break;
1105 case _C_CHR:
1106 return objc_read_char (stream, (char*)data);
1107 break;
1109 case _C_UCHR:
1110 return objc_read_unsigned_char (stream, (unsigned char*)data);
1111 break;
1113 case _C_SHT:
1114 return objc_read_short (stream, (short*)data);
1115 break;
1117 case _C_USHT:
1118 return objc_read_unsigned_short (stream, (unsigned short*)data);
1119 break;
1121 case _C_INT:
1122 return objc_read_int (stream, (int*)data);
1123 break;
1125 case _C_UINT:
1126 return objc_read_unsigned_int (stream, (unsigned int*)data);
1127 break;
1129 case _C_LNG:
1130 return objc_read_long (stream, (long*)data);
1131 break;
1133 case _C_ULNG:
1134 return objc_read_unsigned_long (stream, (unsigned long*)data);
1135 break;
1137 case _C_CHARPTR:
1138 case _C_ATOM:
1139 return objc_read_string (stream, (char**)data);
1140 break;
1142 case _C_ARY_B:
1144 int len = atoi (type + 1);
1145 while (isdigit ((unsigned char) *++type))
1147 return objc_read_array (stream, type, len, data);
1149 break;
1151 case _C_STRUCT_B:
1153 int acc_size = 0;
1154 int align;
1155 while (*type != _C_STRUCT_E && *type++ != '=')
1156 ; /* skip "<name>=" */
1157 while (*type != _C_STRUCT_E)
1159 align = objc_alignof_type (type); /* padd to alignment */
1160 acc_size = ROUND (acc_size, align);
1161 objc_read_type (stream, type, ((char*)data)+acc_size);
1162 acc_size += objc_sizeof_type (type); /* add component size */
1163 type = objc_skip_typespec (type); /* skip component */
1165 return 1;
1168 default:
1170 _objc_abort ("objc_read_type: cannot parse typespec: %s\n", type);
1171 return 0;
1177 ** Write the object specified by the template TYPE to STREAM. Last
1178 ** arguments specify addresses of values to be written. It might
1179 ** seem surprising to specify values by address, but this is extremely
1180 ** convenient for copy-paste with objc_read_types calls. A more
1181 ** down-to-the-earth cause for this passing of addresses is that values
1182 ** of arbitrary size is not well supported in ANSI C for functions with
1183 ** variable number of arguments.
1186 int
1187 objc_write_types (TypedStream *stream, const char *type, ...)
1189 va_list args;
1190 const char *c;
1191 int res = 0;
1193 va_start(args, type);
1195 for (c = type; *c; c = objc_skip_typespec (c))
1197 switch (*c) {
1198 case _C_ID:
1199 res = objc_write_object (stream, *va_arg (args, id*));
1200 break;
1202 case _C_CLASS:
1203 res = objc_write_class (stream, *va_arg (args, Class*));
1204 break;
1206 case _C_SEL:
1207 res = objc_write_selector (stream, *va_arg (args, SEL*));
1208 break;
1210 case _C_CHR:
1211 res = objc_write_char (stream, *va_arg (args, char*));
1212 break;
1214 case _C_UCHR:
1215 res = objc_write_unsigned_char (stream,
1216 *va_arg (args, unsigned char*));
1217 break;
1219 case _C_SHT:
1220 res = objc_write_short (stream, *va_arg (args, short*));
1221 break;
1223 case _C_USHT:
1224 res = objc_write_unsigned_short (stream,
1225 *va_arg (args, unsigned short*));
1226 break;
1228 case _C_INT:
1229 res = objc_write_int(stream, *va_arg (args, int*));
1230 break;
1232 case _C_UINT:
1233 res = objc_write_unsigned_int(stream, *va_arg (args, unsigned int*));
1234 break;
1236 case _C_LNG:
1237 res = objc_write_long(stream, *va_arg (args, long*));
1238 break;
1240 case _C_ULNG:
1241 res = objc_write_unsigned_long(stream, *va_arg (args, unsigned long*));
1242 break;
1244 case _C_CHARPTR:
1246 unsigned char **str = va_arg (args, unsigned char **);
1247 res = objc_write_string (stream, *str, strlen ((char*)*str));
1249 break;
1251 case _C_ATOM:
1253 unsigned char **str = va_arg (args, unsigned char **);
1254 res = objc_write_string_atomic (stream, *str, strlen ((char*)*str));
1256 break;
1258 case _C_ARY_B:
1260 int len = atoi (c + 1);
1261 const char *t = c;
1262 while (isdigit ((unsigned char) *++t))
1264 res = objc_write_array (stream, t, len, va_arg (args, void *));
1265 t = objc_skip_typespec (t);
1266 if (*t != _C_ARY_E)
1267 _objc_abort ("expected `]', got: %s", t);
1269 break;
1271 default:
1272 _objc_abort ("objc_write_types: cannot parse typespec: %s\n", type);
1275 va_end(args);
1276 return res;
1281 ** Last arguments specify addresses of values to be read. Expected
1282 ** type is checked against the type actually present on the stream.
1285 int
1286 objc_read_types(TypedStream *stream, const char *type, ...)
1288 va_list args;
1289 const char *c;
1290 int res = 0;
1292 va_start (args, type);
1294 for (c = type; *c; c = objc_skip_typespec(c))
1296 switch (*c) {
1297 case _C_ID:
1298 res = objc_read_object(stream, va_arg (args, id*));
1299 break;
1301 case _C_CLASS:
1302 res = objc_read_class(stream, va_arg (args, Class*));
1303 break;
1305 case _C_SEL:
1306 res = objc_read_selector(stream, va_arg (args, SEL*));
1307 break;
1309 case _C_CHR:
1310 res = objc_read_char(stream, va_arg (args, char*));
1311 break;
1313 case _C_UCHR:
1314 res = objc_read_unsigned_char(stream, va_arg (args, unsigned char*));
1315 break;
1317 case _C_SHT:
1318 res = objc_read_short(stream, va_arg (args, short*));
1319 break;
1321 case _C_USHT:
1322 res = objc_read_unsigned_short(stream, va_arg (args, unsigned short*));
1323 break;
1325 case _C_INT:
1326 res = objc_read_int(stream, va_arg (args, int*));
1327 break;
1329 case _C_UINT:
1330 res = objc_read_unsigned_int(stream, va_arg (args, unsigned int*));
1331 break;
1333 case _C_LNG:
1334 res = objc_read_long(stream, va_arg (args, long*));
1335 break;
1337 case _C_ULNG:
1338 res = objc_read_unsigned_long(stream, va_arg (args, unsigned long*));
1339 break;
1341 case _C_CHARPTR:
1342 case _C_ATOM:
1344 char **str = va_arg (args, char **);
1345 res = objc_read_string (stream, str);
1347 break;
1349 case _C_ARY_B:
1351 int len = atoi (c + 1);
1352 const char *t = c;
1353 while (isdigit ((unsigned char) *++t))
1355 res = objc_read_array (stream, t, len, va_arg (args, void *));
1356 t = objc_skip_typespec (t);
1357 if (*t != _C_ARY_E)
1358 _objc_abort ("expected `]', got: %s", t);
1360 break;
1362 default:
1363 _objc_abort ("objc_read_types: cannot parse typespec: %s\n", type);
1366 va_end (args);
1367 return res;
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)
1376 objc_write_array (TypedStream *stream, const char *type,
1377 int count, const void *data)
1379 int off = objc_sizeof_type(type);
1380 const char *where = data;
1382 while (count-- > 0)
1384 objc_write_type(stream, type, where);
1385 where += off;
1387 return 1;
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)
1398 objc_read_array (TypedStream *stream, const char *type,
1399 int count, void *data)
1401 int off = objc_sizeof_type(type);
1402 char *where = (char*)data;
1404 while (count-- > 0)
1406 objc_read_type(stream, type, where);
1407 where += off;
1409 return 1;
1412 static int
1413 __objc_fread (FILE *file, char *data, int len)
1415 return fread(data, len, 1, file);
1418 static int
1419 __objc_fwrite (FILE *file, char *data, int len)
1421 return fwrite(data, len, 1, file);
1424 static int
1425 __objc_feof (FILE *file)
1427 return feof(file);
1430 static int
1431 __objc_no_write (FILE *file __attribute__ ((__unused__)),
1432 const char *data __attribute__ ((__unused__)),
1433 int len __attribute__ ((__unused__)))
1435 _objc_abort ("TypedStream not open for writing");
1436 return 0;
1439 static int
1440 __objc_no_read (FILE *file __attribute__ ((__unused__)),
1441 const char *data __attribute__ ((__unused__)),
1442 int len __attribute__ ((__unused__)))
1444 _objc_abort ("TypedStream not open for reading");
1445 return 0;
1448 static int
1449 __objc_read_typed_stream_signature (TypedStream *stream)
1451 char buffer[80];
1452 int pos = 0;
1454 (*stream->read) (stream->physical, buffer+pos, 1);
1455 while (buffer[pos++] != '\0')
1457 sscanf (buffer, "GNU TypedStream %d", &stream->version);
1458 if (stream->version != OBJC_TYPED_STREAM_VERSION)
1459 _objc_abort ("cannot handle TypedStream version %d", stream->version);
1460 return 1;
1463 static int
1464 __objc_write_typed_stream_signature (TypedStream *stream)
1466 char buffer[80];
1467 sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
1468 stream->version = OBJC_TYPED_STREAM_VERSION;
1469 (*stream->write) (stream->physical, buffer, strlen (buffer) + 1);
1470 return 1;
1473 static void __objc_finish_write_root_object(struct objc_typed_stream *stream)
1475 objc_hash_delete (stream->object_table);
1476 stream->object_table = objc_hash_new (64,
1477 (hash_func_type) objc_hash_ptr,
1478 (compare_func_type) objc_compare_ptrs);
1481 static void __objc_finish_read_root_object(struct objc_typed_stream *stream)
1483 node_ptr node;
1484 SEL awake_sel = sel_get_any_uid ("awake");
1485 cache_ptr free_list = objc_hash_new (64,
1486 (hash_func_type) objc_hash_ptr,
1487 (compare_func_type) objc_compare_ptrs);
1489 /* resolve object forward references */
1490 for (node = objc_hash_next (stream->object_refs, NULL); node;
1491 node = objc_hash_next (stream->object_refs, node))
1493 struct objc_list *reflist = node->value;
1494 const void *key = node->key;
1495 id object = objc_hash_value_for_key (stream->object_table, key);
1496 while (reflist)
1498 *((id*) reflist->head) = object;
1499 if (objc_hash_value_for_key (free_list,reflist) == NULL)
1500 objc_hash_add (&free_list,reflist,reflist);
1502 reflist = reflist->tail;
1506 /* apply __objc_free to all objects stored in free_list */
1507 for (node = objc_hash_next (free_list, NULL); node;
1508 node = objc_hash_next (free_list, node))
1509 objc_free ((void *) node->key);
1511 objc_hash_delete (free_list);
1513 /* empty object reference table */
1514 objc_hash_delete (stream->object_refs);
1515 stream->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr,
1516 (compare_func_type) objc_compare_ptrs);
1518 /* call -awake for all objects read */
1519 if (awake_sel)
1521 for (node = objc_hash_next (stream->object_table, NULL); node;
1522 node = objc_hash_next (stream->object_table, node))
1524 id object = node->value;
1525 if (__objc_responds_to (object, awake_sel))
1526 (*objc_msg_lookup (object, awake_sel)) (object, awake_sel);
1530 /* empty object table */
1531 objc_hash_delete (stream->object_table);
1532 stream->object_table = objc_hash_new(64,
1533 (hash_func_type)objc_hash_ptr,
1534 (compare_func_type)objc_compare_ptrs);
1538 ** Open the stream PHYSICAL in MODE
1541 TypedStream *
1542 objc_open_typed_stream (FILE *physical, int mode)
1544 TypedStream *s = (TypedStream *) objc_malloc (sizeof (TypedStream));
1546 s->mode = mode;
1547 s->physical = physical;
1548 s->stream_table = objc_hash_new (64,
1549 (hash_func_type) objc_hash_ptr,
1550 (compare_func_type) objc_compare_ptrs);
1551 s->object_table = objc_hash_new (64,
1552 (hash_func_type) objc_hash_ptr,
1553 (compare_func_type) objc_compare_ptrs);
1554 s->eof = (objc_typed_eof_func) __objc_feof;
1555 s->flush = (objc_typed_flush_func) fflush;
1556 s->writing_root_p = 0;
1557 if (mode == OBJC_READONLY)
1559 s->class_table
1560 = objc_hash_new (8, (hash_func_type) objc_hash_string,
1561 (compare_func_type) objc_compare_strings);
1562 s->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr,
1563 (compare_func_type) objc_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);
1568 else if (mode == OBJC_WRITEONLY)
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);
1576 else
1578 objc_close_typed_stream (s);
1579 return NULL;
1581 s->type = OBJC_FILE_STREAM;
1582 return s;
1586 ** Open the file named by FILE_NAME in MODE
1589 TypedStream*
1590 objc_open_typed_stream_for_file (const char *file_name, int mode)
1592 FILE *file = NULL;
1593 TypedStream *s;
1595 if (mode == OBJC_READONLY)
1596 file = fopen (file_name, "r");
1597 else
1598 file = fopen (file_name, "w");
1600 if (file)
1602 s = objc_open_typed_stream (file, mode);
1603 if (s)
1604 s->type |= OBJC_MANAGED_STREAM;
1605 return s;
1607 else
1608 return NULL;
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.
1616 void
1617 objc_close_typed_stream (TypedStream *stream)
1619 if (stream->mode == OBJC_READONLY)
1621 __objc_finish_read_root_object (stream); /* Just in case... */
1622 objc_hash_delete (stream->class_table);
1623 objc_hash_delete (stream->object_refs);
1626 objc_hash_delete (stream->stream_table);
1627 objc_hash_delete (stream->object_table);
1629 if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
1630 fclose ((FILE *)stream->physical);
1632 objc_free(stream);
1635 BOOL
1636 objc_end_of_typed_stream (TypedStream *stream)
1638 return (*stream->eof) (stream->physical);
1641 void
1642 objc_flush_typed_stream (TypedStream *stream)
1644 (*stream->flush) (stream->physical);
1647 long
1648 objc_get_stream_class_version (TypedStream *stream, Class class)
1650 if (stream->class_table)
1651 return PTR2LONG(objc_hash_value_for_key (stream->class_table,
1652 class->name));
1653 else
1654 return class_get_version (class);