PR middle-end/25568
[official-gcc.git] / libobjc / archive.c
blob992a69600d4a3295cddd0438cbf4f1a298c9b006
1 /* GNU Objective C Runtime archiving
2 Copyright (C) 1993, 1995, 1996, 1997, 2002, 2004 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 2, 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 You should have received a copy of the GNU General Public License along with
17 GCC; see the file COPYING. If not, write to the Free Software
18 Foundation, 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA. */
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. */
27 #include "tconfig.h"
28 #include "objc/runtime.h"
29 #include "objc/typedstream.h"
30 #include "objc/encoding.h"
31 #include <stdlib.h>
33 extern int fflush (FILE *);
35 #define ROUND(V, A) \
36 ({ typeof (V) __v = (V); typeof (A) __a = (A); \
37 __a * ((__v + __a - 1)/__a); })
39 #define PTR2LONG(P) (((char *) (P))-(char *) 0)
40 #define LONG2PTR(L) (((char *) 0) + (L))
42 /* Declare some functions... */
44 static int
45 objc_read_class (struct objc_typed_stream *stream, Class *class);
47 int objc_sizeof_type (const char *type);
49 static int
50 objc_write_use_common (struct objc_typed_stream *stream, unsigned long key);
52 static int
53 objc_write_register_common (struct objc_typed_stream *stream,
54 unsigned long key);
56 static int
57 objc_write_class (struct objc_typed_stream *stream,
58 struct objc_class *class);
60 const char *objc_skip_type (const char *type);
62 static void __objc_finish_write_root_object (struct objc_typed_stream *);
63 static void __objc_finish_read_root_object (struct objc_typed_stream *);
65 static inline int
66 __objc_code_unsigned_char (unsigned char *buf, unsigned char val)
68 if ((val&_B_VALUE) == val)
70 buf[0] = val|_B_SINT;
71 return 1;
73 else
75 buf[0] = _B_NINT|0x01;
76 buf[1] = val;
77 return 2;
81 int
82 objc_write_unsigned_char (struct objc_typed_stream *stream,
83 unsigned char value)
85 unsigned char buf[sizeof (unsigned char) + 1];
86 int len = __objc_code_unsigned_char (buf, value);
87 return (*stream->write) (stream->physical, (char*)buf, len);
90 static inline int
91 __objc_code_char (unsigned char *buf, signed char val)
93 if (val >= 0)
94 return __objc_code_unsigned_char (buf, val);
95 else
97 buf[0] = _B_NINT|_B_SIGN|0x01;
98 buf[1] = -val;
99 return 2;
104 objc_write_char (struct objc_typed_stream *stream, signed char value)
106 unsigned char buf[sizeof (char) + 1];
107 int len = __objc_code_char (buf, value);
108 return (*stream->write) (stream->physical, (char*)buf, len);
111 static inline int
112 __objc_code_unsigned_short (unsigned char *buf, unsigned short val)
114 if ((val&_B_VALUE) == val)
116 buf[0] = val|_B_SINT;
117 return 1;
119 else
121 int c, b;
123 buf[0] = _B_NINT;
125 for (c = sizeof (short); c != 0; c -= 1)
126 if (((val >> (8*(c - 1)))%0x100) != 0)
127 break;
129 buf[0] |= c;
131 for (b = 1; c != 0; c--, b++)
133 buf[b] = (val >> (8*(c - 1)))%0x100;
136 return b;
141 objc_write_unsigned_short (struct objc_typed_stream *stream,
142 unsigned short value)
144 unsigned char buf[sizeof (unsigned short) + 1];
145 int len = __objc_code_unsigned_short (buf, value);
146 return (*stream->write) (stream->physical, (char*)buf, len);
149 static inline int
150 __objc_code_short (unsigned char *buf, short val)
152 int sign = (val < 0);
153 int size = __objc_code_unsigned_short (buf, sign ? -val : val);
154 if (sign)
155 buf[0] |= _B_SIGN;
156 return size;
160 objc_write_short (struct objc_typed_stream *stream, short value)
162 unsigned char buf[sizeof (short) + 1];
163 int len = __objc_code_short (buf, value);
164 return (*stream->write) (stream->physical, (char*)buf, len);
168 static inline int
169 __objc_code_unsigned_int (unsigned char *buf, unsigned int val)
171 if ((val&_B_VALUE) == val)
173 buf[0] = val|_B_SINT;
174 return 1;
176 else
178 int c, b;
180 buf[0] = _B_NINT;
182 for (c = sizeof (int); c != 0; c -= 1)
183 if (((val >> (8*(c - 1)))%0x100) != 0)
184 break;
186 buf[0] |= c;
188 for (b = 1; c != 0; c--, b++)
190 buf[b] = (val >> (8*(c-1)))%0x100;
193 return b;
198 objc_write_unsigned_int (struct objc_typed_stream *stream, unsigned int value)
200 unsigned char buf[sizeof (unsigned int) + 1];
201 int len = __objc_code_unsigned_int (buf, value);
202 return (*stream->write) (stream->physical, (char*)buf, len);
205 static inline int
206 __objc_code_int (unsigned char *buf, int val)
208 int sign = (val < 0);
209 int size = __objc_code_unsigned_int (buf, sign ? -val : val);
210 if (sign)
211 buf[0] |= _B_SIGN;
212 return size;
216 objc_write_int (struct objc_typed_stream *stream, int value)
218 unsigned char buf[sizeof (int) + 1];
219 int len = __objc_code_int (buf, value);
220 return (*stream->write) (stream->physical, (char*)buf, len);
223 static inline int
224 __objc_code_unsigned_long (unsigned char *buf, unsigned long val)
226 if ((val&_B_VALUE) == val)
228 buf[0] = val|_B_SINT;
229 return 1;
231 else
233 int c, b;
235 buf[0] = _B_NINT;
237 for (c = sizeof (long); c != 0; c -= 1)
238 if (((val >> (8*(c - 1)))%0x100) != 0)
239 break;
241 buf[0] |= c;
243 for (b = 1; c != 0; c--, b++)
245 buf[b] = (val >> (8*(c - 1)))%0x100;
248 return b;
253 objc_write_unsigned_long (struct objc_typed_stream *stream,
254 unsigned long value)
256 unsigned char buf[sizeof (unsigned long) + 1];
257 int len = __objc_code_unsigned_long (buf, value);
258 return (*stream->write) (stream->physical, (char*)buf, len);
261 static inline int
262 __objc_code_long (unsigned char *buf, long val)
264 int sign = (val < 0);
265 int size = __objc_code_unsigned_long (buf, sign ? -val : val);
266 if (sign)
267 buf[0] |= _B_SIGN;
268 return size;
272 objc_write_long (struct objc_typed_stream *stream, long value)
274 unsigned char buf[sizeof (long) + 1];
275 int len = __objc_code_long (buf, value);
276 return (*stream->write) (stream->physical, (char*)buf, len);
281 objc_write_string (struct objc_typed_stream *stream,
282 const unsigned char *string, unsigned int nbytes)
284 unsigned char buf[sizeof (unsigned int) + 1];
285 int len = __objc_code_unsigned_int (buf, nbytes);
287 if ((buf[0]&_B_CODE) == _B_SINT)
288 buf[0] = (buf[0]&_B_VALUE)|_B_SSTR;
290 else /* _B_NINT */
291 buf[0] = (buf[0]&_B_VALUE)|_B_NSTR;
293 if ((*stream->write) (stream->physical, (char*)buf, len) != 0)
294 return (*stream->write) (stream->physical, (char*)string, nbytes);
295 else
296 return 0;
300 objc_write_string_atomic (struct objc_typed_stream *stream,
301 unsigned char *string, unsigned int nbytes)
303 unsigned long key;
304 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, string))))
305 return objc_write_use_common (stream, key);
306 else
308 int length;
309 objc_hash_add (&stream->stream_table,
310 LONG2PTR(key=PTR2LONG(string)), string);
311 if ((length = objc_write_register_common (stream, key)))
312 return objc_write_string (stream, string, nbytes);
313 return length;
317 static int
318 objc_write_register_common (struct objc_typed_stream *stream,
319 unsigned long key)
321 unsigned char buf[sizeof (unsigned long)+2];
322 int len = __objc_code_unsigned_long (buf + 1, key);
323 if (len == 1)
325 buf[0] = _B_RCOMM|0x01;
326 buf[1] &= _B_VALUE;
327 return (*stream->write) (stream->physical, (char*)buf, len + 1);
329 else
331 buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
332 return (*stream->write) (stream->physical, (char*)buf + 1, len);
336 static int
337 objc_write_use_common (struct objc_typed_stream *stream, unsigned long key)
339 unsigned char buf[sizeof (unsigned long)+2];
340 int len = __objc_code_unsigned_long (buf + 1, key);
341 if (len == 1)
343 buf[0] = _B_UCOMM|0x01;
344 buf[1] &= _B_VALUE;
345 return (*stream->write) (stream->physical, (char*)buf, 2);
347 else
349 buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
350 return (*stream->write) (stream->physical, (char*)buf + 1, len);
354 static inline int
355 __objc_write_extension (struct objc_typed_stream *stream, unsigned char code)
357 if (code <= _B_VALUE)
359 unsigned char buf = code|_B_EXT;
360 return (*stream->write) (stream->physical, (char*)&buf, 1);
362 else
364 objc_error (nil, OBJC_ERR_BAD_OPCODE,
365 "__objc_write_extension: bad opcode %c\n", code);
366 return -1;
370 inline int
371 __objc_write_object (struct objc_typed_stream *stream, id object)
373 unsigned char buf = '\0';
374 SEL write_sel = sel_get_any_uid ("write:");
375 if (object)
377 __objc_write_extension (stream, _BX_OBJECT);
378 objc_write_class (stream, object->class_pointer);
379 (*objc_msg_lookup (object, write_sel)) (object, write_sel, stream);
380 return (*stream->write) (stream->physical, (char*)&buf, 1);
382 else
383 return objc_write_use_common (stream, 0);
386 int
387 objc_write_object_reference (struct objc_typed_stream *stream, id object)
389 unsigned long key;
390 if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object))))
391 return objc_write_use_common (stream, key);
393 __objc_write_extension (stream, _BX_OBJREF);
394 return objc_write_unsigned_long (stream, PTR2LONG (object));
397 int
398 objc_write_root_object (struct objc_typed_stream *stream, id object)
400 int len = 0;
401 if (stream->writing_root_p)
402 objc_error (nil, OBJC_ERR_RECURSE_ROOT,
403 "objc_write_root_object called recursively");
404 else
406 stream->writing_root_p = 1;
407 __objc_write_extension (stream, _BX_OBJROOT);
408 if ((len = objc_write_object (stream, object)))
409 __objc_finish_write_root_object (stream);
410 stream->writing_root_p = 0;
412 return len;
415 int
416 objc_write_object (struct objc_typed_stream *stream, id object)
418 unsigned long key;
419 if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object))))
420 return objc_write_use_common (stream, key);
422 else if (object == nil)
423 return objc_write_use_common (stream, 0);
425 else
427 int length;
428 objc_hash_add (&stream->object_table,
429 LONG2PTR(key=PTR2LONG(object)), object);
430 if ((length = objc_write_register_common (stream, key)))
431 return __objc_write_object (stream, object);
432 return length;
436 inline int
437 __objc_write_class (struct objc_typed_stream *stream, struct objc_class *class)
439 __objc_write_extension (stream, _BX_CLASS);
440 objc_write_string_atomic (stream, (unsigned char *) class->name,
441 strlen ((char *) class->name));
442 return objc_write_unsigned_long (stream, class->version);
446 static int
447 objc_write_class (struct objc_typed_stream *stream,
448 struct objc_class *class)
450 unsigned long key;
451 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, class))))
452 return objc_write_use_common (stream, key);
453 else
455 int length;
456 objc_hash_add (&stream->stream_table,
457 LONG2PTR(key = PTR2LONG(class)), class);
458 if ((length = objc_write_register_common (stream, key)))
459 return __objc_write_class (stream, class);
460 return length;
465 inline int
466 __objc_write_selector (struct objc_typed_stream *stream, SEL selector)
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, (unsigned char*)"", 0);
473 sel_name = sel_get_name (selector);
474 return objc_write_string (stream, (unsigned char*)sel_name, strlen ((char*)sel_name));
477 int
478 objc_write_selector (struct objc_typed_stream *stream, SEL selector)
480 const char *sel_name;
481 unsigned long key;
483 /* to handle NULL selectors */
484 if ((SEL)0 == selector)
485 return __objc_write_selector (stream, selector);
487 sel_name = sel_get_name (selector);
488 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table,
489 sel_name))))
490 return objc_write_use_common (stream, key);
491 else
493 int length;
494 objc_hash_add (&stream->stream_table,
495 LONG2PTR(key = PTR2LONG(sel_name)), (char *) sel_name);
496 if ((length = objc_write_register_common (stream, key)))
497 return __objc_write_selector (stream, selector);
498 return length;
505 ** Read operations
508 inline int
509 objc_read_char (struct objc_typed_stream *stream, char *val)
511 unsigned char buf;
512 int len;
513 len = (*stream->read) (stream->physical, (char*)&buf, 1);
514 if (len != 0)
516 if ((buf & _B_CODE) == _B_SINT)
517 (*val) = (buf & _B_VALUE);
519 else if ((buf & _B_NUMBER) == 1)
521 len = (*stream->read) (stream->physical, val, 1);
522 if (buf&_B_SIGN)
523 (*val) = -1 * (*val);
526 else
527 objc_error (nil, OBJC_ERR_BAD_DATA,
528 "expected 8bit signed int, got %dbit int",
529 (int) (buf&_B_NUMBER)*8);
531 return len;
535 inline int
536 objc_read_unsigned_char (struct objc_typed_stream *stream, unsigned char *val)
538 unsigned char buf;
539 int len;
540 if ((len = (*stream->read) (stream->physical, (char*)&buf, 1)))
542 if ((buf & _B_CODE) == _B_SINT)
543 (*val) = (buf & _B_VALUE);
545 else if ((buf & _B_NUMBER) == 1)
546 len = (*stream->read) (stream->physical, (char*)val, 1);
548 else
549 objc_error (nil, OBJC_ERR_BAD_DATA,
550 "expected 8bit unsigned int, got %dbit int",
551 (int) (buf&_B_NUMBER)*8);
553 return len;
556 inline int
557 objc_read_short (struct objc_typed_stream *stream, short *value)
559 unsigned char buf[sizeof (short) + 1];
560 int len;
561 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
563 if ((buf[0] & _B_CODE) == _B_SINT)
564 (*value) = (buf[0] & _B_VALUE);
566 else
568 int pos = 1;
569 int nbytes = buf[0] & _B_NUMBER;
570 if (nbytes > (int) sizeof (short))
571 objc_error (nil, OBJC_ERR_BAD_DATA,
572 "expected short, got bigger (%dbits)", nbytes*8);
573 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
574 (*value) = 0;
575 while (pos <= nbytes)
576 (*value) = ((*value)*0x100) + buf[pos++];
577 if (buf[0] & _B_SIGN)
578 (*value) = -(*value);
581 return len;
584 inline int
585 objc_read_unsigned_short (struct objc_typed_stream *stream,
586 unsigned short *value)
588 unsigned char buf[sizeof (unsigned short) + 1];
589 int len;
590 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
592 if ((buf[0] & _B_CODE) == _B_SINT)
593 (*value) = (buf[0] & _B_VALUE);
595 else
597 int pos = 1;
598 int nbytes = buf[0] & _B_NUMBER;
599 if (nbytes > (int) sizeof (short))
600 objc_error (nil, OBJC_ERR_BAD_DATA,
601 "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;
612 inline int
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_error (nil, OBJC_ERR_BAD_DATA, "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;
639 inline int
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_error (nil, OBJC_ERR_BAD_DATA, "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;
666 inline int
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_error (nil, OBJC_ERR_BAD_DATA, "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;
685 inline int
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_error (nil, OBJC_ERR_BAD_DATA, "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;
722 inline int
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;
740 inline int
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_error (nil, OBJC_ERR_BAD_DATA,
794 "expected string, got opcode %c\n", (buf[0]&_B_CODE));
798 return len;
803 objc_read_object (struct objc_typed_stream *stream, id *object)
805 unsigned char buf[sizeof (unsigned int)];
806 int len;
807 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
809 SEL read_sel = sel_get_any_uid ("read:");
810 unsigned long key = 0;
812 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */
814 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
815 len = (*stream->read) (stream->physical, (char*)buf, 1);
818 if (buf[0] == (_B_EXT | _BX_OBJECT))
820 Class class;
822 /* get class */
823 len = objc_read_class (stream, &class);
825 /* create instance */
826 (*object) = class_create_instance (class);
828 /* register? */
829 if (key)
830 objc_hash_add (&stream->object_table, LONG2PTR(key), *object);
832 /* send -read: */
833 if (__objc_responds_to (*object, read_sel))
834 (*get_imp (class, read_sel)) (*object, read_sel, stream);
836 /* check null-byte */
837 len = (*stream->read) (stream->physical, (char*)buf, 1);
838 if (buf[0] != '\0')
839 objc_error (nil, OBJC_ERR_BAD_DATA,
840 "expected null-byte, got opcode %c", buf[0]);
843 else if ((buf[0]&_B_CODE) == _B_UCOMM)
845 if (key)
846 objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
847 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
848 (*object) = objc_hash_value_for_key (stream->object_table,
849 LONG2PTR(key));
852 else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */
854 struct objc_list *other;
855 len = objc_read_unsigned_long (stream, &key);
856 other
857 = (struct objc_list *) objc_hash_value_for_key (stream->object_refs,
858 LONG2PTR(key));
859 objc_hash_add (&stream->object_refs, LONG2PTR(key),
860 (void *)list_cons (object, other));
863 else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */
865 if (key)
866 objc_error (nil, OBJC_ERR_BAD_KEY,
867 "cannot register root object...");
868 len = objc_read_object (stream, object);
869 __objc_finish_read_root_object (stream);
872 else
873 objc_error (nil, OBJC_ERR_BAD_DATA,
874 "expected object, got opcode %c", buf[0]);
876 return len;
879 static int
880 objc_read_class (struct objc_typed_stream *stream, Class *class)
882 unsigned char buf[sizeof (unsigned int)];
883 int len;
884 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
886 unsigned long key = 0;
888 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
890 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
891 len = (*stream->read) (stream->physical, (char*)buf, 1);
894 if (buf[0] == (_B_EXT | _BX_CLASS))
896 char temp[1] = "";
897 char *class_name = temp;
898 unsigned long version;
900 /* get class */
901 len = objc_read_string (stream, &class_name);
902 (*class) = objc_get_class (class_name);
903 objc_free (class_name);
905 /* register */
906 if (key)
907 objc_hash_add (&stream->stream_table, LONG2PTR(key), *class);
909 objc_read_unsigned_long (stream, &version);
910 objc_hash_add (&stream->class_table,
911 (*class)->name, (void *)version);
914 else if ((buf[0]&_B_CODE) == _B_UCOMM)
916 if (key)
917 objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
918 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
919 *class = objc_hash_value_for_key (stream->stream_table,
920 LONG2PTR(key));
921 if (! *class)
922 objc_error (nil, OBJC_ERR_BAD_CLASS,
923 "cannot find class for key %lu", key);
926 else
927 objc_error (nil, OBJC_ERR_BAD_DATA,
928 "expected class, got opcode %c", buf[0]);
930 return len;
934 objc_read_selector (struct objc_typed_stream *stream, SEL* selector)
936 unsigned char buf[sizeof (unsigned int)];
937 int len;
938 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
940 unsigned long key = 0;
942 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
944 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
945 len = (*stream->read) (stream->physical, (char*)buf, 1);
948 if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
950 char temp[1] = "";
951 char *selector_name = temp;
953 /* get selector */
954 len = objc_read_string (stream, &selector_name);
955 /* To handle NULL selectors */
956 if (0 == strlen (selector_name))
958 (*selector) = (SEL)0;
959 return 0;
961 else
962 (*selector) = sel_get_any_uid (selector_name);
963 objc_free (selector_name);
965 /* register */
966 if (key)
967 objc_hash_add (&stream->stream_table,
968 LONG2PTR(key), (void *) *selector);
971 else if ((buf[0]&_B_CODE) == _B_UCOMM)
973 if (key)
974 objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
975 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
976 (*selector) = objc_hash_value_for_key (stream->stream_table,
977 LONG2PTR(key));
980 else
981 objc_error (nil, OBJC_ERR_BAD_DATA,
982 "expected selector, got opcode %c", buf[0]);
984 return len;
988 ** USER LEVEL FUNCTIONS
992 ** Write one object, encoded in TYPE and pointed to by DATA to the
993 ** typed stream STREAM.
997 objc_write_type (TypedStream *stream, const char *type, const void *data)
999 switch (*type) {
1000 case _C_ID:
1001 return objc_write_object (stream, *(id *) data);
1002 break;
1004 case _C_CLASS:
1005 return objc_write_class (stream, *(Class *) data);
1006 break;
1008 case _C_SEL:
1009 return objc_write_selector (stream, *(SEL *) data);
1010 break;
1012 case _C_CHR:
1013 return objc_write_char (stream, *(signed char *) data);
1014 break;
1016 case _C_UCHR:
1017 return objc_write_unsigned_char (stream, *(unsigned char *) data);
1018 break;
1020 case _C_SHT:
1021 return objc_write_short (stream, *(short *) data);
1022 break;
1024 case _C_USHT:
1025 return objc_write_unsigned_short (stream, *(unsigned short *) data);
1026 break;
1028 case _C_INT:
1029 return objc_write_int (stream, *(int *) data);
1030 break;
1032 case _C_UINT:
1033 return objc_write_unsigned_int (stream, *(unsigned int *) data);
1034 break;
1036 case _C_LNG:
1037 return objc_write_long (stream, *(long *) data);
1038 break;
1040 case _C_ULNG:
1041 return objc_write_unsigned_long (stream, *(unsigned long *) data);
1042 break;
1044 case _C_CHARPTR:
1045 return objc_write_string (stream,
1046 *(unsigned char **) data, strlen (*(char **) data));
1047 break;
1049 case _C_ATOM:
1050 return objc_write_string_atomic (stream, *(unsigned char **) data,
1051 strlen (*(char **) data));
1052 break;
1054 case _C_ARY_B:
1056 int len = atoi (type + 1);
1057 while (isdigit ((unsigned char) *++type))
1059 return objc_write_array (stream, type, len, data);
1061 break;
1063 case _C_STRUCT_B:
1065 int acc_size = 0;
1066 int align;
1067 while (*type != _C_STRUCT_E && *type++ != '=')
1068 ; /* skip "<name>=" */
1069 while (*type != _C_STRUCT_E)
1071 align = objc_alignof_type (type); /* padd to alignment */
1072 acc_size = ROUND (acc_size, align);
1073 objc_write_type (stream, type, ((char *) data) + acc_size);
1074 acc_size += objc_sizeof_type (type); /* add component size */
1075 type = objc_skip_typespec (type); /* skip component */
1077 return 1;
1080 default:
1082 objc_error (nil, OBJC_ERR_BAD_TYPE,
1083 "objc_write_type: cannot parse typespec: %s\n", type);
1084 return 0;
1090 ** Read one object, encoded in TYPE and pointed to by DATA to the
1091 ** typed stream STREAM. DATA specifies the address of the types to
1092 ** read. Expected type is checked against the type actually present
1093 ** on the stream.
1097 objc_read_type(TypedStream *stream, const char *type, void *data)
1099 char c;
1100 switch (c = *type) {
1101 case _C_ID:
1102 return objc_read_object (stream, (id*)data);
1103 break;
1105 case _C_CLASS:
1106 return objc_read_class (stream, (Class*)data);
1107 break;
1109 case _C_SEL:
1110 return objc_read_selector (stream, (SEL*)data);
1111 break;
1113 case _C_CHR:
1114 return objc_read_char (stream, (char*)data);
1115 break;
1117 case _C_UCHR:
1118 return objc_read_unsigned_char (stream, (unsigned char*)data);
1119 break;
1121 case _C_SHT:
1122 return objc_read_short (stream, (short*)data);
1123 break;
1125 case _C_USHT:
1126 return objc_read_unsigned_short (stream, (unsigned short*)data);
1127 break;
1129 case _C_INT:
1130 return objc_read_int (stream, (int*)data);
1131 break;
1133 case _C_UINT:
1134 return objc_read_unsigned_int (stream, (unsigned int*)data);
1135 break;
1137 case _C_LNG:
1138 return objc_read_long (stream, (long*)data);
1139 break;
1141 case _C_ULNG:
1142 return objc_read_unsigned_long (stream, (unsigned long*)data);
1143 break;
1145 case _C_CHARPTR:
1146 case _C_ATOM:
1147 return objc_read_string (stream, (char**)data);
1148 break;
1150 case _C_ARY_B:
1152 int len = atoi (type + 1);
1153 while (isdigit ((unsigned char) *++type))
1155 return objc_read_array (stream, type, len, data);
1157 break;
1159 case _C_STRUCT_B:
1161 int acc_size = 0;
1162 int align;
1163 while (*type != _C_STRUCT_E && *type++ != '=')
1164 ; /* skip "<name>=" */
1165 while (*type != _C_STRUCT_E)
1167 align = objc_alignof_type (type); /* padd to alignment */
1168 acc_size = ROUND (acc_size, align);
1169 objc_read_type (stream, type, ((char*)data)+acc_size);
1170 acc_size += objc_sizeof_type (type); /* add component size */
1171 type = objc_skip_typespec (type); /* skip component */
1173 return 1;
1176 default:
1178 objc_error (nil, OBJC_ERR_BAD_TYPE,
1179 "objc_read_type: cannot parse typespec: %s\n", type);
1180 return 0;
1186 ** Write the object specified by the template TYPE to STREAM. Last
1187 ** arguments specify addresses of values to be written. It might
1188 ** seem surprising to specify values by address, but this is extremely
1189 ** convenient for copy-paste with objc_read_types calls. A more
1190 ** down-to-the-earth cause for this passing of addresses is that values
1191 ** of arbitrary size is not well supported in ANSI C for functions with
1192 ** variable number of arguments.
1195 int
1196 objc_write_types (TypedStream *stream, const char *type, ...)
1198 va_list args;
1199 const char *c;
1200 int res = 0;
1202 va_start(args, type);
1204 for (c = type; *c; c = objc_skip_typespec (c))
1206 switch (*c) {
1207 case _C_ID:
1208 res = objc_write_object (stream, *va_arg (args, id*));
1209 break;
1211 case _C_CLASS:
1212 res = objc_write_class (stream, *va_arg (args, Class*));
1213 break;
1215 case _C_SEL:
1216 res = objc_write_selector (stream, *va_arg (args, SEL*));
1217 break;
1219 case _C_CHR:
1220 res = objc_write_char (stream, *va_arg (args, char*));
1221 break;
1223 case _C_UCHR:
1224 res = objc_write_unsigned_char (stream,
1225 *va_arg (args, unsigned char*));
1226 break;
1228 case _C_SHT:
1229 res = objc_write_short (stream, *va_arg (args, short*));
1230 break;
1232 case _C_USHT:
1233 res = objc_write_unsigned_short (stream,
1234 *va_arg (args, unsigned short*));
1235 break;
1237 case _C_INT:
1238 res = objc_write_int(stream, *va_arg (args, int*));
1239 break;
1241 case _C_UINT:
1242 res = objc_write_unsigned_int(stream, *va_arg (args, unsigned int*));
1243 break;
1245 case _C_LNG:
1246 res = objc_write_long(stream, *va_arg (args, long*));
1247 break;
1249 case _C_ULNG:
1250 res = objc_write_unsigned_long(stream, *va_arg (args, unsigned long*));
1251 break;
1253 case _C_CHARPTR:
1255 unsigned char **str = va_arg (args, unsigned char **);
1256 res = objc_write_string (stream, *str, strlen ((char*)*str));
1258 break;
1260 case _C_ATOM:
1262 unsigned char **str = va_arg (args, unsigned char **);
1263 res = objc_write_string_atomic (stream, *str, strlen ((char*)*str));
1265 break;
1267 case _C_ARY_B:
1269 int len = atoi (c + 1);
1270 const char *t = c;
1271 while (isdigit ((unsigned char) *++t))
1273 res = objc_write_array (stream, t, len, va_arg (args, void *));
1274 t = objc_skip_typespec (t);
1275 if (*t != _C_ARY_E)
1276 objc_error (nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t);
1278 break;
1280 default:
1281 objc_error (nil, OBJC_ERR_BAD_TYPE,
1282 "objc_write_types: cannot parse typespec: %s\n", type);
1285 va_end(args);
1286 return res;
1291 ** Last arguments specify addresses of values to be read. Expected
1292 ** type is checked against the type actually present on the stream.
1295 int
1296 objc_read_types(TypedStream *stream, const char *type, ...)
1298 va_list args;
1299 const char *c;
1300 int res = 0;
1302 va_start (args, type);
1304 for (c = type; *c; c = objc_skip_typespec(c))
1306 switch (*c) {
1307 case _C_ID:
1308 res = objc_read_object(stream, va_arg (args, id*));
1309 break;
1311 case _C_CLASS:
1312 res = objc_read_class(stream, va_arg (args, Class*));
1313 break;
1315 case _C_SEL:
1316 res = objc_read_selector(stream, va_arg (args, SEL*));
1317 break;
1319 case _C_CHR:
1320 res = objc_read_char(stream, va_arg (args, char*));
1321 break;
1323 case _C_UCHR:
1324 res = objc_read_unsigned_char(stream, va_arg (args, unsigned char*));
1325 break;
1327 case _C_SHT:
1328 res = objc_read_short(stream, va_arg (args, short*));
1329 break;
1331 case _C_USHT:
1332 res = objc_read_unsigned_short(stream, va_arg (args, unsigned short*));
1333 break;
1335 case _C_INT:
1336 res = objc_read_int(stream, va_arg (args, int*));
1337 break;
1339 case _C_UINT:
1340 res = objc_read_unsigned_int(stream, va_arg (args, unsigned int*));
1341 break;
1343 case _C_LNG:
1344 res = objc_read_long(stream, va_arg (args, long*));
1345 break;
1347 case _C_ULNG:
1348 res = objc_read_unsigned_long(stream, va_arg (args, unsigned long*));
1349 break;
1351 case _C_CHARPTR:
1352 case _C_ATOM:
1354 char **str = va_arg (args, char **);
1355 res = objc_read_string (stream, str);
1357 break;
1359 case _C_ARY_B:
1361 int len = atoi (c + 1);
1362 const char *t = c;
1363 while (isdigit ((unsigned char) *++t))
1365 res = objc_read_array (stream, t, len, va_arg (args, void *));
1366 t = objc_skip_typespec (t);
1367 if (*t != _C_ARY_E)
1368 objc_error (nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t);
1370 break;
1372 default:
1373 objc_error (nil, OBJC_ERR_BAD_TYPE,
1374 "objc_read_types: cannot parse typespec: %s\n", type);
1377 va_end (args);
1378 return res;
1382 ** Write an array of COUNT elements of TYPE from the memory address DATA.
1383 ** This is equivalent of objc_write_type (stream, "[N<type>]", data)
1387 objc_write_array (TypedStream *stream, const char *type,
1388 int count, const void *data)
1390 int off = objc_sizeof_type(type);
1391 const char *where = data;
1393 while (count-- > 0)
1395 objc_write_type(stream, type, where);
1396 where += off;
1398 return 1;
1402 ** Read an array of COUNT elements of TYPE into the memory address
1403 ** DATA. The memory pointed to by data is supposed to be allocated
1404 ** by the callee. This is equivalent of
1405 ** objc_read_type (stream, "[N<type>]", data)
1409 objc_read_array (TypedStream *stream, const char *type,
1410 int count, void *data)
1412 int off = objc_sizeof_type(type);
1413 char *where = (char*)data;
1415 while (count-- > 0)
1417 objc_read_type(stream, type, where);
1418 where += off;
1420 return 1;
1423 static int
1424 __objc_fread (FILE *file, char *data, int len)
1426 return fread(data, len, 1, file);
1429 static int
1430 __objc_fwrite (FILE *file, char *data, int len)
1432 return fwrite(data, len, 1, file);
1435 static int
1436 __objc_feof (FILE *file)
1438 return feof(file);
1441 static int
1442 __objc_no_write (FILE *file __attribute__ ((__unused__)),
1443 const char *data __attribute__ ((__unused__)),
1444 int len __attribute__ ((__unused__)))
1446 objc_error (nil, OBJC_ERR_NO_WRITE, "TypedStream not open for writing");
1447 return 0;
1450 static int
1451 __objc_no_read (FILE *file __attribute__ ((__unused__)),
1452 const char *data __attribute__ ((__unused__)),
1453 int len __attribute__ ((__unused__)))
1455 objc_error (nil, OBJC_ERR_NO_READ, "TypedStream not open for reading");
1456 return 0;
1459 static int
1460 __objc_read_typed_stream_signature (TypedStream *stream)
1462 char buffer[80];
1463 int pos = 0;
1465 (*stream->read) (stream->physical, buffer+pos, 1);
1466 while (buffer[pos++] != '\0')
1468 sscanf (buffer, "GNU TypedStream %d", &stream->version);
1469 if (stream->version != OBJC_TYPED_STREAM_VERSION)
1470 objc_error (nil, OBJC_ERR_STREAM_VERSION,
1471 "cannot handle TypedStream version %d", stream->version);
1472 return 1;
1475 static int
1476 __objc_write_typed_stream_signature (TypedStream *stream)
1478 char buffer[80];
1479 sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
1480 stream->version = OBJC_TYPED_STREAM_VERSION;
1481 (*stream->write) (stream->physical, buffer, strlen (buffer) + 1);
1482 return 1;
1485 static void __objc_finish_write_root_object(struct objc_typed_stream *stream)
1487 objc_hash_delete (stream->object_table);
1488 stream->object_table = objc_hash_new (64,
1489 (hash_func_type) objc_hash_ptr,
1490 (compare_func_type) objc_compare_ptrs);
1493 static void __objc_finish_read_root_object(struct objc_typed_stream *stream)
1495 node_ptr node;
1496 SEL awake_sel = sel_get_any_uid ("awake");
1497 cache_ptr free_list = objc_hash_new (64,
1498 (hash_func_type) objc_hash_ptr,
1499 (compare_func_type) objc_compare_ptrs);
1501 /* resolve object forward references */
1502 for (node = objc_hash_next (stream->object_refs, NULL); node;
1503 node = objc_hash_next (stream->object_refs, node))
1505 struct objc_list *reflist = node->value;
1506 const void *key = node->key;
1507 id object = objc_hash_value_for_key (stream->object_table, key);
1508 while (reflist)
1510 *((id*) reflist->head) = object;
1511 if (objc_hash_value_for_key (free_list,reflist) == NULL)
1512 objc_hash_add (&free_list,reflist,reflist);
1514 reflist = reflist->tail;
1518 /* apply __objc_free to all objects stored in free_list */
1519 for (node = objc_hash_next (free_list, NULL); node;
1520 node = objc_hash_next (free_list, node))
1521 objc_free ((void *) node->key);
1523 objc_hash_delete (free_list);
1525 /* empty object reference table */
1526 objc_hash_delete (stream->object_refs);
1527 stream->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr,
1528 (compare_func_type) objc_compare_ptrs);
1530 /* call -awake for all objects read */
1531 if (awake_sel)
1533 for (node = objc_hash_next (stream->object_table, NULL); node;
1534 node = objc_hash_next (stream->object_table, node))
1536 id object = node->value;
1537 if (__objc_responds_to (object, awake_sel))
1538 (*objc_msg_lookup (object, awake_sel)) (object, awake_sel);
1542 /* empty object table */
1543 objc_hash_delete (stream->object_table);
1544 stream->object_table = objc_hash_new(64,
1545 (hash_func_type)objc_hash_ptr,
1546 (compare_func_type)objc_compare_ptrs);
1550 ** Open the stream PHYSICAL in MODE
1553 TypedStream *
1554 objc_open_typed_stream (FILE *physical, int mode)
1556 TypedStream *s = (TypedStream *) objc_malloc (sizeof (TypedStream));
1558 s->mode = mode;
1559 s->physical = physical;
1560 s->stream_table = objc_hash_new (64,
1561 (hash_func_type) objc_hash_ptr,
1562 (compare_func_type) objc_compare_ptrs);
1563 s->object_table = objc_hash_new (64,
1564 (hash_func_type) objc_hash_ptr,
1565 (compare_func_type) objc_compare_ptrs);
1566 s->eof = (objc_typed_eof_func) __objc_feof;
1567 s->flush = (objc_typed_flush_func) fflush;
1568 s->writing_root_p = 0;
1569 if (mode == OBJC_READONLY)
1571 s->class_table
1572 = objc_hash_new (8, (hash_func_type) objc_hash_string,
1573 (compare_func_type) objc_compare_strings);
1574 s->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr,
1575 (compare_func_type) objc_compare_ptrs);
1576 s->read = (objc_typed_read_func) __objc_fread;
1577 s->write = (objc_typed_write_func) __objc_no_write;
1578 __objc_read_typed_stream_signature (s);
1580 else if (mode == OBJC_WRITEONLY)
1582 s->class_table = 0;
1583 s->object_refs = 0;
1584 s->read = (objc_typed_read_func) __objc_no_read;
1585 s->write = (objc_typed_write_func) __objc_fwrite;
1586 __objc_write_typed_stream_signature (s);
1588 else
1590 objc_close_typed_stream (s);
1591 return NULL;
1593 s->type = OBJC_FILE_STREAM;
1594 return s;
1598 ** Open the file named by FILE_NAME in MODE
1601 TypedStream*
1602 objc_open_typed_stream_for_file (const char *file_name, int mode)
1604 FILE *file = NULL;
1605 TypedStream *s;
1607 if (mode == OBJC_READONLY)
1608 file = fopen (file_name, "r");
1609 else
1610 file = fopen (file_name, "w");
1612 if (file)
1614 s = objc_open_typed_stream (file, mode);
1615 if (s)
1616 s->type |= OBJC_MANAGED_STREAM;
1617 return s;
1619 else
1620 return NULL;
1624 ** Close STREAM freeing the structure it self. If it was opened with
1625 ** objc_open_typed_stream_for_file, the file will also be closed.
1628 void
1629 objc_close_typed_stream (TypedStream *stream)
1631 if (stream->mode == OBJC_READONLY)
1633 __objc_finish_read_root_object (stream); /* Just in case... */
1634 objc_hash_delete (stream->class_table);
1635 objc_hash_delete (stream->object_refs);
1638 objc_hash_delete (stream->stream_table);
1639 objc_hash_delete (stream->object_table);
1641 if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
1642 fclose ((FILE *)stream->physical);
1644 objc_free(stream);
1647 BOOL
1648 objc_end_of_typed_stream (TypedStream *stream)
1650 return (*stream->eof) (stream->physical);
1653 void
1654 objc_flush_typed_stream (TypedStream *stream)
1656 (*stream->flush) (stream->physical);
1659 long
1660 objc_get_stream_class_version (TypedStream *stream, Class class)
1662 if (stream->class_table)
1663 return PTR2LONG(objc_hash_value_for_key (stream->class_table,
1664 class->name));
1665 else
1666 return class_get_version (class);