cp/:
[official-gcc.git] / libobjc / archive.c
blob6ac25fbd9a13334f35fee18c1745272d9ffd320f
1 /* GNU Objective C Runtime archiving
2 Copyright (C) 1993, 1995, 1996, 1997, 2002, 2004, 2009 Free Software Foundation, Inc.
3 Contributed by Kresten Krab Thorup
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 3, or (at your option) any later version.
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 details.
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 #include "tconfig.h"
26 #include "objc/runtime.h"
27 #include "objc/typedstream.h"
28 #include "objc/encoding.h"
29 #include <stdlib.h>
31 extern int fflush (FILE *);
33 #define ROUND(V, A) \
34 ({ typeof (V) __v = (V); typeof (A) __a = (A); \
35 __a * ((__v + __a - 1)/__a); })
37 #define PTR2LONG(P) (((char *) (P))-(char *) 0)
38 #define LONG2PTR(L) (((char *) 0) + (L))
40 /* Declare some functions... */
42 static int
43 objc_read_class (struct objc_typed_stream *stream, Class *class);
45 int objc_sizeof_type (const char *type);
47 static int
48 objc_write_use_common (struct objc_typed_stream *stream, unsigned long key);
50 static int
51 objc_write_register_common (struct objc_typed_stream *stream,
52 unsigned long key);
54 static int
55 objc_write_class (struct objc_typed_stream *stream,
56 struct objc_class *class);
58 const char *objc_skip_type (const char *type);
60 static void __objc_finish_write_root_object (struct objc_typed_stream *);
61 static void __objc_finish_read_root_object (struct objc_typed_stream *);
63 static inline int
64 __objc_code_unsigned_char (unsigned char *buf, unsigned char val)
66 if ((val&_B_VALUE) == val)
68 buf[0] = val|_B_SINT;
69 return 1;
71 else
73 buf[0] = _B_NINT|0x01;
74 buf[1] = val;
75 return 2;
79 int
80 objc_write_unsigned_char (struct objc_typed_stream *stream,
81 unsigned char value)
83 unsigned char buf[sizeof (unsigned char) + 1];
84 int len = __objc_code_unsigned_char (buf, value);
85 return (*stream->write) (stream->physical, (char*)buf, len);
88 static inline int
89 __objc_code_char (unsigned char *buf, signed char val)
91 if (val >= 0)
92 return __objc_code_unsigned_char (buf, val);
93 else
95 buf[0] = _B_NINT|_B_SIGN|0x01;
96 buf[1] = -val;
97 return 2;
102 objc_write_char (struct objc_typed_stream *stream, signed char value)
104 unsigned char buf[sizeof (char) + 1];
105 int len = __objc_code_char (buf, value);
106 return (*stream->write) (stream->physical, (char*)buf, len);
109 static inline int
110 __objc_code_unsigned_short (unsigned char *buf, unsigned short val)
112 if ((val&_B_VALUE) == val)
114 buf[0] = val|_B_SINT;
115 return 1;
117 else
119 int c, b;
121 buf[0] = _B_NINT;
123 for (c = sizeof (short); c != 0; c -= 1)
124 if (((val >> (8*(c - 1)))%0x100) != 0)
125 break;
127 buf[0] |= c;
129 for (b = 1; c != 0; c--, b++)
131 buf[b] = (val >> (8*(c - 1)))%0x100;
134 return b;
139 objc_write_unsigned_short (struct objc_typed_stream *stream,
140 unsigned short value)
142 unsigned char buf[sizeof (unsigned short) + 1];
143 int len = __objc_code_unsigned_short (buf, value);
144 return (*stream->write) (stream->physical, (char*)buf, len);
147 static inline int
148 __objc_code_short (unsigned char *buf, short val)
150 int sign = (val < 0);
151 int size = __objc_code_unsigned_short (buf, sign ? -val : val);
152 if (sign)
153 buf[0] |= _B_SIGN;
154 return size;
158 objc_write_short (struct objc_typed_stream *stream, short value)
160 unsigned char buf[sizeof (short) + 1];
161 int len = __objc_code_short (buf, value);
162 return (*stream->write) (stream->physical, (char*)buf, len);
166 static inline int
167 __objc_code_unsigned_int (unsigned char *buf, unsigned int val)
169 if ((val&_B_VALUE) == val)
171 buf[0] = val|_B_SINT;
172 return 1;
174 else
176 int c, b;
178 buf[0] = _B_NINT;
180 for (c = sizeof (int); c != 0; c -= 1)
181 if (((val >> (8*(c - 1)))%0x100) != 0)
182 break;
184 buf[0] |= c;
186 for (b = 1; c != 0; c--, b++)
188 buf[b] = (val >> (8*(c-1)))%0x100;
191 return b;
196 objc_write_unsigned_int (struct objc_typed_stream *stream, unsigned int value)
198 unsigned char buf[sizeof (unsigned int) + 1];
199 int len = __objc_code_unsigned_int (buf, value);
200 return (*stream->write) (stream->physical, (char*)buf, len);
203 static inline int
204 __objc_code_int (unsigned char *buf, int val)
206 int sign = (val < 0);
207 int size = __objc_code_unsigned_int (buf, sign ? -val : val);
208 if (sign)
209 buf[0] |= _B_SIGN;
210 return size;
214 objc_write_int (struct objc_typed_stream *stream, int value)
216 unsigned char buf[sizeof (int) + 1];
217 int len = __objc_code_int (buf, value);
218 return (*stream->write) (stream->physical, (char*)buf, len);
221 static inline int
222 __objc_code_unsigned_long (unsigned char *buf, unsigned long val)
224 if ((val&_B_VALUE) == val)
226 buf[0] = val|_B_SINT;
227 return 1;
229 else
231 int c, b;
233 buf[0] = _B_NINT;
235 for (c = sizeof (long); c != 0; c -= 1)
236 if (((val >> (8*(c - 1)))%0x100) != 0)
237 break;
239 buf[0] |= c;
241 for (b = 1; c != 0; c--, b++)
243 buf[b] = (val >> (8*(c - 1)))%0x100;
246 return b;
251 objc_write_unsigned_long (struct objc_typed_stream *stream,
252 unsigned long value)
254 unsigned char buf[sizeof (unsigned long) + 1];
255 int len = __objc_code_unsigned_long (buf, value);
256 return (*stream->write) (stream->physical, (char*)buf, len);
259 static inline int
260 __objc_code_long (unsigned char *buf, long val)
262 int sign = (val < 0);
263 int size = __objc_code_unsigned_long (buf, sign ? -val : val);
264 if (sign)
265 buf[0] |= _B_SIGN;
266 return size;
270 objc_write_long (struct objc_typed_stream *stream, long value)
272 unsigned char buf[sizeof (long) + 1];
273 int len = __objc_code_long (buf, value);
274 return (*stream->write) (stream->physical, (char*)buf, len);
279 objc_write_string (struct objc_typed_stream *stream,
280 const unsigned char *string, unsigned int nbytes)
282 unsigned char buf[sizeof (unsigned int) + 1];
283 int len = __objc_code_unsigned_int (buf, nbytes);
285 if ((buf[0]&_B_CODE) == _B_SINT)
286 buf[0] = (buf[0]&_B_VALUE)|_B_SSTR;
288 else /* _B_NINT */
289 buf[0] = (buf[0]&_B_VALUE)|_B_NSTR;
291 if ((*stream->write) (stream->physical, (char*)buf, len) != 0)
292 return (*stream->write) (stream->physical, (char*)string, nbytes);
293 else
294 return 0;
298 objc_write_string_atomic (struct objc_typed_stream *stream,
299 unsigned char *string, unsigned int nbytes)
301 unsigned long key;
302 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, string))))
303 return objc_write_use_common (stream, key);
304 else
306 int length;
307 objc_hash_add (&stream->stream_table,
308 LONG2PTR(key=PTR2LONG(string)), string);
309 if ((length = objc_write_register_common (stream, key)))
310 return objc_write_string (stream, string, nbytes);
311 return length;
315 static int
316 objc_write_register_common (struct objc_typed_stream *stream,
317 unsigned long key)
319 unsigned char buf[sizeof (unsigned long)+2];
320 int len = __objc_code_unsigned_long (buf + 1, key);
321 if (len == 1)
323 buf[0] = _B_RCOMM|0x01;
324 buf[1] &= _B_VALUE;
325 return (*stream->write) (stream->physical, (char*)buf, len + 1);
327 else
329 buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
330 return (*stream->write) (stream->physical, (char*)buf + 1, len);
334 static int
335 objc_write_use_common (struct objc_typed_stream *stream, unsigned long key)
337 unsigned char buf[sizeof (unsigned long)+2];
338 int len = __objc_code_unsigned_long (buf + 1, key);
339 if (len == 1)
341 buf[0] = _B_UCOMM|0x01;
342 buf[1] &= _B_VALUE;
343 return (*stream->write) (stream->physical, (char*)buf, 2);
345 else
347 buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
348 return (*stream->write) (stream->physical, (char*)buf + 1, len);
352 static inline int
353 __objc_write_extension (struct objc_typed_stream *stream, unsigned char code)
355 if (code <= _B_VALUE)
357 unsigned char buf = code|_B_EXT;
358 return (*stream->write) (stream->physical, (char*)&buf, 1);
360 else
362 objc_error (nil, OBJC_ERR_BAD_OPCODE,
363 "__objc_write_extension: bad opcode %c\n", code);
364 return -1;
368 inline int
369 __objc_write_object (struct objc_typed_stream *stream, id object)
371 unsigned char buf = '\0';
372 SEL write_sel = sel_get_any_uid ("write:");
373 if (object)
375 __objc_write_extension (stream, _BX_OBJECT);
376 objc_write_class (stream, object->class_pointer);
377 (*objc_msg_lookup (object, write_sel)) (object, write_sel, stream);
378 return (*stream->write) (stream->physical, (char*)&buf, 1);
380 else
381 return objc_write_use_common (stream, 0);
384 int
385 objc_write_object_reference (struct objc_typed_stream *stream, id object)
387 unsigned long key;
388 if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object))))
389 return objc_write_use_common (stream, key);
391 __objc_write_extension (stream, _BX_OBJREF);
392 return objc_write_unsigned_long (stream, PTR2LONG (object));
395 int
396 objc_write_root_object (struct objc_typed_stream *stream, id object)
398 int len = 0;
399 if (stream->writing_root_p)
400 objc_error (nil, OBJC_ERR_RECURSE_ROOT,
401 "objc_write_root_object called recursively");
402 else
404 stream->writing_root_p = 1;
405 __objc_write_extension (stream, _BX_OBJROOT);
406 if ((len = objc_write_object (stream, object)))
407 __objc_finish_write_root_object (stream);
408 stream->writing_root_p = 0;
410 return len;
413 int
414 objc_write_object (struct objc_typed_stream *stream, id object)
416 unsigned long key;
417 if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object))))
418 return objc_write_use_common (stream, key);
420 else if (object == nil)
421 return objc_write_use_common (stream, 0);
423 else
425 int length;
426 objc_hash_add (&stream->object_table,
427 LONG2PTR(key=PTR2LONG(object)), object);
428 if ((length = objc_write_register_common (stream, key)))
429 return __objc_write_object (stream, object);
430 return length;
434 inline int
435 __objc_write_class (struct objc_typed_stream *stream, struct objc_class *class)
437 __objc_write_extension (stream, _BX_CLASS);
438 objc_write_string_atomic (stream, (unsigned char *) class->name,
439 strlen ((char *) class->name));
440 return objc_write_unsigned_long (stream, class->version);
444 static int
445 objc_write_class (struct objc_typed_stream *stream,
446 struct objc_class *class)
448 unsigned long key;
449 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, class))))
450 return objc_write_use_common (stream, key);
451 else
453 int length;
454 objc_hash_add (&stream->stream_table,
455 LONG2PTR(key = PTR2LONG(class)), class);
456 if ((length = objc_write_register_common (stream, key)))
457 return __objc_write_class (stream, class);
458 return length;
463 inline int
464 __objc_write_selector (struct objc_typed_stream *stream, SEL selector)
466 const char *sel_name;
467 __objc_write_extension (stream, _BX_SEL);
468 /* to handle NULL selectors */
469 if ((SEL)0 == selector)
470 return objc_write_string (stream, (unsigned char*)"", 0);
471 sel_name = sel_get_name (selector);
472 return objc_write_string (stream, (unsigned char*)sel_name, strlen ((char*)sel_name));
475 int
476 objc_write_selector (struct objc_typed_stream *stream, SEL selector)
478 const char *sel_name;
479 unsigned long key;
481 /* to handle NULL selectors */
482 if ((SEL)0 == selector)
483 return __objc_write_selector (stream, selector);
485 sel_name = sel_get_name (selector);
486 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table,
487 sel_name))))
488 return objc_write_use_common (stream, key);
489 else
491 int length;
492 objc_hash_add (&stream->stream_table,
493 LONG2PTR(key = PTR2LONG(sel_name)), (char *) sel_name);
494 if ((length = objc_write_register_common (stream, key)))
495 return __objc_write_selector (stream, selector);
496 return length;
503 ** Read operations
506 inline int
507 objc_read_char (struct objc_typed_stream *stream, char *val)
509 unsigned char buf;
510 int len;
511 len = (*stream->read) (stream->physical, (char*)&buf, 1);
512 if (len != 0)
514 if ((buf & _B_CODE) == _B_SINT)
515 (*val) = (buf & _B_VALUE);
517 else if ((buf & _B_NUMBER) == 1)
519 len = (*stream->read) (stream->physical, val, 1);
520 if (buf&_B_SIGN)
521 (*val) = -1 * (*val);
524 else
525 objc_error (nil, OBJC_ERR_BAD_DATA,
526 "expected 8bit signed int, got %dbit int",
527 (int) (buf&_B_NUMBER)*8);
529 return len;
533 inline int
534 objc_read_unsigned_char (struct objc_typed_stream *stream, unsigned char *val)
536 unsigned char buf;
537 int len;
538 if ((len = (*stream->read) (stream->physical, (char*)&buf, 1)))
540 if ((buf & _B_CODE) == _B_SINT)
541 (*val) = (buf & _B_VALUE);
543 else if ((buf & _B_NUMBER) == 1)
544 len = (*stream->read) (stream->physical, (char*)val, 1);
546 else
547 objc_error (nil, OBJC_ERR_BAD_DATA,
548 "expected 8bit unsigned int, got %dbit int",
549 (int) (buf&_B_NUMBER)*8);
551 return len;
554 inline int
555 objc_read_short (struct objc_typed_stream *stream, short *value)
557 unsigned char buf[sizeof (short) + 1];
558 int len;
559 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
561 if ((buf[0] & _B_CODE) == _B_SINT)
562 (*value) = (buf[0] & _B_VALUE);
564 else
566 int pos = 1;
567 int nbytes = buf[0] & _B_NUMBER;
568 if (nbytes > (int) sizeof (short))
569 objc_error (nil, OBJC_ERR_BAD_DATA,
570 "expected short, got bigger (%dbits)", nbytes*8);
571 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
572 (*value) = 0;
573 while (pos <= nbytes)
574 (*value) = ((*value)*0x100) + buf[pos++];
575 if (buf[0] & _B_SIGN)
576 (*value) = -(*value);
579 return len;
582 inline int
583 objc_read_unsigned_short (struct objc_typed_stream *stream,
584 unsigned short *value)
586 unsigned char buf[sizeof (unsigned short) + 1];
587 int len;
588 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
590 if ((buf[0] & _B_CODE) == _B_SINT)
591 (*value) = (buf[0] & _B_VALUE);
593 else
595 int pos = 1;
596 int nbytes = buf[0] & _B_NUMBER;
597 if (nbytes > (int) sizeof (short))
598 objc_error (nil, OBJC_ERR_BAD_DATA,
599 "expected short, got int or bigger");
600 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
601 (*value) = 0;
602 while (pos <= nbytes)
603 (*value) = ((*value)*0x100) + buf[pos++];
606 return len;
610 inline int
611 objc_read_int (struct objc_typed_stream *stream, int *value)
613 unsigned char buf[sizeof (int) + 1];
614 int len;
615 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
617 if ((buf[0] & _B_CODE) == _B_SINT)
618 (*value) = (buf[0] & _B_VALUE);
620 else
622 int pos = 1;
623 int nbytes = buf[0] & _B_NUMBER;
624 if (nbytes > (int) sizeof (int))
625 objc_error (nil, OBJC_ERR_BAD_DATA, "expected int, got bigger");
626 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
627 (*value) = 0;
628 while (pos <= nbytes)
629 (*value) = ((*value)*0x100) + buf[pos++];
630 if (buf[0] & _B_SIGN)
631 (*value) = -(*value);
634 return len;
637 inline int
638 objc_read_long (struct objc_typed_stream *stream, long *value)
640 unsigned char buf[sizeof (long) + 1];
641 int len;
642 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
644 if ((buf[0] & _B_CODE) == _B_SINT)
645 (*value) = (buf[0] & _B_VALUE);
647 else
649 int pos = 1;
650 int nbytes = buf[0] & _B_NUMBER;
651 if (nbytes > (int) sizeof (long))
652 objc_error (nil, OBJC_ERR_BAD_DATA, "expected long, got bigger");
653 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
654 (*value) = 0;
655 while (pos <= nbytes)
656 (*value) = ((*value)*0x100) + buf[pos++];
657 if (buf[0] & _B_SIGN)
658 (*value) = -(*value);
661 return len;
664 inline int
665 __objc_read_nbyte_uint (struct objc_typed_stream *stream,
666 unsigned int nbytes, unsigned int *val)
668 int len;
669 unsigned int pos = 0;
670 unsigned char buf[sizeof (unsigned int) + 1];
672 if (nbytes > sizeof (int))
673 objc_error (nil, OBJC_ERR_BAD_DATA, "expected int, got bigger");
675 len = (*stream->read) (stream->physical, (char*)buf, nbytes);
676 (*val) = 0;
677 while (pos < nbytes)
678 (*val) = ((*val)*0x100) + buf[pos++];
679 return len;
683 inline int
684 objc_read_unsigned_int (struct objc_typed_stream *stream,
685 unsigned int *value)
687 unsigned char buf[sizeof (unsigned int) + 1];
688 int len;
689 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
691 if ((buf[0] & _B_CODE) == _B_SINT)
692 (*value) = (buf[0] & _B_VALUE);
694 else
695 len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value);
698 return len;
702 __objc_read_nbyte_ulong (struct objc_typed_stream *stream,
703 unsigned int nbytes, unsigned long *val)
705 int len;
706 unsigned int pos = 0;
707 unsigned char buf[sizeof (unsigned long) + 1];
709 if (nbytes > sizeof (long))
710 objc_error (nil, OBJC_ERR_BAD_DATA, "expected long, got bigger");
712 len = (*stream->read) (stream->physical, (char*)buf, nbytes);
713 (*val) = 0;
714 while (pos < nbytes)
715 (*val) = ((*val)*0x100) + buf[pos++];
716 return len;
720 inline int
721 objc_read_unsigned_long (struct objc_typed_stream *stream,
722 unsigned long *value)
724 unsigned char buf[sizeof (unsigned long) + 1];
725 int len;
726 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
728 if ((buf[0] & _B_CODE) == _B_SINT)
729 (*value) = (buf[0] & _B_VALUE);
731 else
732 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value);
735 return len;
738 inline int
739 objc_read_string (struct objc_typed_stream *stream,
740 char **string)
742 unsigned char buf[sizeof (unsigned int) + 1];
743 int len;
744 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
746 unsigned long key = 0;
748 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
750 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
751 len = (*stream->read) (stream->physical, (char*)buf, 1);
754 switch (buf[0]&_B_CODE) {
755 case _B_SSTR:
757 int length = buf[0]&_B_VALUE;
758 (*string) = (char*)objc_malloc (length + 1);
759 if (key)
760 objc_hash_add (&stream->stream_table, LONG2PTR(key), *string);
761 len = (*stream->read) (stream->physical, *string, length);
762 (*string)[length] = '\0';
764 break;
766 case _B_UCOMM:
768 char *tmp;
769 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
770 tmp = objc_hash_value_for_key (stream->stream_table, LONG2PTR (key));
771 *string = objc_malloc (strlen (tmp) + 1);
772 strcpy (*string, tmp);
774 break;
776 case _B_NSTR:
778 unsigned int nbytes = buf[0]&_B_VALUE;
779 len = __objc_read_nbyte_uint (stream, nbytes, &nbytes);
780 if (len) {
781 (*string) = (char*)objc_malloc (nbytes + 1);
782 if (key)
783 objc_hash_add (&stream->stream_table, LONG2PTR(key), *string);
784 len = (*stream->read) (stream->physical, *string, nbytes);
785 (*string)[nbytes] = '\0';
788 break;
790 default:
791 objc_error (nil, OBJC_ERR_BAD_DATA,
792 "expected string, got opcode %c\n", (buf[0]&_B_CODE));
796 return len;
801 objc_read_object (struct objc_typed_stream *stream, id *object)
803 unsigned char buf[sizeof (unsigned int)];
804 int len;
805 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
807 SEL read_sel = sel_get_any_uid ("read:");
808 unsigned long key = 0;
810 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */
812 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
813 len = (*stream->read) (stream->physical, (char*)buf, 1);
816 if (buf[0] == (_B_EXT | _BX_OBJECT))
818 Class class;
820 /* get class */
821 len = objc_read_class (stream, &class);
823 /* create instance */
824 (*object) = class_create_instance (class);
826 /* register? */
827 if (key)
828 objc_hash_add (&stream->object_table, LONG2PTR(key), *object);
830 /* send -read: */
831 if (__objc_responds_to (*object, read_sel))
832 (*get_imp (class, read_sel)) (*object, read_sel, stream);
834 /* check null-byte */
835 len = (*stream->read) (stream->physical, (char*)buf, 1);
836 if (buf[0] != '\0')
837 objc_error (nil, OBJC_ERR_BAD_DATA,
838 "expected null-byte, got opcode %c", buf[0]);
841 else if ((buf[0]&_B_CODE) == _B_UCOMM)
843 if (key)
844 objc_error (nil, OBJC_ERR_BAD_KEY, "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_error (nil, OBJC_ERR_BAD_KEY,
865 "cannot register root object...");
866 len = objc_read_object (stream, object);
867 __objc_finish_read_root_object (stream);
870 else
871 objc_error (nil, OBJC_ERR_BAD_DATA,
872 "expected object, got opcode %c", buf[0]);
874 return len;
877 static int
878 objc_read_class (struct objc_typed_stream *stream, Class *class)
880 unsigned char buf[sizeof (unsigned int)];
881 int len;
882 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
884 unsigned long key = 0;
886 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
888 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
889 len = (*stream->read) (stream->physical, (char*)buf, 1);
892 if (buf[0] == (_B_EXT | _BX_CLASS))
894 char temp[1] = "";
895 char *class_name = temp;
896 unsigned long version;
898 /* get class */
899 len = objc_read_string (stream, &class_name);
900 (*class) = objc_get_class (class_name);
901 objc_free (class_name);
903 /* register */
904 if (key)
905 objc_hash_add (&stream->stream_table, LONG2PTR(key), *class);
907 objc_read_unsigned_long (stream, &version);
908 objc_hash_add (&stream->class_table,
909 (*class)->name, (void *) ((size_t) version));
912 else if ((buf[0]&_B_CODE) == _B_UCOMM)
914 if (key)
915 objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
916 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
917 *class = objc_hash_value_for_key (stream->stream_table,
918 LONG2PTR(key));
919 if (! *class)
920 objc_error (nil, OBJC_ERR_BAD_CLASS,
921 "cannot find class for key %lu", key);
924 else
925 objc_error (nil, OBJC_ERR_BAD_DATA,
926 "expected class, got opcode %c", buf[0]);
928 return len;
932 objc_read_selector (struct objc_typed_stream *stream, SEL* selector)
934 unsigned char buf[sizeof (unsigned int)];
935 int len;
936 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
938 unsigned long key = 0;
940 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
942 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
943 len = (*stream->read) (stream->physical, (char*)buf, 1);
946 if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
948 char temp[1] = "";
949 char *selector_name = temp;
951 /* get selector */
952 len = objc_read_string (stream, &selector_name);
953 /* To handle NULL selectors */
954 if (0 == strlen (selector_name))
956 (*selector) = (SEL)0;
957 return 0;
959 else
960 (*selector) = sel_get_any_uid (selector_name);
961 objc_free (selector_name);
963 /* register */
964 if (key)
965 objc_hash_add (&stream->stream_table,
966 LONG2PTR(key), (void *) *selector);
969 else if ((buf[0]&_B_CODE) == _B_UCOMM)
971 if (key)
972 objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
973 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
974 (*selector) = objc_hash_value_for_key (stream->stream_table,
975 LONG2PTR(key));
978 else
979 objc_error (nil, OBJC_ERR_BAD_DATA,
980 "expected selector, got opcode %c", buf[0]);
982 return len;
986 ** USER LEVEL FUNCTIONS
990 ** Write one object, encoded in TYPE and pointed to by DATA to the
991 ** typed stream STREAM.
995 objc_write_type (TypedStream *stream, const char *type, const void *data)
997 switch (*type) {
998 case _C_ID:
999 return objc_write_object (stream, *(id *) data);
1000 break;
1002 case _C_CLASS:
1003 return objc_write_class (stream, *(Class *) data);
1004 break;
1006 case _C_SEL:
1007 return objc_write_selector (stream, *(SEL *) data);
1008 break;
1010 case _C_CHR:
1011 return objc_write_char (stream, *(signed char *) data);
1012 break;
1014 case _C_UCHR:
1015 return objc_write_unsigned_char (stream, *(unsigned char *) data);
1016 break;
1018 case _C_SHT:
1019 return objc_write_short (stream, *(short *) data);
1020 break;
1022 case _C_USHT:
1023 return objc_write_unsigned_short (stream, *(unsigned short *) data);
1024 break;
1026 case _C_INT:
1027 return objc_write_int (stream, *(int *) data);
1028 break;
1030 case _C_UINT:
1031 return objc_write_unsigned_int (stream, *(unsigned int *) data);
1032 break;
1034 case _C_LNG:
1035 return objc_write_long (stream, *(long *) data);
1036 break;
1038 case _C_ULNG:
1039 return objc_write_unsigned_long (stream, *(unsigned long *) data);
1040 break;
1042 case _C_CHARPTR:
1043 return objc_write_string (stream,
1044 *(unsigned char **) data, strlen (*(char **) data));
1045 break;
1047 case _C_ATOM:
1048 return objc_write_string_atomic (stream, *(unsigned char **) data,
1049 strlen (*(char **) data));
1050 break;
1052 case _C_ARY_B:
1054 int len = atoi (type + 1);
1055 while (isdigit ((unsigned char) *++type))
1057 return objc_write_array (stream, type, len, data);
1059 break;
1061 case _C_STRUCT_B:
1063 int acc_size = 0;
1064 int align;
1065 while (*type != _C_STRUCT_E && *type++ != '=')
1066 ; /* skip "<name>=" */
1067 while (*type != _C_STRUCT_E)
1069 align = objc_alignof_type (type); /* padd to alignment */
1070 acc_size = ROUND (acc_size, align);
1071 objc_write_type (stream, type, ((char *) data) + acc_size);
1072 acc_size += objc_sizeof_type (type); /* add component size */
1073 type = objc_skip_typespec (type); /* skip component */
1075 return 1;
1078 default:
1080 objc_error (nil, OBJC_ERR_BAD_TYPE,
1081 "objc_write_type: cannot parse typespec: %s\n", type);
1082 return 0;
1088 ** Read one object, encoded in TYPE and pointed to by DATA to the
1089 ** typed stream STREAM. DATA specifies the address of the types to
1090 ** read. Expected type is checked against the type actually present
1091 ** on the stream.
1095 objc_read_type(TypedStream *stream, const char *type, void *data)
1097 char c;
1098 switch (c = *type) {
1099 case _C_ID:
1100 return objc_read_object (stream, (id*)data);
1101 break;
1103 case _C_CLASS:
1104 return objc_read_class (stream, (Class*)data);
1105 break;
1107 case _C_SEL:
1108 return objc_read_selector (stream, (SEL*)data);
1109 break;
1111 case _C_CHR:
1112 return objc_read_char (stream, (char*)data);
1113 break;
1115 case _C_UCHR:
1116 return objc_read_unsigned_char (stream, (unsigned char*)data);
1117 break;
1119 case _C_SHT:
1120 return objc_read_short (stream, (short*)data);
1121 break;
1123 case _C_USHT:
1124 return objc_read_unsigned_short (stream, (unsigned short*)data);
1125 break;
1127 case _C_INT:
1128 return objc_read_int (stream, (int*)data);
1129 break;
1131 case _C_UINT:
1132 return objc_read_unsigned_int (stream, (unsigned int*)data);
1133 break;
1135 case _C_LNG:
1136 return objc_read_long (stream, (long*)data);
1137 break;
1139 case _C_ULNG:
1140 return objc_read_unsigned_long (stream, (unsigned long*)data);
1141 break;
1143 case _C_CHARPTR:
1144 case _C_ATOM:
1145 return objc_read_string (stream, (char**)data);
1146 break;
1148 case _C_ARY_B:
1150 int len = atoi (type + 1);
1151 while (isdigit ((unsigned char) *++type))
1153 return objc_read_array (stream, type, len, data);
1155 break;
1157 case _C_STRUCT_B:
1159 int acc_size = 0;
1160 int align;
1161 while (*type != _C_STRUCT_E && *type++ != '=')
1162 ; /* skip "<name>=" */
1163 while (*type != _C_STRUCT_E)
1165 align = objc_alignof_type (type); /* padd to alignment */
1166 acc_size = ROUND (acc_size, align);
1167 objc_read_type (stream, type, ((char*)data)+acc_size);
1168 acc_size += objc_sizeof_type (type); /* add component size */
1169 type = objc_skip_typespec (type); /* skip component */
1171 return 1;
1174 default:
1176 objc_error (nil, OBJC_ERR_BAD_TYPE,
1177 "objc_read_type: cannot parse typespec: %s\n", type);
1178 return 0;
1184 ** Write the object specified by the template TYPE to STREAM. Last
1185 ** arguments specify addresses of values to be written. It might
1186 ** seem surprising to specify values by address, but this is extremely
1187 ** convenient for copy-paste with objc_read_types calls. A more
1188 ** down-to-the-earth cause for this passing of addresses is that values
1189 ** of arbitrary size is not well supported in ANSI C for functions with
1190 ** variable number of arguments.
1193 int
1194 objc_write_types (TypedStream *stream, const char *type, ...)
1196 va_list args;
1197 const char *c;
1198 int res = 0;
1200 va_start(args, type);
1202 for (c = type; *c; c = objc_skip_typespec (c))
1204 switch (*c) {
1205 case _C_ID:
1206 res = objc_write_object (stream, *va_arg (args, id*));
1207 break;
1209 case _C_CLASS:
1210 res = objc_write_class (stream, *va_arg (args, Class*));
1211 break;
1213 case _C_SEL:
1214 res = objc_write_selector (stream, *va_arg (args, SEL*));
1215 break;
1217 case _C_CHR:
1218 res = objc_write_char (stream, *va_arg (args, char*));
1219 break;
1221 case _C_UCHR:
1222 res = objc_write_unsigned_char (stream,
1223 *va_arg (args, unsigned char*));
1224 break;
1226 case _C_SHT:
1227 res = objc_write_short (stream, *va_arg (args, short*));
1228 break;
1230 case _C_USHT:
1231 res = objc_write_unsigned_short (stream,
1232 *va_arg (args, unsigned short*));
1233 break;
1235 case _C_INT:
1236 res = objc_write_int(stream, *va_arg (args, int*));
1237 break;
1239 case _C_UINT:
1240 res = objc_write_unsigned_int(stream, *va_arg (args, unsigned int*));
1241 break;
1243 case _C_LNG:
1244 res = objc_write_long(stream, *va_arg (args, long*));
1245 break;
1247 case _C_ULNG:
1248 res = objc_write_unsigned_long(stream, *va_arg (args, unsigned long*));
1249 break;
1251 case _C_CHARPTR:
1253 unsigned char **str = va_arg (args, unsigned char **);
1254 res = objc_write_string (stream, *str, strlen ((char*)*str));
1256 break;
1258 case _C_ATOM:
1260 unsigned char **str = va_arg (args, unsigned char **);
1261 res = objc_write_string_atomic (stream, *str, strlen ((char*)*str));
1263 break;
1265 case _C_ARY_B:
1267 int len = atoi (c + 1);
1268 const char *t = c;
1269 while (isdigit ((unsigned char) *++t))
1271 res = objc_write_array (stream, t, len, va_arg (args, void *));
1272 t = objc_skip_typespec (t);
1273 if (*t != _C_ARY_E)
1274 objc_error (nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t);
1276 break;
1278 default:
1279 objc_error (nil, OBJC_ERR_BAD_TYPE,
1280 "objc_write_types: cannot parse typespec: %s\n", type);
1283 va_end(args);
1284 return res;
1289 ** Last arguments specify addresses of values to be read. Expected
1290 ** type is checked against the type actually present on the stream.
1293 int
1294 objc_read_types(TypedStream *stream, const char *type, ...)
1296 va_list args;
1297 const char *c;
1298 int res = 0;
1300 va_start (args, type);
1302 for (c = type; *c; c = objc_skip_typespec(c))
1304 switch (*c) {
1305 case _C_ID:
1306 res = objc_read_object(stream, va_arg (args, id*));
1307 break;
1309 case _C_CLASS:
1310 res = objc_read_class(stream, va_arg (args, Class*));
1311 break;
1313 case _C_SEL:
1314 res = objc_read_selector(stream, va_arg (args, SEL*));
1315 break;
1317 case _C_CHR:
1318 res = objc_read_char(stream, va_arg (args, char*));
1319 break;
1321 case _C_UCHR:
1322 res = objc_read_unsigned_char(stream, va_arg (args, unsigned char*));
1323 break;
1325 case _C_SHT:
1326 res = objc_read_short(stream, va_arg (args, short*));
1327 break;
1329 case _C_USHT:
1330 res = objc_read_unsigned_short(stream, va_arg (args, unsigned short*));
1331 break;
1333 case _C_INT:
1334 res = objc_read_int(stream, va_arg (args, int*));
1335 break;
1337 case _C_UINT:
1338 res = objc_read_unsigned_int(stream, va_arg (args, unsigned int*));
1339 break;
1341 case _C_LNG:
1342 res = objc_read_long(stream, va_arg (args, long*));
1343 break;
1345 case _C_ULNG:
1346 res = objc_read_unsigned_long(stream, va_arg (args, unsigned long*));
1347 break;
1349 case _C_CHARPTR:
1350 case _C_ATOM:
1352 char **str = va_arg (args, char **);
1353 res = objc_read_string (stream, str);
1355 break;
1357 case _C_ARY_B:
1359 int len = atoi (c + 1);
1360 const char *t = c;
1361 while (isdigit ((unsigned char) *++t))
1363 res = objc_read_array (stream, t, len, va_arg (args, void *));
1364 t = objc_skip_typespec (t);
1365 if (*t != _C_ARY_E)
1366 objc_error (nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t);
1368 break;
1370 default:
1371 objc_error (nil, OBJC_ERR_BAD_TYPE,
1372 "objc_read_types: cannot parse typespec: %s\n", type);
1375 va_end (args);
1376 return res;
1380 ** Write an array of COUNT elements of TYPE from the memory address DATA.
1381 ** This is equivalent of objc_write_type (stream, "[N<type>]", data)
1385 objc_write_array (TypedStream *stream, const char *type,
1386 int count, const void *data)
1388 int off = objc_sizeof_type(type);
1389 const char *where = data;
1391 while (count-- > 0)
1393 objc_write_type(stream, type, where);
1394 where += off;
1396 return 1;
1400 ** Read an array of COUNT elements of TYPE into the memory address
1401 ** DATA. The memory pointed to by data is supposed to be allocated
1402 ** by the callee. This is equivalent of
1403 ** objc_read_type (stream, "[N<type>]", data)
1407 objc_read_array (TypedStream *stream, const char *type,
1408 int count, void *data)
1410 int off = objc_sizeof_type(type);
1411 char *where = (char*)data;
1413 while (count-- > 0)
1415 objc_read_type(stream, type, where);
1416 where += off;
1418 return 1;
1421 static int
1422 __objc_fread (FILE *file, char *data, int len)
1424 return fread(data, len, 1, file);
1427 static int
1428 __objc_fwrite (FILE *file, char *data, int len)
1430 return fwrite(data, len, 1, file);
1433 static int
1434 __objc_feof (FILE *file)
1436 return feof(file);
1439 static int
1440 __objc_no_write (FILE *file __attribute__ ((__unused__)),
1441 const char *data __attribute__ ((__unused__)),
1442 int len __attribute__ ((__unused__)))
1444 objc_error (nil, OBJC_ERR_NO_WRITE, "TypedStream not open for writing");
1445 return 0;
1448 static int
1449 __objc_no_read (FILE *file __attribute__ ((__unused__)),
1450 const char *data __attribute__ ((__unused__)),
1451 int len __attribute__ ((__unused__)))
1453 objc_error (nil, OBJC_ERR_NO_READ, "TypedStream not open for reading");
1454 return 0;
1457 static int
1458 __objc_read_typed_stream_signature (TypedStream *stream)
1460 char buffer[80];
1461 int pos = 0;
1463 (*stream->read) (stream->physical, buffer+pos, 1);
1464 while (buffer[pos++] != '\0')
1466 sscanf (buffer, "GNU TypedStream %d", &stream->version);
1467 if (stream->version != OBJC_TYPED_STREAM_VERSION)
1468 objc_error (nil, OBJC_ERR_STREAM_VERSION,
1469 "cannot handle TypedStream version %d", stream->version);
1470 return 1;
1473 static int
1474 __objc_write_typed_stream_signature (TypedStream *stream)
1476 char buffer[80];
1477 sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
1478 stream->version = OBJC_TYPED_STREAM_VERSION;
1479 (*stream->write) (stream->physical, buffer, strlen (buffer) + 1);
1480 return 1;
1483 static void __objc_finish_write_root_object(struct objc_typed_stream *stream)
1485 objc_hash_delete (stream->object_table);
1486 stream->object_table = objc_hash_new (64,
1487 (hash_func_type) objc_hash_ptr,
1488 (compare_func_type) objc_compare_ptrs);
1491 static void __objc_finish_read_root_object(struct objc_typed_stream *stream)
1493 node_ptr node;
1494 SEL awake_sel = sel_get_any_uid ("awake");
1495 cache_ptr free_list = objc_hash_new (64,
1496 (hash_func_type) objc_hash_ptr,
1497 (compare_func_type) objc_compare_ptrs);
1499 /* resolve object forward references */
1500 for (node = objc_hash_next (stream->object_refs, NULL); node;
1501 node = objc_hash_next (stream->object_refs, node))
1503 struct objc_list *reflist = node->value;
1504 const void *key = node->key;
1505 id object = objc_hash_value_for_key (stream->object_table, key);
1506 while (reflist)
1508 *((id*) reflist->head) = object;
1509 if (objc_hash_value_for_key (free_list,reflist) == NULL)
1510 objc_hash_add (&free_list,reflist,reflist);
1512 reflist = reflist->tail;
1516 /* apply __objc_free to all objects stored in free_list */
1517 for (node = objc_hash_next (free_list, NULL); node;
1518 node = objc_hash_next (free_list, node))
1519 objc_free ((void *) node->key);
1521 objc_hash_delete (free_list);
1523 /* empty object reference table */
1524 objc_hash_delete (stream->object_refs);
1525 stream->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr,
1526 (compare_func_type) objc_compare_ptrs);
1528 /* call -awake for all objects read */
1529 if (awake_sel)
1531 for (node = objc_hash_next (stream->object_table, NULL); node;
1532 node = objc_hash_next (stream->object_table, node))
1534 id object = node->value;
1535 if (__objc_responds_to (object, awake_sel))
1536 (*objc_msg_lookup (object, awake_sel)) (object, awake_sel);
1540 /* empty object table */
1541 objc_hash_delete (stream->object_table);
1542 stream->object_table = objc_hash_new(64,
1543 (hash_func_type)objc_hash_ptr,
1544 (compare_func_type)objc_compare_ptrs);
1548 ** Open the stream PHYSICAL in MODE
1551 TypedStream *
1552 objc_open_typed_stream (FILE *physical, int mode)
1554 TypedStream *s = (TypedStream *) objc_malloc (sizeof (TypedStream));
1556 s->mode = mode;
1557 s->physical = physical;
1558 s->stream_table = objc_hash_new (64,
1559 (hash_func_type) objc_hash_ptr,
1560 (compare_func_type) objc_compare_ptrs);
1561 s->object_table = objc_hash_new (64,
1562 (hash_func_type) objc_hash_ptr,
1563 (compare_func_type) objc_compare_ptrs);
1564 s->eof = (objc_typed_eof_func) __objc_feof;
1565 s->flush = (objc_typed_flush_func) fflush;
1566 s->writing_root_p = 0;
1567 if (mode == OBJC_READONLY)
1569 s->class_table
1570 = objc_hash_new (8, (hash_func_type) objc_hash_string,
1571 (compare_func_type) objc_compare_strings);
1572 s->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr,
1573 (compare_func_type) objc_compare_ptrs);
1574 s->read = (objc_typed_read_func) __objc_fread;
1575 s->write = (objc_typed_write_func) __objc_no_write;
1576 __objc_read_typed_stream_signature (s);
1578 else if (mode == OBJC_WRITEONLY)
1580 s->class_table = 0;
1581 s->object_refs = 0;
1582 s->read = (objc_typed_read_func) __objc_no_read;
1583 s->write = (objc_typed_write_func) __objc_fwrite;
1584 __objc_write_typed_stream_signature (s);
1586 else
1588 objc_close_typed_stream (s);
1589 return NULL;
1591 s->type = OBJC_FILE_STREAM;
1592 return s;
1596 ** Open the file named by FILE_NAME in MODE
1599 TypedStream*
1600 objc_open_typed_stream_for_file (const char *file_name, int mode)
1602 FILE *file = NULL;
1603 TypedStream *s;
1605 if (mode == OBJC_READONLY)
1606 file = fopen (file_name, "r");
1607 else
1608 file = fopen (file_name, "w");
1610 if (file)
1612 s = objc_open_typed_stream (file, mode);
1613 if (s)
1614 s->type |= OBJC_MANAGED_STREAM;
1615 return s;
1617 else
1618 return NULL;
1622 ** Close STREAM freeing the structure it self. If it was opened with
1623 ** objc_open_typed_stream_for_file, the file will also be closed.
1626 void
1627 objc_close_typed_stream (TypedStream *stream)
1629 if (stream->mode == OBJC_READONLY)
1631 __objc_finish_read_root_object (stream); /* Just in case... */
1632 objc_hash_delete (stream->class_table);
1633 objc_hash_delete (stream->object_refs);
1636 objc_hash_delete (stream->stream_table);
1637 objc_hash_delete (stream->object_table);
1639 if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
1640 fclose ((FILE *)stream->physical);
1642 objc_free(stream);
1645 BOOL
1646 objc_end_of_typed_stream (TypedStream *stream)
1648 return (*stream->eof) (stream->physical);
1651 void
1652 objc_flush_typed_stream (TypedStream *stream)
1654 (*stream->flush) (stream->physical);
1657 long
1658 objc_get_stream_class_version (TypedStream *stream, Class class)
1660 if (stream->class_table)
1661 return PTR2LONG(objc_hash_value_for_key (stream->class_table,
1662 class->name));
1663 else
1664 return class_get_version (class);