* doc/tm.texi.in (HANDLE_SYSV_PRAGMA,
[official-gcc.git] / libobjc / archive.c
blobb539ca1163ed928f0e5e5d619e259c8576a2a8f7
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 /* This file is entirely deprecated and will be removed. */
27 #include "objc-private/common.h"
28 #include "objc-private/error.h"
29 #include "tconfig.h"
30 #include "objc/objc-api.h"
31 #include "objc/hash.h"
32 #include "objc/objc-list.h"
33 #include "objc-private/runtime.h"
34 #include "objc/typedstream.h"
35 #include "objc/encoding.h"
36 #include <stdlib.h>
38 extern int fflush (FILE *);
40 #define ROUND(V, A) \
41 ({ typeof (V) __v = (V); typeof (A) __a = (A); \
42 __a * ((__v + __a - 1)/__a); })
44 #define PTR2LONG(P) (((char *) (P))-(char *) 0)
45 #define LONG2PTR(L) (((char *) 0) + (L))
47 /* Declare some functions... */
49 static int
50 objc_read_class (struct objc_typed_stream *stream, Class *class);
52 int objc_sizeof_type (const char *type);
54 static int
55 objc_write_use_common (struct objc_typed_stream *stream, unsigned long key);
57 static int
58 objc_write_register_common (struct objc_typed_stream *stream,
59 unsigned long key);
61 static int
62 objc_write_class (struct objc_typed_stream *stream,
63 struct objc_class *class);
65 const char *objc_skip_type (const char *type);
67 static void __objc_finish_write_root_object (struct objc_typed_stream *);
68 static void __objc_finish_read_root_object (struct objc_typed_stream *);
70 static inline int
71 __objc_code_unsigned_char (unsigned char *buf, unsigned char val)
73 if ((val&_B_VALUE) == val)
75 buf[0] = val|_B_SINT;
76 return 1;
78 else
80 buf[0] = _B_NINT|0x01;
81 buf[1] = val;
82 return 2;
86 int
87 objc_write_unsigned_char (struct objc_typed_stream *stream,
88 unsigned char value)
90 unsigned char buf[sizeof (unsigned char) + 1];
91 int len = __objc_code_unsigned_char (buf, value);
92 return (*stream->write) (stream->physical, (char*)buf, len);
95 static inline int
96 __objc_code_char (unsigned char *buf, signed char val)
98 if (val >= 0)
99 return __objc_code_unsigned_char (buf, val);
100 else
102 buf[0] = _B_NINT|_B_SIGN|0x01;
103 buf[1] = -val;
104 return 2;
109 objc_write_char (struct objc_typed_stream *stream, signed char value)
111 unsigned char buf[sizeof (char) + 1];
112 int len = __objc_code_char (buf, value);
113 return (*stream->write) (stream->physical, (char*)buf, len);
116 static inline int
117 __objc_code_unsigned_short (unsigned char *buf, unsigned short val)
119 if ((val&_B_VALUE) == val)
121 buf[0] = val|_B_SINT;
122 return 1;
124 else
126 int c, b;
128 buf[0] = _B_NINT;
130 for (c = sizeof (short); c != 0; c -= 1)
131 if (((val >> (8*(c - 1)))%0x100) != 0)
132 break;
134 buf[0] |= c;
136 for (b = 1; c != 0; c--, b++)
138 buf[b] = (val >> (8*(c - 1)))%0x100;
141 return b;
146 objc_write_unsigned_short (struct objc_typed_stream *stream,
147 unsigned short value)
149 unsigned char buf[sizeof (unsigned short) + 1];
150 int len = __objc_code_unsigned_short (buf, value);
151 return (*stream->write) (stream->physical, (char*)buf, len);
154 static inline int
155 __objc_code_short (unsigned char *buf, short val)
157 int sign = (val < 0);
158 int size = __objc_code_unsigned_short (buf, sign ? -val : val);
159 if (sign)
160 buf[0] |= _B_SIGN;
161 return size;
165 objc_write_short (struct objc_typed_stream *stream, short value)
167 unsigned char buf[sizeof (short) + 1];
168 int len = __objc_code_short (buf, value);
169 return (*stream->write) (stream->physical, (char*)buf, len);
173 static inline int
174 __objc_code_unsigned_int (unsigned char *buf, unsigned int val)
176 if ((val&_B_VALUE) == val)
178 buf[0] = val|_B_SINT;
179 return 1;
181 else
183 int c, b;
185 buf[0] = _B_NINT;
187 for (c = sizeof (int); c != 0; c -= 1)
188 if (((val >> (8*(c - 1)))%0x100) != 0)
189 break;
191 buf[0] |= c;
193 for (b = 1; c != 0; c--, b++)
195 buf[b] = (val >> (8*(c-1)))%0x100;
198 return b;
203 objc_write_unsigned_int (struct objc_typed_stream *stream, unsigned int value)
205 unsigned char buf[sizeof (unsigned int) + 1];
206 int len = __objc_code_unsigned_int (buf, value);
207 return (*stream->write) (stream->physical, (char*)buf, len);
210 static inline int
211 __objc_code_int (unsigned char *buf, int val)
213 int sign = (val < 0);
214 int size = __objc_code_unsigned_int (buf, sign ? -val : val);
215 if (sign)
216 buf[0] |= _B_SIGN;
217 return size;
221 objc_write_int (struct objc_typed_stream *stream, int value)
223 unsigned char buf[sizeof (int) + 1];
224 int len = __objc_code_int (buf, value);
225 return (*stream->write) (stream->physical, (char*)buf, len);
228 static inline int
229 __objc_code_unsigned_long (unsigned char *buf, unsigned long val)
231 if ((val&_B_VALUE) == val)
233 buf[0] = val|_B_SINT;
234 return 1;
236 else
238 int c, b;
240 buf[0] = _B_NINT;
242 for (c = sizeof (long); c != 0; c -= 1)
243 if (((val >> (8*(c - 1)))%0x100) != 0)
244 break;
246 buf[0] |= c;
248 for (b = 1; c != 0; c--, b++)
250 buf[b] = (val >> (8*(c - 1)))%0x100;
253 return b;
258 objc_write_unsigned_long (struct objc_typed_stream *stream,
259 unsigned long value)
261 unsigned char buf[sizeof (unsigned long) + 1];
262 int len = __objc_code_unsigned_long (buf, value);
263 return (*stream->write) (stream->physical, (char*)buf, len);
266 static inline int
267 __objc_code_long (unsigned char *buf, long val)
269 int sign = (val < 0);
270 int size = __objc_code_unsigned_long (buf, sign ? -val : val);
271 if (sign)
272 buf[0] |= _B_SIGN;
273 return size;
277 objc_write_long (struct objc_typed_stream *stream, long value)
279 unsigned char buf[sizeof (long) + 1];
280 int len = __objc_code_long (buf, value);
281 return (*stream->write) (stream->physical, (char*)buf, len);
286 objc_write_string (struct objc_typed_stream *stream,
287 const unsigned char *string, unsigned int nbytes)
289 unsigned char buf[sizeof (unsigned int) + 1];
290 int len = __objc_code_unsigned_int (buf, nbytes);
292 if ((buf[0]&_B_CODE) == _B_SINT)
293 buf[0] = (buf[0]&_B_VALUE)|_B_SSTR;
295 else /* _B_NINT */
296 buf[0] = (buf[0]&_B_VALUE)|_B_NSTR;
298 if ((*stream->write) (stream->physical, (char*)buf, len) != 0)
299 return (*stream->write) (stream->physical, (char*)string, nbytes);
300 else
301 return 0;
305 objc_write_string_atomic (struct objc_typed_stream *stream,
306 unsigned char *string, unsigned int nbytes)
308 unsigned long key;
309 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, string))))
310 return objc_write_use_common (stream, key);
311 else
313 int length;
314 objc_hash_add (&stream->stream_table,
315 LONG2PTR(key=PTR2LONG(string)), string);
316 if ((length = objc_write_register_common (stream, key)))
317 return objc_write_string (stream, string, nbytes);
318 return length;
322 static int
323 objc_write_register_common (struct objc_typed_stream *stream,
324 unsigned long key)
326 unsigned char buf[sizeof (unsigned long)+2];
327 int len = __objc_code_unsigned_long (buf + 1, key);
328 if (len == 1)
330 buf[0] = _B_RCOMM|0x01;
331 buf[1] &= _B_VALUE;
332 return (*stream->write) (stream->physical, (char*)buf, len + 1);
334 else
336 buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
337 return (*stream->write) (stream->physical, (char*)buf + 1, len);
341 static int
342 objc_write_use_common (struct objc_typed_stream *stream, unsigned long key)
344 unsigned char buf[sizeof (unsigned long)+2];
345 int len = __objc_code_unsigned_long (buf + 1, key);
346 if (len == 1)
348 buf[0] = _B_UCOMM|0x01;
349 buf[1] &= _B_VALUE;
350 return (*stream->write) (stream->physical, (char*)buf, 2);
352 else
354 buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
355 return (*stream->write) (stream->physical, (char*)buf + 1, len);
359 static inline int
360 __objc_write_extension (struct objc_typed_stream *stream, unsigned char code)
362 if (code <= _B_VALUE)
364 unsigned char buf = code|_B_EXT;
365 return (*stream->write) (stream->physical, (char*)&buf, 1);
367 else
369 _objc_abort ("__objc_write_extension: bad opcode %c\n", code);
370 return -1;
375 __objc_write_object (struct objc_typed_stream *stream, id object)
377 unsigned char buf = '\0';
378 SEL write_sel = sel_get_any_uid ("write:");
379 if (object)
381 __objc_write_extension (stream, _BX_OBJECT);
382 objc_write_class (stream, object->class_pointer);
383 (*objc_msg_lookup (object, write_sel)) (object, write_sel, stream);
384 return (*stream->write) (stream->physical, (char*)&buf, 1);
386 else
387 return objc_write_use_common (stream, 0);
390 int
391 objc_write_object_reference (struct objc_typed_stream *stream, id object)
393 unsigned long key;
394 if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object))))
395 return objc_write_use_common (stream, key);
397 __objc_write_extension (stream, _BX_OBJREF);
398 return objc_write_unsigned_long (stream, PTR2LONG (object));
401 int
402 objc_write_root_object (struct objc_typed_stream *stream, id object)
404 int len = 0;
405 if (stream->writing_root_p)
406 _objc_abort ("objc_write_root_object called recursively");
407 else
409 stream->writing_root_p = 1;
410 __objc_write_extension (stream, _BX_OBJROOT);
411 if ((len = objc_write_object (stream, object)))
412 __objc_finish_write_root_object (stream);
413 stream->writing_root_p = 0;
415 return len;
418 int
419 objc_write_object (struct objc_typed_stream *stream, id object)
421 unsigned long key;
422 if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object))))
423 return objc_write_use_common (stream, key);
425 else if (object == nil)
426 return objc_write_use_common (stream, 0);
428 else
430 int length;
431 objc_hash_add (&stream->object_table,
432 LONG2PTR(key=PTR2LONG(object)), object);
433 if ((length = objc_write_register_common (stream, key)))
434 return __objc_write_object (stream, object);
435 return length;
440 __objc_write_class (struct objc_typed_stream *stream, struct objc_class *class)
442 __objc_write_extension (stream, _BX_CLASS);
443 objc_write_string_atomic (stream, (unsigned char *) class->name,
444 strlen ((char *) class->name));
445 return objc_write_unsigned_long (stream, class->version);
449 static int
450 objc_write_class (struct objc_typed_stream *stream,
451 struct objc_class *class)
453 unsigned long key;
454 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, class))))
455 return objc_write_use_common (stream, key);
456 else
458 int length;
459 objc_hash_add (&stream->stream_table,
460 LONG2PTR(key = PTR2LONG(class)), class);
461 if ((length = objc_write_register_common (stream, key)))
462 return __objc_write_class (stream, class);
463 return length;
468 int
469 __objc_write_selector (struct objc_typed_stream *stream, SEL selector)
471 const char *sel_name;
472 __objc_write_extension (stream, _BX_SEL);
473 /* to handle NULL selectors */
474 if ((SEL)0 == selector)
475 return objc_write_string (stream, (unsigned char*)"", 0);
476 sel_name = sel_get_name (selector);
477 return objc_write_string (stream, (unsigned char*)sel_name, strlen ((char*)sel_name));
480 int
481 objc_write_selector (struct objc_typed_stream *stream, SEL selector)
483 const char *sel_name;
484 unsigned long key;
486 /* to handle NULL selectors */
487 if ((SEL)0 == selector)
488 return __objc_write_selector (stream, selector);
490 sel_name = sel_get_name (selector);
491 if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table,
492 sel_name))))
493 return objc_write_use_common (stream, key);
494 else
496 int length;
497 objc_hash_add (&stream->stream_table,
498 LONG2PTR(key = PTR2LONG(sel_name)), (char *) sel_name);
499 if ((length = objc_write_register_common (stream, key)))
500 return __objc_write_selector (stream, selector);
501 return length;
508 ** Read operations
512 objc_read_char (struct objc_typed_stream *stream, char *val)
514 unsigned char buf;
515 int len;
516 len = (*stream->read) (stream->physical, (char*)&buf, 1);
517 if (len != 0)
519 if ((buf & _B_CODE) == _B_SINT)
520 (*val) = (buf & _B_VALUE);
522 else if ((buf & _B_NUMBER) == 1)
524 len = (*stream->read) (stream->physical, val, 1);
525 if (buf&_B_SIGN)
526 (*val) = -1 * (*val);
529 else
530 _objc_abort ("expected 8bit signed int, got %dbit int",
531 (int) (buf&_B_NUMBER)*8);
533 return len;
538 objc_read_unsigned_char (struct objc_typed_stream *stream, unsigned char *val)
540 unsigned char buf;
541 int len;
542 if ((len = (*stream->read) (stream->physical, (char*)&buf, 1)))
544 if ((buf & _B_CODE) == _B_SINT)
545 (*val) = (buf & _B_VALUE);
547 else if ((buf & _B_NUMBER) == 1)
548 len = (*stream->read) (stream->physical, (char*)val, 1);
550 else
551 _objc_abort ("expected 8bit unsigned int, got %dbit int",
552 (int) (buf&_B_NUMBER)*8);
554 return len;
558 objc_read_short (struct objc_typed_stream *stream, short *value)
560 unsigned char buf[sizeof (short) + 1];
561 int len;
562 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
564 if ((buf[0] & _B_CODE) == _B_SINT)
565 (*value) = (buf[0] & _B_VALUE);
567 else
569 int pos = 1;
570 int nbytes = buf[0] & _B_NUMBER;
571 if (nbytes > (int) sizeof (short))
572 _objc_abort ("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;
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_abort ("expected short, got int or bigger");
601 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
602 (*value) = 0;
603 while (pos <= nbytes)
604 (*value) = ((*value)*0x100) + buf[pos++];
607 return len;
612 objc_read_int (struct objc_typed_stream *stream, int *value)
614 unsigned char buf[sizeof (int) + 1];
615 int len;
616 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
618 if ((buf[0] & _B_CODE) == _B_SINT)
619 (*value) = (buf[0] & _B_VALUE);
621 else
623 int pos = 1;
624 int nbytes = buf[0] & _B_NUMBER;
625 if (nbytes > (int) sizeof (int))
626 _objc_abort ("expected int, got bigger");
627 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
628 (*value) = 0;
629 while (pos <= nbytes)
630 (*value) = ((*value)*0x100) + buf[pos++];
631 if (buf[0] & _B_SIGN)
632 (*value) = -(*value);
635 return len;
639 objc_read_long (struct objc_typed_stream *stream, long *value)
641 unsigned char buf[sizeof (long) + 1];
642 int len;
643 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
645 if ((buf[0] & _B_CODE) == _B_SINT)
646 (*value) = (buf[0] & _B_VALUE);
648 else
650 int pos = 1;
651 int nbytes = buf[0] & _B_NUMBER;
652 if (nbytes > (int) sizeof (long))
653 _objc_abort ("expected long, got bigger");
654 len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes);
655 (*value) = 0;
656 while (pos <= nbytes)
657 (*value) = ((*value)*0x100) + buf[pos++];
658 if (buf[0] & _B_SIGN)
659 (*value) = -(*value);
662 return len;
666 __objc_read_nbyte_uint (struct objc_typed_stream *stream,
667 unsigned int nbytes, unsigned int *val)
669 int len;
670 unsigned int pos = 0;
671 unsigned char buf[sizeof (unsigned int) + 1];
673 if (nbytes > sizeof (int))
674 _objc_abort ("expected int, got bigger");
676 len = (*stream->read) (stream->physical, (char*)buf, nbytes);
677 (*val) = 0;
678 while (pos < nbytes)
679 (*val) = ((*val)*0x100) + buf[pos++];
680 return len;
685 objc_read_unsigned_int (struct objc_typed_stream *stream,
686 unsigned int *value)
688 unsigned char buf[sizeof (unsigned int) + 1];
689 int len;
690 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
692 if ((buf[0] & _B_CODE) == _B_SINT)
693 (*value) = (buf[0] & _B_VALUE);
695 else
696 len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value);
699 return len;
703 __objc_read_nbyte_ulong (struct objc_typed_stream *stream,
704 unsigned int nbytes, unsigned long *val)
706 int len;
707 unsigned int pos = 0;
708 unsigned char buf[sizeof (unsigned long) + 1];
710 if (nbytes > sizeof (long))
711 _objc_abort ("expected long, got bigger");
713 len = (*stream->read) (stream->physical, (char*)buf, nbytes);
714 (*val) = 0;
715 while (pos < nbytes)
716 (*val) = ((*val)*0x100) + buf[pos++];
717 return len;
722 objc_read_unsigned_long (struct objc_typed_stream *stream,
723 unsigned long *value)
725 unsigned char buf[sizeof (unsigned long) + 1];
726 int len;
727 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
729 if ((buf[0] & _B_CODE) == _B_SINT)
730 (*value) = (buf[0] & _B_VALUE);
732 else
733 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value);
736 return len;
740 objc_read_string (struct objc_typed_stream *stream,
741 char **string)
743 unsigned char buf[sizeof (unsigned int) + 1];
744 int len;
745 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
747 unsigned long key = 0;
749 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
751 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
752 len = (*stream->read) (stream->physical, (char*)buf, 1);
755 switch (buf[0]&_B_CODE) {
756 case _B_SSTR:
758 int length = buf[0]&_B_VALUE;
759 (*string) = (char*)objc_malloc (length + 1);
760 if (key)
761 objc_hash_add (&stream->stream_table, LONG2PTR(key), *string);
762 len = (*stream->read) (stream->physical, *string, length);
763 (*string)[length] = '\0';
765 break;
767 case _B_UCOMM:
769 char *tmp;
770 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
771 tmp = objc_hash_value_for_key (stream->stream_table, LONG2PTR (key));
772 *string = objc_malloc (strlen (tmp) + 1);
773 strcpy (*string, tmp);
775 break;
777 case _B_NSTR:
779 unsigned int nbytes = buf[0]&_B_VALUE;
780 len = __objc_read_nbyte_uint (stream, nbytes, &nbytes);
781 if (len) {
782 (*string) = (char*)objc_malloc (nbytes + 1);
783 if (key)
784 objc_hash_add (&stream->stream_table, LONG2PTR(key), *string);
785 len = (*stream->read) (stream->physical, *string, nbytes);
786 (*string)[nbytes] = '\0';
789 break;
791 default:
792 _objc_abort ("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_abort ("expected null-byte, got opcode %c", buf[0]);
840 else if ((buf[0]&_B_CODE) == _B_UCOMM)
842 if (key)
843 _objc_abort ("cannot register use upcode...");
844 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
845 (*object) = objc_hash_value_for_key (stream->object_table,
846 LONG2PTR(key));
849 else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */
851 struct objc_list *other;
852 len = objc_read_unsigned_long (stream, &key);
853 other
854 = (struct objc_list *) objc_hash_value_for_key (stream->object_refs,
855 LONG2PTR(key));
856 objc_hash_add (&stream->object_refs, LONG2PTR(key),
857 (void *)list_cons (object, other));
860 else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */
862 if (key)
863 _objc_abort ("cannot register root object...");
864 len = objc_read_object (stream, object);
865 __objc_finish_read_root_object (stream);
868 else
869 _objc_abort ("expected object, got opcode %c", buf[0]);
871 return len;
874 static int
875 objc_read_class (struct objc_typed_stream *stream, Class *class)
877 unsigned char buf[sizeof (unsigned int)];
878 int len;
879 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
881 unsigned long key = 0;
883 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
885 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
886 len = (*stream->read) (stream->physical, (char*)buf, 1);
889 if (buf[0] == (_B_EXT | _BX_CLASS))
891 char temp[1] = "";
892 char *class_name = temp;
893 unsigned long version;
895 /* get class */
896 len = objc_read_string (stream, &class_name);
897 (*class) = objc_get_class (class_name);
898 objc_free (class_name);
900 /* register */
901 if (key)
902 objc_hash_add (&stream->stream_table, LONG2PTR(key), *class);
904 objc_read_unsigned_long (stream, &version);
905 objc_hash_add (&stream->class_table,
906 (*class)->name, (void *) ((size_t) version));
909 else if ((buf[0]&_B_CODE) == _B_UCOMM)
911 if (key)
912 _objc_abort ("cannot register use upcode...");
913 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
914 *class = objc_hash_value_for_key (stream->stream_table,
915 LONG2PTR(key));
916 if (! *class)
917 _objc_abort ("cannot find class for key %lu", key);
920 else
921 _objc_abort ("expected class, got opcode %c", buf[0]);
923 return len;
927 objc_read_selector (struct objc_typed_stream *stream, SEL* selector)
929 unsigned char buf[sizeof (unsigned int)];
930 int len;
931 if ((len = (*stream->read) (stream->physical, (char*)buf, 1)))
933 unsigned long key = 0;
935 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
937 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
938 len = (*stream->read) (stream->physical, (char*)buf, 1);
941 if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
943 char temp[1] = "";
944 char *selector_name = temp;
946 /* get selector */
947 len = objc_read_string (stream, &selector_name);
948 /* To handle NULL selectors */
949 if (0 == strlen (selector_name))
951 (*selector) = (SEL)0;
952 return 0;
954 else
955 (*selector) = sel_get_any_uid (selector_name);
956 objc_free (selector_name);
958 /* register */
959 if (key)
960 objc_hash_add (&stream->stream_table,
961 LONG2PTR(key), (void *) *selector);
964 else if ((buf[0]&_B_CODE) == _B_UCOMM)
966 if (key)
967 _objc_abort ("cannot register use upcode...");
968 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key);
969 (*selector) = objc_hash_value_for_key (stream->stream_table,
970 LONG2PTR(key));
973 else
974 _objc_abort ("expected selector, got opcode %c", buf[0]);
976 return len;
980 ** USER LEVEL FUNCTIONS
984 ** Write one object, encoded in TYPE and pointed to by DATA to the
985 ** typed stream STREAM.
989 objc_write_type (TypedStream *stream, const char *type, const void *data)
991 switch (*type) {
992 case _C_ID:
993 return objc_write_object (stream, *(id *) data);
994 break;
996 case _C_CLASS:
997 return objc_write_class (stream, *(Class *) data);
998 break;
1000 case _C_SEL:
1001 return objc_write_selector (stream, *(SEL *) data);
1002 break;
1004 case _C_CHR:
1005 return objc_write_char (stream, *(signed char *) data);
1006 break;
1008 case _C_UCHR:
1009 return objc_write_unsigned_char (stream, *(unsigned char *) data);
1010 break;
1012 case _C_SHT:
1013 return objc_write_short (stream, *(short *) data);
1014 break;
1016 case _C_USHT:
1017 return objc_write_unsigned_short (stream, *(unsigned short *) data);
1018 break;
1020 case _C_INT:
1021 return objc_write_int (stream, *(int *) data);
1022 break;
1024 case _C_UINT:
1025 return objc_write_unsigned_int (stream, *(unsigned int *) data);
1026 break;
1028 case _C_LNG:
1029 return objc_write_long (stream, *(long *) data);
1030 break;
1032 case _C_ULNG:
1033 return objc_write_unsigned_long (stream, *(unsigned long *) data);
1034 break;
1036 case _C_CHARPTR:
1037 return objc_write_string (stream,
1038 *(unsigned char **) data, strlen (*(char **) data));
1039 break;
1041 case _C_ATOM:
1042 return objc_write_string_atomic (stream, *(unsigned char **) data,
1043 strlen (*(char **) data));
1044 break;
1046 case _C_ARY_B:
1048 int len = atoi (type + 1);
1049 while (isdigit ((unsigned char) *++type))
1051 return objc_write_array (stream, type, len, data);
1053 break;
1055 case _C_STRUCT_B:
1057 int acc_size = 0;
1058 int align;
1059 while (*type != _C_STRUCT_E && *type++ != '=')
1060 ; /* skip "<name>=" */
1061 while (*type != _C_STRUCT_E)
1063 align = objc_alignof_type (type); /* padd to alignment */
1064 acc_size = ROUND (acc_size, align);
1065 objc_write_type (stream, type, ((char *) data) + acc_size);
1066 acc_size += objc_sizeof_type (type); /* add component size */
1067 type = objc_skip_typespec (type); /* skip component */
1069 return 1;
1072 default:
1074 _objc_abort ("objc_write_type: cannot parse typespec: %s\n", type);
1075 return 0;
1081 ** Read one object, encoded in TYPE and pointed to by DATA to the
1082 ** typed stream STREAM. DATA specifies the address of the types to
1083 ** read. Expected type is checked against the type actually present
1084 ** on the stream.
1088 objc_read_type(TypedStream *stream, const char *type, void *data)
1090 char c;
1091 switch (c = *type) {
1092 case _C_ID:
1093 return objc_read_object (stream, (id*)data);
1094 break;
1096 case _C_CLASS:
1097 return objc_read_class (stream, (Class*)data);
1098 break;
1100 case _C_SEL:
1101 return objc_read_selector (stream, (SEL*)data);
1102 break;
1104 case _C_CHR:
1105 return objc_read_char (stream, (char*)data);
1106 break;
1108 case _C_UCHR:
1109 return objc_read_unsigned_char (stream, (unsigned char*)data);
1110 break;
1112 case _C_SHT:
1113 return objc_read_short (stream, (short*)data);
1114 break;
1116 case _C_USHT:
1117 return objc_read_unsigned_short (stream, (unsigned short*)data);
1118 break;
1120 case _C_INT:
1121 return objc_read_int (stream, (int*)data);
1122 break;
1124 case _C_UINT:
1125 return objc_read_unsigned_int (stream, (unsigned int*)data);
1126 break;
1128 case _C_LNG:
1129 return objc_read_long (stream, (long*)data);
1130 break;
1132 case _C_ULNG:
1133 return objc_read_unsigned_long (stream, (unsigned long*)data);
1134 break;
1136 case _C_CHARPTR:
1137 case _C_ATOM:
1138 return objc_read_string (stream, (char**)data);
1139 break;
1141 case _C_ARY_B:
1143 int len = atoi (type + 1);
1144 while (isdigit ((unsigned char) *++type))
1146 return objc_read_array (stream, type, len, data);
1148 break;
1150 case _C_STRUCT_B:
1152 int acc_size = 0;
1153 int align;
1154 while (*type != _C_STRUCT_E && *type++ != '=')
1155 ; /* skip "<name>=" */
1156 while (*type != _C_STRUCT_E)
1158 align = objc_alignof_type (type); /* padd to alignment */
1159 acc_size = ROUND (acc_size, align);
1160 objc_read_type (stream, type, ((char*)data)+acc_size);
1161 acc_size += objc_sizeof_type (type); /* add component size */
1162 type = objc_skip_typespec (type); /* skip component */
1164 return 1;
1167 default:
1169 _objc_abort ("objc_read_type: cannot parse typespec: %s\n", type);
1170 return 0;
1176 ** Write the object specified by the template TYPE to STREAM. Last
1177 ** arguments specify addresses of values to be written. It might
1178 ** seem surprising to specify values by address, but this is extremely
1179 ** convenient for copy-paste with objc_read_types calls. A more
1180 ** down-to-the-earth cause for this passing of addresses is that values
1181 ** of arbitrary size is not well supported in ANSI C for functions with
1182 ** variable number of arguments.
1185 int
1186 objc_write_types (TypedStream *stream, const char *type, ...)
1188 va_list args;
1189 const char *c;
1190 int res = 0;
1192 va_start(args, type);
1194 for (c = type; *c; c = objc_skip_typespec (c))
1196 switch (*c) {
1197 case _C_ID:
1198 res = objc_write_object (stream, *va_arg (args, id*));
1199 break;
1201 case _C_CLASS:
1202 res = objc_write_class (stream, *va_arg (args, Class*));
1203 break;
1205 case _C_SEL:
1206 res = objc_write_selector (stream, *va_arg (args, SEL*));
1207 break;
1209 case _C_CHR:
1210 res = objc_write_char (stream, *va_arg (args, char*));
1211 break;
1213 case _C_UCHR:
1214 res = objc_write_unsigned_char (stream,
1215 *va_arg (args, unsigned char*));
1216 break;
1218 case _C_SHT:
1219 res = objc_write_short (stream, *va_arg (args, short*));
1220 break;
1222 case _C_USHT:
1223 res = objc_write_unsigned_short (stream,
1224 *va_arg (args, unsigned short*));
1225 break;
1227 case _C_INT:
1228 res = objc_write_int(stream, *va_arg (args, int*));
1229 break;
1231 case _C_UINT:
1232 res = objc_write_unsigned_int(stream, *va_arg (args, unsigned int*));
1233 break;
1235 case _C_LNG:
1236 res = objc_write_long(stream, *va_arg (args, long*));
1237 break;
1239 case _C_ULNG:
1240 res = objc_write_unsigned_long(stream, *va_arg (args, unsigned long*));
1241 break;
1243 case _C_CHARPTR:
1245 unsigned char **str = va_arg (args, unsigned char **);
1246 res = objc_write_string (stream, *str, strlen ((char*)*str));
1248 break;
1250 case _C_ATOM:
1252 unsigned char **str = va_arg (args, unsigned char **);
1253 res = objc_write_string_atomic (stream, *str, strlen ((char*)*str));
1255 break;
1257 case _C_ARY_B:
1259 int len = atoi (c + 1);
1260 const char *t = c;
1261 while (isdigit ((unsigned char) *++t))
1263 res = objc_write_array (stream, t, len, va_arg (args, void *));
1264 t = objc_skip_typespec (t);
1265 if (*t != _C_ARY_E)
1266 _objc_abort ("expected `]', got: %s", t);
1268 break;
1270 default:
1271 _objc_abort ("objc_write_types: cannot parse typespec: %s\n", type);
1274 va_end(args);
1275 return res;
1280 ** Last arguments specify addresses of values to be read. Expected
1281 ** type is checked against the type actually present on the stream.
1284 int
1285 objc_read_types(TypedStream *stream, const char *type, ...)
1287 va_list args;
1288 const char *c;
1289 int res = 0;
1291 va_start (args, type);
1293 for (c = type; *c; c = objc_skip_typespec(c))
1295 switch (*c) {
1296 case _C_ID:
1297 res = objc_read_object(stream, va_arg (args, id*));
1298 break;
1300 case _C_CLASS:
1301 res = objc_read_class(stream, va_arg (args, Class*));
1302 break;
1304 case _C_SEL:
1305 res = objc_read_selector(stream, va_arg (args, SEL*));
1306 break;
1308 case _C_CHR:
1309 res = objc_read_char(stream, va_arg (args, char*));
1310 break;
1312 case _C_UCHR:
1313 res = objc_read_unsigned_char(stream, va_arg (args, unsigned char*));
1314 break;
1316 case _C_SHT:
1317 res = objc_read_short(stream, va_arg (args, short*));
1318 break;
1320 case _C_USHT:
1321 res = objc_read_unsigned_short(stream, va_arg (args, unsigned short*));
1322 break;
1324 case _C_INT:
1325 res = objc_read_int(stream, va_arg (args, int*));
1326 break;
1328 case _C_UINT:
1329 res = objc_read_unsigned_int(stream, va_arg (args, unsigned int*));
1330 break;
1332 case _C_LNG:
1333 res = objc_read_long(stream, va_arg (args, long*));
1334 break;
1336 case _C_ULNG:
1337 res = objc_read_unsigned_long(stream, va_arg (args, unsigned long*));
1338 break;
1340 case _C_CHARPTR:
1341 case _C_ATOM:
1343 char **str = va_arg (args, char **);
1344 res = objc_read_string (stream, str);
1346 break;
1348 case _C_ARY_B:
1350 int len = atoi (c + 1);
1351 const char *t = c;
1352 while (isdigit ((unsigned char) *++t))
1354 res = objc_read_array (stream, t, len, va_arg (args, void *));
1355 t = objc_skip_typespec (t);
1356 if (*t != _C_ARY_E)
1357 _objc_abort ("expected `]', got: %s", t);
1359 break;
1361 default:
1362 _objc_abort ("objc_read_types: cannot parse typespec: %s\n", type);
1365 va_end (args);
1366 return res;
1370 ** Write an array of COUNT elements of TYPE from the memory address DATA.
1371 ** This is equivalent of objc_write_type (stream, "[N<type>]", data)
1375 objc_write_array (TypedStream *stream, const char *type,
1376 int count, const void *data)
1378 int off = objc_sizeof_type(type);
1379 const char *where = data;
1381 while (count-- > 0)
1383 objc_write_type(stream, type, where);
1384 where += off;
1386 return 1;
1390 ** Read an array of COUNT elements of TYPE into the memory address
1391 ** DATA. The memory pointed to by data is supposed to be allocated
1392 ** by the callee. This is equivalent of
1393 ** objc_read_type (stream, "[N<type>]", data)
1397 objc_read_array (TypedStream *stream, const char *type,
1398 int count, void *data)
1400 int off = objc_sizeof_type(type);
1401 char *where = (char*)data;
1403 while (count-- > 0)
1405 objc_read_type(stream, type, where);
1406 where += off;
1408 return 1;
1411 static int
1412 __objc_fread (FILE *file, char *data, int len)
1414 return fread(data, len, 1, file);
1417 static int
1418 __objc_fwrite (FILE *file, char *data, int len)
1420 return fwrite(data, len, 1, file);
1423 static int
1424 __objc_feof (FILE *file)
1426 return feof(file);
1429 static int
1430 __objc_no_write (FILE *file __attribute__ ((__unused__)),
1431 const char *data __attribute__ ((__unused__)),
1432 int len __attribute__ ((__unused__)))
1434 _objc_abort ("TypedStream not open for writing");
1435 return 0;
1438 static int
1439 __objc_no_read (FILE *file __attribute__ ((__unused__)),
1440 const char *data __attribute__ ((__unused__)),
1441 int len __attribute__ ((__unused__)))
1443 _objc_abort ("TypedStream not open for reading");
1444 return 0;
1447 static int
1448 __objc_read_typed_stream_signature (TypedStream *stream)
1450 char buffer[80];
1451 int pos = 0;
1453 (*stream->read) (stream->physical, buffer+pos, 1);
1454 while (buffer[pos++] != '\0')
1456 sscanf (buffer, "GNU TypedStream %d", &stream->version);
1457 if (stream->version != OBJC_TYPED_STREAM_VERSION)
1458 _objc_abort ("cannot handle TypedStream version %d", stream->version);
1459 return 1;
1462 static int
1463 __objc_write_typed_stream_signature (TypedStream *stream)
1465 char buffer[80];
1466 sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
1467 stream->version = OBJC_TYPED_STREAM_VERSION;
1468 (*stream->write) (stream->physical, buffer, strlen (buffer) + 1);
1469 return 1;
1472 static void __objc_finish_write_root_object(struct objc_typed_stream *stream)
1474 objc_hash_delete (stream->object_table);
1475 stream->object_table = objc_hash_new (64,
1476 (hash_func_type) objc_hash_ptr,
1477 (compare_func_type) objc_compare_ptrs);
1480 static void __objc_finish_read_root_object(struct objc_typed_stream *stream)
1482 node_ptr node;
1483 SEL awake_sel = sel_get_any_uid ("awake");
1484 cache_ptr free_list = objc_hash_new (64,
1485 (hash_func_type) objc_hash_ptr,
1486 (compare_func_type) objc_compare_ptrs);
1488 /* resolve object forward references */
1489 for (node = objc_hash_next (stream->object_refs, NULL); node;
1490 node = objc_hash_next (stream->object_refs, node))
1492 struct objc_list *reflist = node->value;
1493 const void *key = node->key;
1494 id object = objc_hash_value_for_key (stream->object_table, key);
1495 while (reflist)
1497 *((id*) reflist->head) = object;
1498 if (objc_hash_value_for_key (free_list,reflist) == NULL)
1499 objc_hash_add (&free_list,reflist,reflist);
1501 reflist = reflist->tail;
1505 /* apply __objc_free to all objects stored in free_list */
1506 for (node = objc_hash_next (free_list, NULL); node;
1507 node = objc_hash_next (free_list, node))
1508 objc_free ((void *) node->key);
1510 objc_hash_delete (free_list);
1512 /* empty object reference table */
1513 objc_hash_delete (stream->object_refs);
1514 stream->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr,
1515 (compare_func_type) objc_compare_ptrs);
1517 /* call -awake for all objects read */
1518 if (awake_sel)
1520 for (node = objc_hash_next (stream->object_table, NULL); node;
1521 node = objc_hash_next (stream->object_table, node))
1523 id object = node->value;
1524 if (__objc_responds_to (object, awake_sel))
1525 (*objc_msg_lookup (object, awake_sel)) (object, awake_sel);
1529 /* empty object table */
1530 objc_hash_delete (stream->object_table);
1531 stream->object_table = objc_hash_new(64,
1532 (hash_func_type)objc_hash_ptr,
1533 (compare_func_type)objc_compare_ptrs);
1537 ** Open the stream PHYSICAL in MODE
1540 TypedStream *
1541 objc_open_typed_stream (FILE *physical, int mode)
1543 TypedStream *s = (TypedStream *) objc_malloc (sizeof (TypedStream));
1545 s->mode = mode;
1546 s->physical = physical;
1547 s->stream_table = objc_hash_new (64,
1548 (hash_func_type) objc_hash_ptr,
1549 (compare_func_type) objc_compare_ptrs);
1550 s->object_table = objc_hash_new (64,
1551 (hash_func_type) objc_hash_ptr,
1552 (compare_func_type) objc_compare_ptrs);
1553 s->eof = (objc_typed_eof_func) __objc_feof;
1554 s->flush = (objc_typed_flush_func) fflush;
1555 s->writing_root_p = 0;
1556 if (mode == OBJC_READONLY)
1558 s->class_table
1559 = objc_hash_new (8, (hash_func_type) objc_hash_string,
1560 (compare_func_type) objc_compare_strings);
1561 s->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr,
1562 (compare_func_type) objc_compare_ptrs);
1563 s->read = (objc_typed_read_func) __objc_fread;
1564 s->write = (objc_typed_write_func) __objc_no_write;
1565 __objc_read_typed_stream_signature (s);
1567 else if (mode == OBJC_WRITEONLY)
1569 s->class_table = 0;
1570 s->object_refs = 0;
1571 s->read = (objc_typed_read_func) __objc_no_read;
1572 s->write = (objc_typed_write_func) __objc_fwrite;
1573 __objc_write_typed_stream_signature (s);
1575 else
1577 objc_close_typed_stream (s);
1578 return NULL;
1580 s->type = OBJC_FILE_STREAM;
1581 return s;
1585 ** Open the file named by FILE_NAME in MODE
1588 TypedStream*
1589 objc_open_typed_stream_for_file (const char *file_name, int mode)
1591 FILE *file = NULL;
1592 TypedStream *s;
1594 if (mode == OBJC_READONLY)
1595 file = fopen (file_name, "r");
1596 else
1597 file = fopen (file_name, "w");
1599 if (file)
1601 s = objc_open_typed_stream (file, mode);
1602 if (s)
1603 s->type |= OBJC_MANAGED_STREAM;
1604 return s;
1606 else
1607 return NULL;
1611 ** Close STREAM freeing the structure it self. If it was opened with
1612 ** objc_open_typed_stream_for_file, the file will also be closed.
1615 void
1616 objc_close_typed_stream (TypedStream *stream)
1618 if (stream->mode == OBJC_READONLY)
1620 __objc_finish_read_root_object (stream); /* Just in case... */
1621 objc_hash_delete (stream->class_table);
1622 objc_hash_delete (stream->object_refs);
1625 objc_hash_delete (stream->stream_table);
1626 objc_hash_delete (stream->object_table);
1628 if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
1629 fclose ((FILE *)stream->physical);
1631 objc_free(stream);
1634 BOOL
1635 objc_end_of_typed_stream (TypedStream *stream)
1637 return (*stream->eof) (stream->physical);
1640 void
1641 objc_flush_typed_stream (TypedStream *stream)
1643 (*stream->flush) (stream->physical);
1646 long
1647 objc_get_stream_class_version (TypedStream *stream, Class class)
1649 if (stream->class_table)
1650 return PTR2LONG(objc_hash_value_for_key (stream->class_table,
1651 class->name));
1652 else
1653 return class_get_version (class);