Be sure to initialize the size before use.
[official-gcc.git] / libobjc / archive.c
blob10106c1145e7f2880c4929a4031821cd81944b51
1 /* GNU Objective C Runtime archiving
2 Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
3 Contributed by Kresten Krab Thorup
5 This file is part of GNU CC.
7 GNU CC 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 GNU CC 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 GNU CC; see the file COPYING. If not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, 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 "runtime.h"
29 #include "typedstream.h"
30 #include "encoding.h"
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
36 extern int fflush(FILE*);
38 #define ROUND(V, A) \
39 ({ typeof(V) __v=(V); typeof(A) __a=(A); \
40 __a*((__v+__a-1)/__a); })
42 #define PTR2LONG(P) (((char*)(P))-(char*)0)
43 #define LONG2PTR(L) (((char*)0)+(L))
45 /* Declare some functions... */
47 static int
48 objc_read_class (struct objc_typed_stream* stream, Class* class);
50 int objc_sizeof_type(const char* type);
52 static int
53 objc_write_use_common (struct objc_typed_stream* stream, unsigned long key);
55 static int
56 objc_write_register_common (struct objc_typed_stream* stream,
57 unsigned long key);
59 static int
60 objc_write_class (struct objc_typed_stream* stream,
61 struct objc_class* class);
63 const char* objc_skip_type (const char* type);
65 static void __objc_finish_write_root_object(struct objc_typed_stream*);
66 static void __objc_finish_read_root_object(struct objc_typed_stream*);
68 static __inline__ int
69 __objc_code_unsigned_char (unsigned char* buf, unsigned char val)
71 if ((val&_B_VALUE) == val)
73 buf[0] = val|_B_SINT;
74 return 1;
76 else
78 buf[0] = _B_NINT|0x01;
79 buf[1] = val;
80 return 2;
84 int
85 objc_write_unsigned_char (struct objc_typed_stream* stream,
86 unsigned char value)
88 unsigned char buf[sizeof (unsigned char)+1];
89 int len = __objc_code_unsigned_char (buf, value);
90 return (*stream->write)(stream->physical, buf, len);
93 static __inline__ int
94 __objc_code_char (unsigned char* buf, signed char val)
96 if (val >= 0)
97 return __objc_code_unsigned_char (buf, val);
98 else
100 buf[0] = _B_NINT|_B_SIGN|0x01;
101 buf[1] = -val;
102 return 2;
107 objc_write_char (struct objc_typed_stream* stream, signed char value)
109 unsigned char buf[sizeof (char)+1];
110 int len = __objc_code_char (buf, value);
111 return (*stream->write)(stream->physical, buf, len);
114 static __inline__ int
115 __objc_code_unsigned_short (unsigned char* buf, unsigned short val)
117 if ((val&_B_VALUE) == val)
119 buf[0] = val|_B_SINT;
120 return 1;
122 else
124 int c, b;
126 buf[0] = _B_NINT;
128 for (c= sizeof(short); c != 0; c -= 1)
129 if (((val>>(8*(c-1)))%0x100) != 0)
130 break;
132 buf[0] |= c;
134 for (b = 1; c != 0; c--, b++)
136 buf[b] = (val >> (8*(c-1)))%0x100;
139 return b;
144 objc_write_unsigned_short (struct objc_typed_stream* stream,
145 unsigned short value)
147 unsigned char buf[sizeof (unsigned short)+1];
148 int len = __objc_code_unsigned_short (buf, value);
149 return (*stream->write)(stream->physical, buf, len);
152 static __inline__ int
153 __objc_code_short (unsigned char* buf, short val)
155 int sign = (val < 0);
156 int size = __objc_code_unsigned_short (buf, sign ? -val : val);
157 if (sign)
158 buf[0] |= _B_SIGN;
159 return size;
163 objc_write_short (struct objc_typed_stream* stream, short value)
165 unsigned char buf[sizeof (short)+1];
166 int len = __objc_code_short (buf, value);
167 return (*stream->write)(stream->physical, buf, len);
171 static __inline__ int
172 __objc_code_unsigned_int (unsigned char* buf, unsigned int val)
174 if ((val&_B_VALUE) == val)
176 buf[0] = val|_B_SINT;
177 return 1;
179 else
181 int c, b;
183 buf[0] = _B_NINT;
185 for (c= sizeof(int); c != 0; c -= 1)
186 if (((val>>(8*(c-1)))%0x100) != 0)
187 break;
189 buf[0] |= c;
191 for (b = 1; c != 0; c--, b++)
193 buf[b] = (val >> (8*(c-1)))%0x100;
196 return b;
201 objc_write_unsigned_int (struct objc_typed_stream* stream, unsigned int value)
203 unsigned char buf[sizeof(unsigned int)+1];
204 int len = __objc_code_unsigned_int (buf, value);
205 return (*stream->write)(stream->physical, buf, len);
208 static __inline__ int
209 __objc_code_int (unsigned char* buf, int val)
211 int sign = (val < 0);
212 int size = __objc_code_unsigned_int (buf, sign ? -val : val);
213 if (sign)
214 buf[0] |= _B_SIGN;
215 return size;
219 objc_write_int (struct objc_typed_stream* stream, int value)
221 unsigned char buf[sizeof(int)+1];
222 int len = __objc_code_int (buf, value);
223 return (*stream->write)(stream->physical, buf, len);
226 static __inline__ int
227 __objc_code_unsigned_long (unsigned char* buf, unsigned long val)
229 if ((val&_B_VALUE) == val)
231 buf[0] = val|_B_SINT;
232 return 1;
234 else
236 int c, b;
238 buf[0] = _B_NINT;
240 for (c= sizeof(long); c != 0; c -= 1)
241 if (((val>>(8*(c-1)))%0x100) != 0)
242 break;
244 buf[0] |= c;
246 for (b = 1; c != 0; c--, b++)
248 buf[b] = (val >> (8*(c-1)))%0x100;
251 return b;
256 objc_write_unsigned_long (struct objc_typed_stream* stream,
257 unsigned long value)
259 unsigned char buf[sizeof(unsigned long)+1];
260 int len = __objc_code_unsigned_long (buf, value);
261 return (*stream->write)(stream->physical, buf, len);
264 static __inline__ int
265 __objc_code_long (unsigned char* buf, long val)
267 int sign = (val < 0);
268 int size = __objc_code_unsigned_long (buf, sign ? -val : val);
269 if (sign)
270 buf[0] |= _B_SIGN;
271 return size;
275 objc_write_long (struct objc_typed_stream* stream, long value)
277 unsigned char buf[sizeof(long)+1];
278 int len = __objc_code_long (buf, value);
279 return (*stream->write)(stream->physical, buf, len);
284 objc_write_string (struct objc_typed_stream* stream,
285 const unsigned char* string, unsigned int nbytes)
287 unsigned char buf[sizeof(unsigned int)+1];
288 int len = __objc_code_unsigned_int (buf, nbytes);
290 if ((buf[0]&_B_CODE) == _B_SINT)
291 buf[0] = (buf[0]&_B_VALUE)|_B_SSTR;
293 else /* _B_NINT */
294 buf[0] = (buf[0]&_B_VALUE)|_B_NSTR;
296 if ((*stream->write)(stream->physical, buf, len) != 0)
297 return (*stream->write)(stream->physical, string, nbytes);
298 else
299 return 0;
303 objc_write_string_atomic (struct objc_typed_stream* stream,
304 unsigned char* string, unsigned int nbytes)
306 unsigned long key;
307 if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, string))))
308 return objc_write_use_common (stream, key);
309 else
311 int length;
312 hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(string)), string);
313 if ((length = objc_write_register_common (stream, key)))
314 return objc_write_string (stream, string, nbytes);
315 return length;
319 static int
320 objc_write_register_common (struct objc_typed_stream* stream,
321 unsigned long key)
323 unsigned char buf[sizeof (unsigned long)+2];
324 int len = __objc_code_unsigned_long (buf+1, key);
325 if (len == 1)
327 buf[0] = _B_RCOMM|0x01;
328 buf[1] &= _B_VALUE;
329 return (*stream->write)(stream->physical, buf, len+1);
331 else
333 buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
334 return (*stream->write)(stream->physical, buf+1, len);
338 static int
339 objc_write_use_common (struct objc_typed_stream* stream, unsigned long key)
341 unsigned char buf[sizeof (unsigned long)+2];
342 int len = __objc_code_unsigned_long (buf+1, key);
343 if (len == 1)
345 buf[0] = _B_UCOMM|0x01;
346 buf[1] &= _B_VALUE;
347 return (*stream->write)(stream->physical, buf, 2);
349 else
351 buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
352 return (*stream->write)(stream->physical, buf+1, len);
356 static __inline__ int
357 __objc_write_extension (struct objc_typed_stream* stream, unsigned char code)
359 if (code <= _B_VALUE)
361 unsigned char buf = code|_B_EXT;
362 return (*stream->write)(stream->physical, &buf, 1);
364 else
366 objc_error(nil, OBJC_ERR_BAD_OPCODE,
367 "__objc_write_extension: bad opcode %c\n", code);
368 return -1;
372 __inline__ int
373 __objc_write_object (struct objc_typed_stream* stream, id object)
375 unsigned char buf = '\0';
376 SEL write_sel = sel_get_any_uid ("write:");
377 if (object)
379 __objc_write_extension (stream, _BX_OBJECT);
380 objc_write_class (stream, object->class_pointer);
381 (*objc_msg_lookup(object, write_sel))(object, write_sel, stream);
382 return (*stream->write)(stream->physical, &buf, 1);
384 else
385 return objc_write_use_common(stream, 0);
388 int
389 objc_write_object_reference (struct objc_typed_stream* stream, id object)
391 unsigned long key;
392 if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object))))
393 return objc_write_use_common (stream, key);
395 __objc_write_extension (stream, _BX_OBJREF);
396 return objc_write_unsigned_long (stream, PTR2LONG (object));
399 int
400 objc_write_root_object (struct objc_typed_stream* stream, id object)
402 int len = 0;
403 if (stream->writing_root_p)
404 objc_error (nil, OBJC_ERR_RECURSE_ROOT,
405 "objc_write_root_object called recursively");
406 else
408 stream->writing_root_p = 1;
409 __objc_write_extension (stream, _BX_OBJROOT);
410 if((len = objc_write_object (stream, object)))
411 __objc_finish_write_root_object(stream);
412 stream->writing_root_p = 0;
414 return len;
417 int
418 objc_write_object (struct objc_typed_stream* stream, id object)
420 unsigned long key;
421 if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object))))
422 return objc_write_use_common (stream, key);
424 else if (object == nil)
425 return objc_write_use_common(stream, 0);
427 else
429 int length;
430 hash_add (&stream->object_table, LONG2PTR(key=PTR2LONG(object)), object);
431 if ((length = objc_write_register_common (stream, key)))
432 return __objc_write_object (stream, object);
433 return length;
437 __inline__ int
438 __objc_write_class (struct objc_typed_stream* stream, struct objc_class* class)
440 __objc_write_extension (stream, _BX_CLASS);
441 objc_write_string_atomic(stream, (char*)class->name,
442 strlen((char*)class->name));
443 return objc_write_unsigned_long (stream, class->version);
447 static int
448 objc_write_class (struct objc_typed_stream* stream,
449 struct objc_class* class)
451 unsigned long key;
452 if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, class))))
453 return objc_write_use_common (stream, key);
454 else
456 int length;
457 hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(class)), class);
458 if ((length = objc_write_register_common (stream, key)))
459 return __objc_write_class (stream, class);
460 return length;
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, "", 0);
473 sel_name = sel_get_name (selector);
474 return objc_write_string (stream, 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(hash_value_for_key (stream->stream_table, sel_name))))
489 return objc_write_use_common (stream, key);
490 else
492 int length;
493 hash_add (&stream->stream_table,
494 LONG2PTR(key=PTR2LONG(sel_name)), (char*)sel_name);
495 if ((length = objc_write_register_common (stream, key)))
496 return __objc_write_selector (stream, selector);
497 return length;
504 ** Read operations
507 __inline__ int
508 objc_read_char (struct objc_typed_stream* stream, char* val)
510 unsigned char buf;
511 int len;
512 len = (*stream->read)(stream->physical, &buf, 1);
513 if (len != 0)
515 if ((buf & _B_CODE) == _B_SINT)
516 (*val) = (buf & _B_VALUE);
518 else if ((buf & _B_NUMBER) == 1)
520 len = (*stream->read)(stream->physical, val, 1);
521 if (buf&_B_SIGN)
522 (*val) = -1*(*val);
525 else
526 objc_error(nil, OBJC_ERR_BAD_DATA,
527 "expected 8bit signed int, got %dbit int",
528 (int)(buf&_B_NUMBER)*8);
530 return len;
534 __inline__ int
535 objc_read_unsigned_char (struct objc_typed_stream* stream, unsigned char* val)
537 unsigned char buf;
538 int len;
539 if ((len = (*stream->read)(stream->physical, &buf, 1)))
541 if ((buf & _B_CODE) == _B_SINT)
542 (*val) = (buf & _B_VALUE);
544 else if ((buf & _B_NUMBER) == 1)
545 len = (*stream->read)(stream->physical, val, 1);
547 else
548 objc_error(nil, OBJC_ERR_BAD_DATA,
549 "expected 8bit unsigned int, got %dbit int",
550 (int)(buf&_B_NUMBER)*8);
552 return len;
555 __inline__ int
556 objc_read_short (struct objc_typed_stream* stream, short* value)
558 unsigned char buf[sizeof(short)+1];
559 int len;
560 if ((len = (*stream->read)(stream->physical, buf, 1)))
562 if ((buf[0] & _B_CODE) == _B_SINT)
563 (*value) = (buf[0] & _B_VALUE);
565 else
567 int pos = 1;
568 int nbytes = buf[0] & _B_NUMBER;
569 if (nbytes > sizeof (short))
570 objc_error(nil, OBJC_ERR_BAD_DATA,
571 "expected short, got bigger (%dbits)", nbytes*8);
572 len = (*stream->read)(stream->physical, buf+1, nbytes);
573 (*value) = 0;
574 while (pos <= nbytes)
575 (*value) = ((*value)*0x100) + buf[pos++];
576 if (buf[0] & _B_SIGN)
577 (*value) = -(*value);
580 return len;
583 __inline__ int
584 objc_read_unsigned_short (struct objc_typed_stream* stream,
585 unsigned short* value)
587 unsigned char buf[sizeof(unsigned short)+1];
588 int len;
589 if ((len = (*stream->read)(stream->physical, buf, 1)))
591 if ((buf[0] & _B_CODE) == _B_SINT)
592 (*value) = (buf[0] & _B_VALUE);
594 else
596 int pos = 1;
597 int nbytes = buf[0] & _B_NUMBER;
598 if (nbytes > sizeof (short))
599 objc_error(nil, OBJC_ERR_BAD_DATA,
600 "expected short, got int or bigger");
601 len = (*stream->read)(stream->physical, buf+1, nbytes);
602 (*value) = 0;
603 while (pos <= nbytes)
604 (*value) = ((*value)*0x100) + buf[pos++];
607 return len;
611 __inline__ int
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, 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 > sizeof (int))
626 objc_error(nil, OBJC_ERR_BAD_DATA, "expected int, got bigger");
627 len = (*stream->read)(stream->physical, buf+1, nbytes);
628 (*value) = 0;
629 while (pos <= nbytes)
630 (*value) = ((*value)*0x100) + buf[pos++];
631 if (buf[0] & _B_SIGN)
632 (*value) = -(*value);
635 return len;
638 __inline__ int
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, 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 > sizeof (long))
653 objc_error(nil, OBJC_ERR_BAD_DATA, "expected long, got bigger");
654 len = (*stream->read)(stream->physical, buf+1, nbytes);
655 (*value) = 0;
656 while (pos <= nbytes)
657 (*value) = ((*value)*0x100) + buf[pos++];
658 if (buf[0] & _B_SIGN)
659 (*value) = -(*value);
662 return len;
665 __inline__ int
666 __objc_read_nbyte_uint (struct objc_typed_stream* stream,
667 unsigned int nbytes, unsigned int* val)
669 int len, 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, 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, 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, pos = 0;
706 unsigned char buf[sizeof(unsigned long)+1];
708 if (nbytes > sizeof (long))
709 objc_error(nil, OBJC_ERR_BAD_DATA, "expected long, got bigger");
711 len = (*stream->read)(stream->physical, buf, nbytes);
712 (*val) = 0;
713 while (pos < nbytes)
714 (*val) = ((*val)*0x100) + buf[pos++];
715 return len;
719 __inline__ int
720 objc_read_unsigned_long (struct objc_typed_stream* stream,
721 unsigned long* value)
723 unsigned char buf[sizeof(unsigned long)+1];
724 int len;
725 if ((len = (*stream->read)(stream->physical, buf, 1)))
727 if ((buf[0] & _B_CODE) == _B_SINT)
728 (*value) = (buf[0] & _B_VALUE);
730 else
731 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value);
734 return len;
737 __inline__ int
738 objc_read_string (struct objc_typed_stream* stream,
739 char** string)
741 unsigned char buf[sizeof(unsigned int)+1];
742 int len;
743 if ((len = (*stream->read)(stream->physical, buf, 1)))
745 unsigned long key = 0;
747 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
749 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
750 len = (*stream->read)(stream->physical, buf, 1);
753 switch (buf[0]&_B_CODE) {
754 case _B_SSTR:
756 int length = buf[0]&_B_VALUE;
757 (*string) = (char*)objc_malloc(length+1);
758 if (key)
759 hash_add (&stream->stream_table, LONG2PTR(key), *string);
760 len = (*stream->read)(stream->physical, *string, length);
761 (*string)[length] = '\0';
763 break;
765 case _B_UCOMM:
767 char *tmp;
768 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
769 tmp = hash_value_for_key (stream->stream_table, LONG2PTR (key));
770 *string = objc_malloc (strlen(tmp) + 1);
771 strcpy (*string, tmp);
773 break;
775 case _B_NSTR:
777 unsigned int nbytes = buf[0]&_B_VALUE;
778 len = __objc_read_nbyte_uint(stream, nbytes, &nbytes);
779 if (len) {
780 (*string) = (char*)objc_malloc(nbytes+1);
781 if (key)
782 hash_add (&stream->stream_table, LONG2PTR(key), *string);
783 len = (*stream->read)(stream->physical, *string, nbytes);
784 (*string)[nbytes] = '\0';
787 break;
789 default:
790 objc_error(nil, OBJC_ERR_BAD_DATA,
791 "expected string, got opcode %c\n", (buf[0]&_B_CODE));
795 return len;
800 objc_read_object (struct objc_typed_stream* stream, id* object)
802 unsigned char buf[sizeof (unsigned int)];
803 int len;
804 if ((len = (*stream->read)(stream->physical, buf, 1)))
806 SEL read_sel = sel_get_any_uid ("read:");
807 unsigned long key = 0;
809 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */
811 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
812 len = (*stream->read)(stream->physical, buf, 1);
815 if (buf[0] == (_B_EXT | _BX_OBJECT))
817 Class class;
819 /* get class */
820 len = objc_read_class (stream, &class);
822 /* create instance */
823 (*object) = class_create_instance(class);
825 /* register? */
826 if (key)
827 hash_add (&stream->object_table, LONG2PTR(key), *object);
829 /* send -read: */
830 if (__objc_responds_to (*object, read_sel))
831 (*get_imp(class, read_sel))(*object, read_sel, stream);
833 /* check null-byte */
834 len = (*stream->read)(stream->physical, buf, 1);
835 if (buf[0] != '\0')
836 objc_error(nil, OBJC_ERR_BAD_DATA,
837 "expected null-byte, got opcode %c", buf[0]);
840 else if ((buf[0]&_B_CODE) == _B_UCOMM)
842 if (key)
843 objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
844 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
845 (*object) = hash_value_for_key (stream->object_table, LONG2PTR(key));
848 else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */
850 struct objc_list* other;
851 len = objc_read_unsigned_long (stream, &key);
852 other = (struct objc_list*)hash_value_for_key (stream->object_refs,
853 LONG2PTR(key));
854 hash_add (&stream->object_refs, LONG2PTR(key),
855 (void*)list_cons(object, other));
858 else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */
860 if (key)
861 objc_error(nil, OBJC_ERR_BAD_KEY,
862 "cannot register root object...");
863 len = objc_read_object (stream, object);
864 __objc_finish_read_root_object (stream);
867 else
868 objc_error(nil, OBJC_ERR_BAD_DATA,
869 "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, 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, buf, 1);
889 if (buf[0] == (_B_EXT | _BX_CLASS))
891 char* class_name;
892 unsigned long version;
894 /* get class */
895 len = objc_read_string (stream, &class_name);
896 (*class) = objc_get_class(class_name);
897 objc_free(class_name);
899 /* register */
900 if (key)
901 hash_add (&stream->stream_table, LONG2PTR(key), *class);
903 objc_read_unsigned_long(stream, &version);
904 hash_add (&stream->class_table, (*class)->name, (void*)version);
907 else if ((buf[0]&_B_CODE) == _B_UCOMM)
909 if (key)
910 objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
911 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
912 (*class) = hash_value_for_key (stream->stream_table, LONG2PTR(key));
913 if (!*class)
914 objc_error(nil, OBJC_ERR_BAD_CLASS,
915 "cannot find class for key %lu", key);
918 else
919 objc_error(nil, OBJC_ERR_BAD_DATA,
920 "expected class, got opcode %c", buf[0]);
922 return len;
926 objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
928 unsigned char buf[sizeof (unsigned int)];
929 int len;
930 if ((len = (*stream->read)(stream->physical, buf, 1)))
932 unsigned long key = 0;
934 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
936 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
937 len = (*stream->read)(stream->physical, buf, 1);
940 if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
942 char* selector_name;
944 /* get selector */
945 len = objc_read_string (stream, &selector_name);
946 /* To handle NULL selectors */
947 if (0 == strlen(selector_name))
949 (*selector) = (SEL)0;
950 return 0;
952 else
953 (*selector) = sel_get_any_uid(selector_name);
954 objc_free(selector_name);
956 /* register */
957 if (key)
958 hash_add (&stream->stream_table, LONG2PTR(key), (void*)*selector);
961 else if ((buf[0]&_B_CODE) == _B_UCOMM)
963 if (key)
964 objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
965 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
966 (*selector) = hash_value_for_key (stream->stream_table,
967 LONG2PTR(key));
970 else
971 objc_error(nil, OBJC_ERR_BAD_DATA,
972 "expected selector, got opcode %c", buf[0]);
974 return len;
978 ** USER LEVEL FUNCTIONS
982 ** Write one object, encoded in TYPE and pointed to by DATA to the
983 ** typed stream STREAM.
987 objc_write_type(TypedStream* stream, const char* type, const void* data)
989 switch(*type) {
990 case _C_ID:
991 return objc_write_object (stream, *(id*)data);
992 break;
994 case _C_CLASS:
995 return objc_write_class (stream, *(Class*)data);
996 break;
998 case _C_SEL:
999 return objc_write_selector (stream, *(SEL*)data);
1000 break;
1002 case _C_CHR:
1003 return objc_write_char(stream, *(signed char*)data);
1004 break;
1006 case _C_UCHR:
1007 return objc_write_unsigned_char(stream, *(unsigned char*)data);
1008 break;
1010 case _C_SHT:
1011 return objc_write_short(stream, *(short*)data);
1012 break;
1014 case _C_USHT:
1015 return objc_write_unsigned_short(stream, *(unsigned short*)data);
1016 break;
1018 case _C_INT:
1019 return objc_write_int(stream, *(int*)data);
1020 break;
1022 case _C_UINT:
1023 return objc_write_unsigned_int(stream, *(unsigned int*)data);
1024 break;
1026 case _C_LNG:
1027 return objc_write_long(stream, *(long*)data);
1028 break;
1030 case _C_ULNG:
1031 return objc_write_unsigned_long(stream, *(unsigned long*)data);
1032 break;
1034 case _C_CHARPTR:
1035 return objc_write_string (stream, *(char**)data, strlen(*(char**)data));
1036 break;
1038 case _C_ATOM:
1039 return objc_write_string_atomic (stream, *(char**)data,
1040 strlen(*(char**)data));
1041 break;
1043 case _C_ARY_B:
1045 int len = atoi(type+1);
1046 while (isdigit(*++type))
1048 return objc_write_array (stream, type, len, data);
1050 break;
1052 case _C_STRUCT_B:
1054 int acc_size = 0;
1055 int align;
1056 while (*type != _C_STRUCT_E && *type++ != '=')
1057 ; /* skip "<name>=" */
1058 while (*type != _C_STRUCT_E)
1060 align = objc_alignof_type (type); /* padd to alignment */
1061 acc_size += ROUND (acc_size, align);
1062 objc_write_type (stream, type, ((char*)data)+acc_size);
1063 acc_size += objc_sizeof_type (type); /* add component size */
1064 type = objc_skip_typespec (type); /* skip component */
1066 return 1;
1069 default:
1071 objc_error(nil, OBJC_ERR_BAD_TYPE,
1072 "objc_write_type: cannot parse typespec: %s\n", type);
1073 return 0;
1079 ** Read one object, encoded in TYPE and pointed to by DATA to the
1080 ** typed stream STREAM. DATA specifies the address of the types to
1081 ** read. Expected type is checked against the type actually present
1082 ** on the stream.
1086 objc_read_type(TypedStream* stream, const char* type, void* data)
1088 char c;
1089 switch(c = *type) {
1090 case _C_ID:
1091 return objc_read_object (stream, (id*)data);
1092 break;
1094 case _C_CLASS:
1095 return objc_read_class (stream, (Class*)data);
1096 break;
1098 case _C_SEL:
1099 return objc_read_selector (stream, (SEL*)data);
1100 break;
1102 case _C_CHR:
1103 return objc_read_char (stream, (char*)data);
1104 break;
1106 case _C_UCHR:
1107 return objc_read_unsigned_char (stream, (unsigned char*)data);
1108 break;
1110 case _C_SHT:
1111 return objc_read_short (stream, (short*)data);
1112 break;
1114 case _C_USHT:
1115 return objc_read_unsigned_short (stream, (unsigned short*)data);
1116 break;
1118 case _C_INT:
1119 return objc_read_int (stream, (int*)data);
1120 break;
1122 case _C_UINT:
1123 return objc_read_unsigned_int (stream, (unsigned int*)data);
1124 break;
1126 case _C_LNG:
1127 return objc_read_long (stream, (long*)data);
1128 break;
1130 case _C_ULNG:
1131 return objc_read_unsigned_long (stream, (unsigned long*)data);
1132 break;
1134 case _C_CHARPTR:
1135 case _C_ATOM:
1136 return objc_read_string (stream, (char**)data);
1137 break;
1139 case _C_ARY_B:
1141 int len = atoi(type+1);
1142 while (isdigit(*++type))
1144 return objc_read_array (stream, type, len, data);
1146 break;
1148 case _C_STRUCT_B:
1150 int acc_size = 0;
1151 int align;
1152 while (*type != _C_STRUCT_E && *type++ != '=')
1153 ; /* skip "<name>=" */
1154 while (*type != _C_STRUCT_E)
1156 align = objc_alignof_type (type); /* padd to alignment */
1157 acc_size += ROUND (acc_size, align);
1158 objc_read_type (stream, type, ((char*)data)+acc_size);
1159 acc_size += objc_sizeof_type (type); /* add component size */
1160 type = objc_skip_typespec (type); /* skip component */
1162 return 1;
1165 default:
1167 objc_error(nil, OBJC_ERR_BAD_TYPE,
1168 "objc_read_type: cannot parse typespec: %s\n", type);
1169 return 0;
1175 ** Write the object specified by the template TYPE to STREAM. Last
1176 ** arguments specify addresses of values to be written. It might
1177 ** seem surprising to specify values by address, but this is extremely
1178 ** convenient for copy-paste with objc_read_types calls. A more
1179 ** down-to-the-earth cause for this passing of addresses is that values
1180 ** of arbitrary size is not well supported in ANSI C for functions with
1181 ** variable number of arguments.
1184 int
1185 objc_write_types (TypedStream* stream, const char* type, ...)
1187 va_list args;
1188 const char *c;
1189 int res = 0;
1191 va_start(args, type);
1193 for (c = type; *c; c = objc_skip_typespec (c))
1195 switch(*c) {
1196 case _C_ID:
1197 res = objc_write_object (stream, *va_arg (args, id*));
1198 break;
1200 case _C_CLASS:
1201 res = objc_write_class (stream, *va_arg(args, Class*));
1202 break;
1204 case _C_SEL:
1205 res = objc_write_selector (stream, *va_arg(args, SEL*));
1206 break;
1208 case _C_CHR:
1209 res = objc_write_char (stream, *va_arg (args, char*));
1210 break;
1212 case _C_UCHR:
1213 res = objc_write_unsigned_char (stream,
1214 *va_arg (args, unsigned char*));
1215 break;
1217 case _C_SHT:
1218 res = objc_write_short (stream, *va_arg(args, short*));
1219 break;
1221 case _C_USHT:
1222 res = objc_write_unsigned_short (stream,
1223 *va_arg(args, unsigned short*));
1224 break;
1226 case _C_INT:
1227 res = objc_write_int(stream, *va_arg(args, int*));
1228 break;
1230 case _C_UINT:
1231 res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*));
1232 break;
1234 case _C_LNG:
1235 res = objc_write_long(stream, *va_arg(args, long*));
1236 break;
1238 case _C_ULNG:
1239 res = objc_write_unsigned_long(stream, *va_arg(args, unsigned long*));
1240 break;
1242 case _C_CHARPTR:
1244 char** str = va_arg(args, char**);
1245 res = objc_write_string (stream, *str, strlen(*str));
1247 break;
1249 case _C_ATOM:
1251 char** str = va_arg(args, char**);
1252 res = objc_write_string_atomic (stream, *str, strlen(*str));
1254 break;
1256 case _C_ARY_B:
1258 int len = atoi(c+1);
1259 const char* t = c;
1260 while (isdigit(*++t))
1262 res = objc_write_array (stream, t, len, va_arg(args, void*));
1263 t = objc_skip_typespec (t);
1264 if (*t != _C_ARY_E)
1265 objc_error(nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t);
1267 break;
1269 default:
1270 objc_error(nil, OBJC_ERR_BAD_TYPE,
1271 "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(*++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_error(nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t);
1359 break;
1361 default:
1362 objc_error(nil, OBJC_ERR_BAD_TYPE,
1363 "objc_read_types: cannot parse typespec: %s\n", type);
1366 va_end(args);
1367 return res;
1371 ** Write an array of COUNT elements of TYPE from the memory address DATA.
1372 ** This is equivalent of objc_write_type (stream, "[N<type>]", data)
1376 objc_write_array (TypedStream* stream, const char* type,
1377 int count, const void* data)
1379 int off = objc_sizeof_type(type);
1380 const char* where = data;
1382 while (count-- > 0)
1384 objc_write_type(stream, type, where);
1385 where += off;
1387 return 1;
1391 ** Read an array of COUNT elements of TYPE into the memory address
1392 ** DATA. The memory pointed to by data is supposed to be allocated
1393 ** by the callee. This is equivalent of
1394 ** objc_read_type (stream, "[N<type>]", data)
1398 objc_read_array (TypedStream* stream, const char* type,
1399 int count, void* data)
1401 int off = objc_sizeof_type(type);
1402 char* where = (char*)data;
1404 while (count-- > 0)
1406 objc_read_type(stream, type, where);
1407 where += off;
1409 return 1;
1412 static int
1413 __objc_fread(FILE* file, char* data, int len)
1415 return fread(data, len, 1, file);
1418 static int
1419 __objc_fwrite(FILE* file, char* data, int len)
1421 return fwrite(data, len, 1, file);
1424 static int
1425 __objc_feof(FILE* file)
1427 return feof(file);
1430 static int
1431 __objc_no_write(FILE* file, char* data, int len)
1433 objc_error (nil, OBJC_ERR_NO_WRITE, "TypedStream not open for writing");
1434 return 0;
1437 static int
1438 __objc_no_read(FILE* file, char* data, int len)
1440 objc_error (nil, OBJC_ERR_NO_READ, "TypedStream not open for reading");
1441 return 0;
1444 static int
1445 __objc_read_typed_stream_signature (TypedStream* stream)
1447 char buffer[80];
1448 int pos = 0;
1450 (*stream->read)(stream->physical, buffer+pos, 1);
1451 while (buffer[pos++] != '\0')
1453 sscanf (buffer, "GNU TypedStream %d", &stream->version);
1454 if (stream->version != OBJC_TYPED_STREAM_VERSION)
1455 objc_error (nil, OBJC_ERR_STREAM_VERSION,
1456 "cannot handle TypedStream version %d", stream->version);
1457 return 1;
1460 static int
1461 __objc_write_typed_stream_signature (TypedStream* stream)
1463 char buffer[80];
1464 sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
1465 stream->version = OBJC_TYPED_STREAM_VERSION;
1466 (*stream->write)(stream->physical, buffer, strlen(buffer)+1);
1467 return 1;
1470 static void __objc_finish_write_root_object(struct objc_typed_stream* stream)
1472 hash_delete (stream->object_table);
1473 stream->object_table = hash_new(64,
1474 (hash_func_type)hash_ptr,
1475 (compare_func_type)compare_ptrs);
1478 static void __objc_finish_read_root_object(struct objc_typed_stream* stream)
1480 node_ptr node;
1481 SEL awake_sel = sel_get_any_uid ("awake");
1482 cache_ptr free_list = hash_new (64,
1483 (hash_func_type) hash_ptr,
1484 (compare_func_type) compare_ptrs);
1486 /* resolve object forward references */
1487 for (node = hash_next (stream->object_refs, NULL); node;
1488 node = hash_next (stream->object_refs, node))
1490 struct objc_list* reflist = node->value;
1491 const void* key = node->key;
1492 id object = hash_value_for_key (stream->object_table, key);
1493 while(reflist)
1495 *((id*)reflist->head) = object;
1496 if (hash_value_for_key (free_list,reflist) == NULL)
1497 hash_add (&free_list,reflist,reflist);
1499 reflist = reflist->tail;
1503 /* apply __objc_free to all objects stored in free_list */
1504 for (node = hash_next (free_list, NULL); node;
1505 node = hash_next (free_list, node))
1506 objc_free ((void *) node->key);
1508 hash_delete (free_list);
1510 /* empty object reference table */
1511 hash_delete (stream->object_refs);
1512 stream->object_refs = hash_new(8, (hash_func_type)hash_ptr,
1513 (compare_func_type)compare_ptrs);
1515 /* call -awake for all objects read */
1516 if (awake_sel)
1518 for (node = hash_next (stream->object_table, NULL); node;
1519 node = hash_next (stream->object_table, node))
1521 id object = node->value;
1522 if (__objc_responds_to (object, awake_sel))
1523 (*objc_msg_lookup(object, awake_sel))(object, awake_sel);
1527 /* empty object table */
1528 hash_delete (stream->object_table);
1529 stream->object_table = hash_new(64,
1530 (hash_func_type)hash_ptr,
1531 (compare_func_type)compare_ptrs);
1535 ** Open the stream PHYSICAL in MODE
1538 TypedStream*
1539 objc_open_typed_stream (FILE* physical, int mode)
1541 TypedStream* s = (TypedStream*)objc_malloc(sizeof(TypedStream));
1543 s->mode = mode;
1544 s->physical = physical;
1545 s->stream_table = hash_new(64,
1546 (hash_func_type)hash_ptr,
1547 (compare_func_type)compare_ptrs);
1548 s->object_table = hash_new(64,
1549 (hash_func_type)hash_ptr,
1550 (compare_func_type)compare_ptrs);
1551 s->eof = (objc_typed_eof_func)__objc_feof;
1552 s->flush = (objc_typed_flush_func)fflush;
1553 s->writing_root_p = 0;
1554 if (mode == OBJC_READONLY)
1556 s->class_table = hash_new(8, (hash_func_type)hash_string,
1557 (compare_func_type)compare_strings);
1558 s->object_refs = hash_new(8, (hash_func_type)hash_ptr,
1559 (compare_func_type)compare_ptrs);
1560 s->read = (objc_typed_read_func)__objc_fread;
1561 s->write = (objc_typed_write_func)__objc_no_write;
1562 __objc_read_typed_stream_signature (s);
1564 else if (mode == OBJC_WRITEONLY)
1566 s->class_table = 0;
1567 s->object_refs = 0;
1568 s->read = (objc_typed_read_func)__objc_no_read;
1569 s->write = (objc_typed_write_func)__objc_fwrite;
1570 __objc_write_typed_stream_signature (s);
1572 else
1574 objc_close_typed_stream (s);
1575 return NULL;
1577 s->type = OBJC_FILE_STREAM;
1578 return s;
1582 ** Open the file named by FILE_NAME in MODE
1585 TypedStream*
1586 objc_open_typed_stream_for_file (const char* file_name, int mode)
1588 FILE* file = NULL;
1589 TypedStream* s;
1591 if (mode == OBJC_READONLY)
1592 file = fopen (file_name, "r");
1593 else
1594 file = fopen (file_name, "w");
1596 if (file)
1598 s = objc_open_typed_stream (file, mode);
1599 if (s)
1600 s->type |= OBJC_MANAGED_STREAM;
1601 return s;
1603 else
1604 return NULL;
1608 ** Close STREAM freeing the structure it self. If it was opened with
1609 ** objc_open_typed_stream_for_file, the file will also be closed.
1612 void
1613 objc_close_typed_stream (TypedStream* stream)
1615 if (stream->mode == OBJC_READONLY)
1617 __objc_finish_read_root_object (stream); /* Just in case... */
1618 hash_delete (stream->class_table);
1619 hash_delete (stream->object_refs);
1622 hash_delete (stream->stream_table);
1623 hash_delete (stream->object_table);
1625 if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
1626 fclose ((FILE*)stream->physical);
1628 objc_free(stream);
1631 BOOL
1632 objc_end_of_typed_stream (TypedStream* stream)
1634 return (*stream->eof)(stream->physical);
1637 void
1638 objc_flush_typed_stream (TypedStream* stream)
1640 (*stream->flush)(stream->physical);
1643 long
1644 objc_get_stream_class_version (TypedStream* stream, Class class)
1646 if (stream->class_table)
1647 return PTR2LONG(hash_value_for_key (stream->class_table, class->name));
1648 else
1649 return class_get_version (class);