OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.git] / gcc / objc / archive.c
1 /* GNU Objective C Runtime archiving
2    Copyright (C) 1993 Free Software Foundation, Inc.
3
4 Author: Kresten Krab Thorup
5
6 This file is part of GNU CC.
7
8 GNU CC is free software; you can redistribute it and/or modify it under the
9    terms of the GNU General Public License as published by the Free Software
10    Foundation; either version 2, or (at your option) any later version.
11
12 GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
13    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15    details.
16
17 You should have received a copy of the GNU General Public License along with
18    GNU CC; see the file COPYING.  If not, write to the Free Software
19    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
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.  */
26
27 /*
28 ** Note: This version assumes that int and longs are both 32bit.
29 **       Most API function are in the bottom of this file.
30 */
31
32 #include "runtime.h"
33 #include <objc/objc-archive.h>
34
35 #define __objc_fatal(format, args...) \
36  { fprintf(stderr, "archining: "); \
37    fprintf(stderr, format, ## args); \
38    fprintf(stderr, "\n"); abort(); }
39
40 /* Declare some functions... */
41
42 static int
43 objc_read_class (struct objc_typed_stream* stream, Class** class);
44
45 static int
46 objc_sizeof_type(const char* type);
47
48 static int
49 objc_write_use_common (struct objc_typed_stream* stream, unsigned int key);
50
51 static int
52 objc_write_register_common (struct objc_typed_stream* stream,
53                             unsigned int key);
54
55 static int 
56 objc_write_class (struct objc_typed_stream* stream,
57                          struct objc_class* class);
58
59 static const char*
60 __objc_skip_type (const char* type);
61
62 static __inline__ int
63 __objc_code_unsigned_char (unsigned char* buf, unsigned char val)
64 {
65   if ((val&_B_VALUE) == val)
66     {
67       buf[0] = val|_B_SINT;
68       return 1;
69     }
70   else
71     {
72       buf[0] = _B_NINT|0x01;
73       buf[1] = val;
74       return 2;
75     }
76 }
77
78 int
79 objc_write_unsigned_char (struct objc_typed_stream* stream,
80                           unsigned char value)
81 {
82   unsigned char buf[sizeof (unsigned char)+1];
83   int len = __objc_code_unsigned_char (buf, value);
84   return (*stream->write)(stream->physical, buf, len);
85 }
86
87 static __inline__ int
88 __objc_code_char (unsigned char* buf, char val)
89 {
90   if (val >= 0)
91     return __objc_code_unsigned_char (buf, val);
92   else
93     {
94       buf[0] = _B_NINT|_B_SIGN|0x01;
95       buf[1] = -val;
96       return 2;
97     }
98 }
99
100 int
101 objc_write_char (struct objc_typed_stream* stream, char value)
102 {
103   unsigned char buf[sizeof (char)+1];
104   int len = __objc_code_char (buf, value);
105   return (*stream->write)(stream->physical, buf, len);
106 }
107
108 static __inline__ int
109 __objc_code_unsigned_short (unsigned char* buf, unsigned short val)
110 {
111   if (val <= 0xffU)
112     return __objc_code_unsigned_char (buf, val);
113
114   else 
115     {
116       buf[0] = _B_NINT|0x02;
117       buf[1] = val/0x100;
118       buf[2] = val%0x100;
119       return 3;
120     }
121 }
122
123 int
124 objc_write_unsigned_short (struct objc_typed_stream* stream, unsigned short value)
125 {
126   unsigned char buf[sizeof (unsigned short)+1];
127   int len = __objc_code_unsigned_short (buf, value);
128   return (*stream->write)(stream->physical, buf, len);
129 }
130       
131 static __inline__ int
132 __objc_code_short (unsigned char* buf, short val)
133 {
134   if (val > 0)
135     return __objc_code_unsigned_short (buf, val);
136
137   if (val > -0x7f)              /* val > -128 */
138     return __objc_code_char (buf, val);
139
140   else 
141     {
142       int len = __objc_code_unsigned_short (buf, -val);
143       buf[0] |= _B_SIGN;
144       return len;
145     }
146 }
147
148 int
149 objc_write_short (struct objc_typed_stream* stream, short value)
150 {
151   unsigned char buf[sizeof (short)+1];
152   int len = __objc_code_short (buf, value);
153   return (*stream->write)(stream->physical, buf, len);
154 }
155       
156
157 static __inline__ int
158 __objc_code_unsigned_int (unsigned char* buf, unsigned int val)
159 {
160   if (val < 0x10000)
161     return __objc_code_unsigned_short (buf, val%0x10000);
162
163   else if (val < 0x1000000)
164     {
165       buf[0] = _B_NINT|3;
166       buf[1] = val/0x10000;
167       buf[2] = (val%0x10000)/0x100;
168       buf[3] = val%0x100;
169       return 4;
170     }
171
172   else 
173     {
174       buf[0] = _B_NINT|4;
175       buf[1] = val/0x1000000;
176       buf[2] = (val%0x1000000)/0x10000;
177       buf[3] = (val%0x10000)/0x100;
178       buf[4] = val%0x100;
179       return 5;
180     }
181 }
182
183 int
184 objc_write_unsigned_int (struct objc_typed_stream* stream, unsigned int value)
185 {
186   unsigned char buf[sizeof(unsigned int)+1];
187   int len = __objc_code_unsigned_int (buf, value);
188   return (*stream->write)(stream->physical, buf, len);
189 }
190
191 static __inline__ int
192 __objc_code_int (unsigned char* buf, int val)
193 {
194   if (val >= 0)
195     return __objc_code_unsigned_int (buf, val);
196
197   if (val > -0x7f)
198     return __objc_code_char (buf, val);
199
200   else 
201     {
202       int len = __objc_code_unsigned_int (buf, -val);
203       buf[0] |= _B_SIGN;
204       return len;
205     }
206 }
207
208 int
209 objc_write_int (struct objc_typed_stream* stream, int value)
210 {
211   unsigned char buf[sizeof(int)+1];
212   int len = __objc_code_int (buf, value);
213   return (*stream->write)(stream->physical, buf, len);
214 }
215
216 int
217 objc_write_string (struct objc_typed_stream* stream,
218                    const unsigned char* string, unsigned int nbytes)
219 {
220   unsigned char buf[sizeof(unsigned int)+1];
221   int len = __objc_code_unsigned_int (buf, nbytes);
222   
223   if ((buf[0]&_B_CODE) == _B_SINT)
224     buf[0] = (buf[0]&_B_VALUE)|_B_SSTR;
225
226   else /* _B_NINT */
227     buf[0] = (buf[0]&_B_VALUE)|_B_NSTR;
228
229   if ((*stream->write)(stream->physical, buf, len) != 0)
230     return (*stream->write)(stream->physical, string, nbytes);
231   else
232     return 0;
233 }
234
235 int
236 objc_write_string_atomic (struct objc_typed_stream* stream,
237                           unsigned char* string, unsigned int nbytes)
238 {
239   unsigned int key;
240   if ((key = (unsigned int)hash_value_for_key (stream->stream_table, string)))
241     return objc_write_use_common (stream, key);
242   else
243     {
244       int length;
245       hash_add (&stream->stream_table, (void*)key=(unsigned int)string, string);
246       if ((length = objc_write_register_common (stream, key)))
247         return objc_write_string (stream, string, nbytes);
248       return length;
249     }
250 }
251
252 static int
253 objc_write_register_common (struct objc_typed_stream* stream, unsigned int key)
254 {
255   unsigned char buf[sizeof (unsigned int)+2];
256   int len = __objc_code_unsigned_int (buf+1, key);
257   if (len == 1)
258     {
259       buf[0] = _B_RCOMM|0x01;
260       buf[1] &= _B_VALUE;
261       return (*stream->write)(stream->physical, buf, len+1);
262     }
263   else
264     {
265       buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
266       return (*stream->write)(stream->physical, buf+1, len);
267     }
268 }
269
270 static int
271 objc_write_use_common (struct objc_typed_stream* stream, unsigned int key)
272 {
273   unsigned char buf[sizeof (unsigned int)+2];
274   int len = __objc_code_unsigned_int (buf+1, key);
275   if (len == 1)
276     {
277       buf[0] = _B_UCOMM|0x01;
278       buf[1] &= _B_VALUE;
279       return (*stream->write)(stream->physical, buf, 2);
280     }
281   else
282     {
283       buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
284       return (*stream->write)(stream->physical, buf+1, len);
285     }
286 }
287
288 static __inline__ int
289 __objc_write_extension (struct objc_typed_stream* stream, unsigned char code)
290 {
291   if (code <= _B_VALUE)
292     {
293       unsigned char buf = code|_B_EXT;
294       return (*stream->write)(stream->physical, &buf, 1);
295     }
296   else 
297     abort();
298 }
299
300 __inline__ int
301 __objc_write_object (struct objc_typed_stream* stream, id object)
302 {
303   unsigned char buf = '\0';
304   SEL write_sel = sel_get_uid ("write:");
305   if (object)
306     {
307       __objc_write_extension (stream, _BX_OBJECT);
308       objc_write_class (stream, object->class_pointer);
309       (*objc_msg_lookup(object, write_sel))(object, write_sel, stream);
310       return (*stream->write)(stream->physical, &buf, 1);
311     }
312   else
313     return objc_write_use_common(stream, 0);
314 }
315
316 int 
317 objc_write_object (struct objc_typed_stream* stream, id object)
318 {
319   unsigned int key;
320   if ((key = (unsigned int)hash_value_for_key (stream->stream_table, object)))
321     return objc_write_use_common (stream, key);
322
323   else if (object == nil)
324     return objc_write_use_common(stream, 0);
325
326   else
327     {
328       int length;
329       hash_add (&stream->stream_table, (void*)key=(unsigned int)object, object);
330       if ((length = objc_write_register_common (stream, key)))
331         return __objc_write_object (stream, object);
332       return length;
333     }
334 }
335
336 __inline__ int
337 __objc_write_class (struct objc_typed_stream* stream, struct objc_class* class)
338 {
339   unsigned char buf = '\0';
340   SEL write_sel = sel_get_uid ("write:");
341   __objc_write_extension (stream, _BX_CLASS);
342   objc_write_string_atomic(stream, (char*)class->name,
343                            strlen(class->name));
344   objc_write_unsigned_int (stream, CLS_GETNUMBER(class));
345   (*objc_msg_lookup(class, write_sel))(class, write_sel, stream);
346   return (*stream->write)(stream->physical, &buf, 1);
347 }
348
349
350 static int 
351 objc_write_class (struct objc_typed_stream* stream,
352                          struct objc_class* class)
353 {
354   unsigned int key;
355   if ((key = (unsigned int)hash_value_for_key (stream->stream_table, class)))
356     return objc_write_use_common (stream, key);
357   else
358     {
359       int length;
360       hash_add (&stream->stream_table, (void*)key=(unsigned int)class, class);
361       if ((length = objc_write_register_common (stream, key)))
362         return __objc_write_class (stream, class);
363       return length;
364     }
365 }
366
367
368 __inline__ int 
369 __objc_write_selector (struct objc_typed_stream* stream, SEL selector)
370 {
371   const char* sel_name = sel_get_name (selector);
372   __objc_write_extension (stream, _BX_SEL);
373   return objc_write_string (stream, sel_name, strlen(sel_name));
374 }
375
376 int 
377 objc_write_selector (struct objc_typed_stream* stream, SEL selector)
378 {
379   const char* sel_name = sel_get_name (selector);
380   unsigned int key;
381   if ((key = (unsigned int)hash_value_for_key (stream->stream_table, sel_name)))
382     return objc_write_use_common (stream, key);
383   else
384     {
385       int length;
386       hash_add (&stream->stream_table, (void*)key=(unsigned int)sel_name, (char*)sel_name);
387       if ((length = objc_write_register_common (stream, key)))
388         return __objc_write_selector (stream, selector);
389       return length;
390     }
391 }
392
393
394
395 /*
396 ** Read operations 
397 */
398
399 __inline__ int
400 objc_read_char (struct objc_typed_stream* stream, char* val)
401 {
402   unsigned char buf;
403   int len;
404   len = (*stream->read)(stream->physical, &buf, 1);
405   if (len != 0)
406     {
407       if ((buf & _B_CODE) == _B_SINT)
408         (*val) = (buf & _B_VALUE);
409
410       else if ((buf & _B_NUMBER) == 1)
411         {
412           len = (*stream->read)(stream->physical, val, 1);
413           if (buf&_B_SIGN)
414             (*val) = -1*(*val);
415         }
416
417       else
418         __objc_fatal("expected 8bit signed int, got %dbit int",
419                      (int)(buf&_B_NUMBER)*8);
420     }
421   return len;
422 }
423
424
425 __inline__ int
426 objc_read_unsigned_char (struct objc_typed_stream* stream, unsigned char* val)
427 {
428   unsigned char buf;
429   int len;
430   if ((len = (*stream->read)(stream->physical, &buf, 1)))
431     {
432       if ((buf & _B_CODE) == _B_SINT)
433         (*val) = (buf & _B_VALUE);
434
435       else if ((buf & _B_NUMBER) == 1)
436         len = (*stream->read)(stream->physical, val, 1);
437
438       else
439         __objc_fatal("expected 8bit unsigned int, got %dbit int",
440                      (int)(buf&_B_NUMBER)*8);
441     }
442   return len;
443 }
444
445 __inline__ int
446 objc_read_short (struct objc_typed_stream* stream, short* value)
447 {
448   unsigned char buf[sizeof(short)+1];
449   int len;
450   if ((len = (*stream->read)(stream->physical, buf, 1)))
451     {
452       if ((buf[0] & _B_CODE) == _B_SINT)
453         (*value) = (buf[0] & _B_VALUE);
454
455       else
456         {
457           int pos = 1;
458           int nbytes = buf[0] & _B_NUMBER;
459           if (nbytes > sizeof (short))
460             __objc_fatal("expected short, got bigger (%dbits)", nbytes*8);
461           len = (*stream->read)(stream->physical, buf+1, nbytes);
462           (*value) = 0;
463           while (pos <= nbytes)
464             (*value) = ((*value)*0x100) + buf[pos++];
465           if (buf[0] & _B_SIGN)
466             (*value) = -(*value);
467         }
468     }
469   return len;
470 }
471
472 __inline__ int
473 objc_read_unsigned_short (struct objc_typed_stream* stream,
474                           unsigned short* value)
475 {
476   unsigned char buf[sizeof(unsigned short)+1];
477   int len;
478   if ((len = (*stream->read)(stream->physical, buf, 1)))
479     {
480       if ((buf[0] & _B_CODE) == _B_SINT)
481         (*value) = (buf[0] & _B_VALUE);
482
483       else
484         {
485           int pos = 1;
486           int nbytes = buf[0] & _B_NUMBER;
487           if (nbytes > sizeof (short))
488             __objc_fatal("expected short, got int or bigger");
489           len = (*stream->read)(stream->physical, buf+1, nbytes);
490           (*value) = 0;
491           while (pos <= nbytes)
492             (*value) = ((*value)*0x100) + buf[pos++];
493         }
494     }
495   return len;
496 }
497
498
499 __inline__ int
500 objc_read_int (struct objc_typed_stream* stream, int* value)
501 {
502   unsigned char buf[sizeof(int)+1];
503   int len;
504   if ((len = (*stream->read)(stream->physical, buf, 1)))
505     {
506       if ((buf[0] & _B_CODE) == _B_SINT)
507         (*value) = (buf[0] & _B_VALUE);
508
509       else
510         {
511           int pos = 1;
512           int nbytes = buf[0] & _B_NUMBER;
513           if (nbytes > sizeof (int))
514             __objc_fatal("expected int, got bigger");
515           len = (*stream->read)(stream->physical, buf+1, nbytes);
516           (*value) = 0;
517           while (pos <= nbytes)
518             (*value) = ((*value)*0x100) + buf[pos++];
519           if (buf[0] & _B_SIGN)
520             (*value) = -(*value);
521         }
522     }
523   return len;
524 }
525
526 __inline__ int
527 __objc_read_nbyte_uint (struct objc_typed_stream* stream,
528                        unsigned int nbytes, unsigned int* val)
529 {
530   int len, pos = 0;
531   unsigned char buf[sizeof(unsigned int)+1];
532
533   if (nbytes > sizeof (int))
534     __objc_fatal("expected int, got bigger");
535
536   len = (*stream->read)(stream->physical, buf, nbytes);
537   (*val) = 0;
538   while (pos < nbytes)
539     (*val) = ((*val)*0x100) + buf[pos++];
540   return len;
541 }
542   
543
544 __inline__ int
545 objc_read_unsigned_int (struct objc_typed_stream* stream,
546                         unsigned int* value)
547 {
548   unsigned char buf[sizeof(unsigned int)+1];
549   int len;
550   if ((len = (*stream->read)(stream->physical, buf, 1)))
551     {
552       if ((buf[0] & _B_CODE) == _B_SINT)
553         (*value) = (buf[0] & _B_VALUE);
554
555       else
556         len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value);
557
558     }
559   return len;
560 }
561
562 __inline__ int
563 objc_read_string (struct objc_typed_stream* stream,
564                   char** string)
565 {
566   unsigned char buf[sizeof(unsigned int)+1];
567   int len;
568   if ((len = (*stream->read)(stream->physical, buf, 1)))
569     {
570       unsigned int key = 0;
571
572       if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
573         {
574           len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
575           len = (*stream->read)(stream->physical, buf, 1);
576         }
577
578       switch (buf[0]&_B_CODE) {
579       case _B_SSTR:
580         {
581           int length = buf[0]&_B_VALUE;
582           (*string) = (char*)malloc(length+1);
583           if (key)
584             hash_add (&stream->stream_table, (void*)key, *string);
585           len = (*stream->read)(stream->physical, *string, length);
586           (*string)[length] = '\0';
587         }
588         break;
589
590       case _B_UCOMM:
591         {
592           len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
593           (*string) = hash_value_for_key (stream->stream_table, (void*)key);
594         }
595         break;
596
597       case _B_NSTR:
598         {
599           unsigned int nbytes = buf[0]&_B_VALUE;
600           len = __objc_read_nbyte_uint(stream, nbytes, &nbytes);
601           if (len) {
602             (*string) = (char*)malloc(nbytes);
603             if (key)
604               hash_add (&stream->stream_table, (void*)key, *string);
605             len = (*stream->read)(stream->physical, *string, buf[0]&_B_VALUE);
606             (*string)[nbytes] = '\0';
607           }
608         }
609         break;
610         
611       default:
612         __objc_fatal("expected string, got opcode %c\n", (buf[0]&_B_CODE));
613       }
614     }
615
616   return len;
617 }
618
619
620 int
621 objc_read_object (struct objc_typed_stream* stream, id* object)
622 {
623   unsigned char buf[sizeof (unsigned int)];
624   int len;
625   if ((len = (*stream->read)(stream->physical, buf, 1)))
626     {
627       SEL read_sel = sel_get_uid ("read:");
628       unsigned int key = 0;
629
630       if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */
631         {
632           len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
633           len = (*stream->read)(stream->physical, buf, 1);
634         }
635
636       if (buf[0] == (_B_EXT | _BX_OBJECT))
637         {
638           Class* class;
639
640           /* get class */
641           len = objc_read_class (stream, &class);
642
643           /* create instance */
644           (*object) = class_create_instance(class);
645
646           /* register? */
647           if (key)
648             hash_add (&stream->stream_table, (void*)key, *object);
649
650           /* send -read: */
651           if (__objc_responds_to (*object, read_sel))
652             (*get_imp(class, read_sel))(*object, read_sel, stream);
653
654           /* check null-byte */
655           len = (*stream->read)(stream->physical, buf, 1);
656           if (buf[0] != '\0')
657             __objc_fatal("expected null-byte, got opcode %c", buf[0]);
658         }
659
660       else if ((buf[0]&_B_CODE) == _B_UCOMM)
661         {
662           if (key)
663             __objc_fatal("cannot register use upcode...");
664           len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
665           (*object) = hash_value_for_key (stream->stream_table, (void*)key);
666         }
667
668       else
669         __objc_fatal("expected object, got opcode %c", buf[0]);
670     }
671   return len;
672 }
673
674 static int
675 objc_read_class (struct objc_typed_stream* stream, Class** class)
676 {
677   unsigned char buf[sizeof (unsigned int)];
678   int len;
679   if ((len = (*stream->read)(stream->physical, buf, 1)))
680     {
681       SEL read_sel = sel_get_uid ("read:");
682       unsigned int key = 0;
683
684       if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
685         {
686           len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
687           len = (*stream->read)(stream->physical, buf, 1);
688         }
689
690       if (buf[0] == (_B_EXT | _BX_CLASS))
691         {
692           char* class_name;
693           int version;
694
695           /* get class */
696           len = objc_read_string (stream, &class_name);
697           (*class) = objc_get_class(class_name);
698           free (class_name);
699
700           /* register */
701           if (key)
702             hash_add (&stream->stream_table, (void*)key, *class);
703
704           /* call +read: */
705           (*objc_msg_lookup(*class, read_sel))(*class, read_sel, stream);
706
707           objc_read_unsigned_int(stream, &version);
708           hash_add (&stream->class_table, (*class)->name, (void*)version);
709
710           /* check null-byte */
711           len = (*stream->read)(stream->physical, buf, 1);
712           if (buf[0] != '\0')
713             __objc_fatal("expected null-byte, got opcode %c", buf[0]);
714         }
715
716       else if ((buf[0]&_B_CODE) == _B_UCOMM)
717         {
718           if (key)
719             __objc_fatal("cannot register use upcode...");
720           len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
721           (*class) = hash_value_for_key (stream->stream_table, (void*)key);
722           if (!*class)
723             __objc_fatal("cannot find class for key %x", key);
724         }
725
726       else
727         __objc_fatal("expected class, got opcode %c", buf[0]);
728     }
729   return len;
730 }
731
732 int
733 objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
734 {
735   unsigned char buf[sizeof (unsigned int)];
736   int len;
737   if ((len = (*stream->read)(stream->physical, buf, 1)))
738     {
739       unsigned int key = 0;
740
741       if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
742         {
743           len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
744           len = (*stream->read)(stream->physical, buf, 1);
745         }
746
747       if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
748         {
749           char* selector_name;
750
751           /* get selector */
752           len = objc_read_string (stream, &selector_name);
753           (*selector) = sel_get_uid(selector_name);
754           free (selector_name);
755
756           /* register */
757           if (key)
758             hash_add (&stream->stream_table, (void*)key, *selector);
759         }
760
761       else if ((buf[0]&_B_CODE) == _B_UCOMM)
762         {
763           if (key)
764             __objc_fatal("cannot register use upcode...");
765           len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
766           (*selector) = hash_value_for_key (stream->stream_table, (void*)key);
767         }
768
769       else
770         __objc_fatal("expected selector, got opcode %c", buf[0]);
771     }
772   return len;
773 }
774
775 static int
776 objc_sizeof_type(const char* type)
777 {
778   switch(*type) {
779   case _C_ID: return sizeof(id);
780     break;
781
782   case _C_CLASS:
783     return sizeof(Class*);
784     break;
785
786   case _C_SEL:
787     return sizeof(SEL);
788     break;
789
790   case _C_CHR:
791     return sizeof(char);
792     break;
793     
794   case _C_UCHR:
795     return sizeof(unsigned char);
796     break;
797
798   case _C_SHT:
799     return sizeof(short);
800     break;
801
802   case _C_USHT:
803     return sizeof(unsigned short);
804     break;
805
806   case _C_INT:
807   case _C_LNG:
808     return sizeof(int);
809     break;
810
811   case _C_UINT:
812   case _C_ULNG:
813     return sizeof(unsigned int);
814     break;
815
816   case _C_ATOM:
817   case _C_CHARPTR:
818     return sizeof(char*);
819     break;
820
821   default:
822     fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
823     abort();
824   }
825 }
826
827
828 static const char*
829 __objc_skip_type (const char* type)
830 {
831   switch (*type) {
832   case _C_ID:
833   case _C_CLASS:
834   case _C_SEL:
835   case _C_CHR:
836   case _C_UCHR:
837   case _C_CHARPTR:
838   case _C_ATOM:
839   case _C_SHT:
840   case _C_USHT:
841   case _C_INT:
842   case _C_UINT:
843   case _C_LNG:
844   case _C_ULNG:
845   case _C_FLT:
846   case _C_DBL:
847     return ++type;
848     break;
849
850   case _C_ARY_B:
851     while(isdigit(*++type));
852     type = __objc_skip_type(type);
853     if (*type == _C_ARY_E)
854       return ++type;
855     else
856       __objc_fatal("cannot parse typespec: %s", type);
857     break;
858
859   default:
860     fprintf(stderr, "objc_read_types: cannot parse typespec: %s\n", type);
861     abort();
862   }
863 }
864
865 /*
866 ** USER LEVEL FUNCTIONS
867 */
868
869 /*
870 ** Write one object, encoded in TYPE and pointed to by DATA to the
871 ** typed stream STREAM.  
872 */
873
874 int
875 objc_write_type(TypedStream* stream, const char* type, const void* data)
876 {
877   switch(*type) {
878   case _C_ID:
879     return objc_write_object (stream, *(id*)data);
880     break;
881
882   case _C_CLASS:
883     return objc_write_class (stream, *(Class**)data);
884     break;
885
886   case _C_SEL:
887     return objc_write_selector (stream, *(SEL*)data);
888     break;
889
890   case _C_CHR:
891     return objc_write_char(stream, *(char*)data);
892     break;
893     
894   case _C_UCHR:
895     return objc_write_unsigned_char(stream, *(unsigned char*)data);
896     break;
897
898   case _C_SHT:
899     return objc_write_short(stream, *(short*)data);
900     break;
901
902   case _C_USHT:
903     return objc_write_unsigned_short(stream, *(unsigned short*)data);
904     break;
905
906   case _C_INT:
907   case _C_LNG:
908     return objc_write_int(stream, *(int*)data);
909     break;
910
911   case _C_UINT:
912   case _C_ULNG:
913     return objc_write_unsigned_int(stream, *(unsigned int*)data);
914     break;
915
916   case _C_CHARPTR:
917     return objc_write_string (stream, (char*)data, strlen((char*)data));
918     break;
919
920   case _C_ATOM:
921     return objc_write_string_atomic (stream, (char*)data, strlen((char*)data));
922     break;
923
924   case _C_ARY_B:
925     {
926       int len = atoi(type+1);
927       while (isdigit(*++type));
928       return objc_write_array (stream, type, len, data);
929     }
930     break; 
931
932   default:
933     fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
934     abort();
935   }
936 }
937
938 /*
939 ** Read one object, encoded in TYPE and pointed to by DATA to the
940 ** typed stream STREAM.  DATA specifies the address of the types to
941 ** read.  Expected type is checked against the type actually present
942 ** on the stream. 
943 */
944
945 int
946 objc_read_type(TypedStream* stream, const char* type, void* data)
947 {
948   char c;
949   switch(c = *type) {
950   case _C_ID:
951     return objc_read_object (stream, (id*)data);
952     break;
953
954   case _C_CLASS:
955     return objc_read_class (stream, (Class**)data);
956     break;
957
958   case _C_SEL:
959     return objc_read_selector (stream, (SEL*)data);
960     break;
961
962   case _C_CHR:
963     return objc_read_char (stream, (char*)data);
964     break;
965     
966   case _C_UCHR:
967     return objc_read_unsigned_char (stream, (unsigned char*)data);
968     break;
969
970   case _C_SHT:
971     return objc_read_short (stream, (short*)data);
972     break;
973
974   case _C_USHT:
975     return objc_read_unsigned_short (stream, (unsigned short*)data);
976     break;
977
978   case _C_INT:
979   case _C_LNG:
980     return objc_read_int (stream, (int*)data);
981     break;
982
983   case _C_UINT:
984   case _C_ULNG:
985     return objc_read_unsigned_int (stream, (unsigned int*)data);
986     break;
987
988   case _C_CHARPTR:
989   case _C_ATOM:
990     return objc_read_string (stream, (char**)data);
991     break;
992
993   case _C_ARY_B:
994     {
995       int len = atoi(type+1);
996       while (isdigit(*++type));
997       return objc_read_array (stream, type, len, data);
998     }
999     break; 
1000
1001   default:
1002     fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
1003     abort();
1004   }
1005 }
1006
1007 /*
1008 ** Write the object specified by the template TYPE to STREAM.  Last
1009 ** arguments specify addresses of values to be written.  It might 
1010 ** seem surprising to specify values by address, but this is extremely
1011 ** convenient for copy-paste with objc_read_types calls.  A more
1012 ** down-to-the-earth cause for this passing of addresses is that values
1013 ** of arbitrary size is not well supported in ANSI C for functions with
1014 ** variable number of arguments.
1015 */
1016
1017 int 
1018 objc_write_types (TypedStream* stream, const char* type, ...)
1019 {
1020   va_list args;
1021   const char *c;
1022   int res = 0;
1023
1024   va_start(args, type);
1025
1026   for (c = type; *c; c = __objc_skip_type (c))
1027     {
1028       switch(*c) {
1029       case _C_ID:
1030         res = objc_write_object (stream, *va_arg (args, id*));
1031         break;
1032
1033       case _C_CLASS:
1034         res = objc_write_class (stream, *va_arg(args, Class**));
1035         break;
1036
1037       case _C_SEL:
1038         res = objc_write_selector (stream, *va_arg(args, SEL*));
1039         break;
1040         
1041       case _C_CHR:
1042         res = objc_write_char (stream, *va_arg (args, char*));
1043         break;
1044         
1045       case _C_UCHR:
1046         res = objc_write_unsigned_char (stream,
1047                                         *va_arg (args, unsigned char*));
1048         break;
1049         
1050       case _C_SHT:
1051         res = objc_write_short (stream, *va_arg(args, short*));
1052         break;
1053
1054       case _C_USHT:
1055         res = objc_write_unsigned_short (stream,
1056                                          *va_arg(args, unsigned short*));
1057         break;
1058
1059       case _C_INT:
1060       case _C_LNG:
1061         res = objc_write_int(stream, *va_arg(args, int*));
1062         break;
1063         
1064       case _C_UINT:
1065       case _C_ULNG:
1066         res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*));
1067         break;
1068
1069       case _C_CHARPTR:
1070         {
1071           char* str = va_arg(args, char*);
1072           res = objc_write_string (stream, str, strlen(str));
1073         }
1074         break;
1075
1076       case _C_ATOM:
1077         {
1078           char* str = va_arg(args, char*);
1079           res = objc_write_string_atomic (stream, str, strlen(str));
1080         }
1081         break;
1082
1083       case _C_ARY_B:
1084         {
1085           int len = atoi(c+1);
1086           const char* t = c;
1087           while (isdigit(*++t));
1088           res = objc_write_array (stream, t, len, va_arg(args, void*));
1089           t = __objc_skip_type (t);
1090           if (*t != _C_ARY_E)
1091             __objc_fatal("expected `]', got: %s", t);
1092         }
1093         break; 
1094         
1095       default:
1096         fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
1097         abort();
1098       }
1099     }
1100   va_end(args);
1101   return res;
1102 }
1103
1104
1105 /* 
1106 ** Last arguments specify addresses of values to be read.  Expected
1107 ** type is checked against the type actually present on the stream. 
1108 */
1109
1110 int 
1111 objc_read_types(TypedStream* stream, const char* type, ...)
1112 {
1113   va_list args;
1114   const char *c;
1115   int res = 0;
1116
1117   va_start(args, type);
1118
1119   for (c = type; *c; c = __objc_skip_type(c))
1120     {
1121       switch(*c) {
1122       case _C_ID:
1123         res = objc_read_object(stream, va_arg(args, id*));
1124         break;
1125
1126       case _C_CLASS:
1127         res = objc_read_class(stream, va_arg(args, Class**));
1128         break;
1129
1130       case _C_SEL:
1131         res = objc_read_selector(stream, va_arg(args, SEL*));
1132         break;
1133         
1134       case _C_CHR:
1135         res = objc_read_char(stream, va_arg(args, char*));
1136         break;
1137         
1138       case _C_UCHR:
1139         res = objc_read_unsigned_char(stream, va_arg(args, unsigned char*));
1140         break;
1141         
1142       case _C_SHT:
1143         res = objc_read_short(stream, va_arg(args, short*));
1144         break;
1145
1146       case _C_USHT:
1147         res = objc_read_unsigned_short(stream, va_arg(args, unsigned short*));
1148         break;
1149
1150       case _C_INT:
1151       case _C_LNG:
1152         res = objc_read_int(stream, va_arg(args, int*));
1153         break;
1154         
1155       case _C_UINT:
1156       case _C_ULNG:
1157         res = objc_read_unsigned_int(stream, va_arg(args, unsigned int*));
1158         break;
1159
1160       case _C_CHARPTR:
1161       case _C_ATOM:
1162         {
1163           char** str = va_arg(args, char**);
1164           res = objc_read_string (stream, str);
1165         }
1166         break;
1167
1168       case _C_ARY_B:
1169         {
1170           int len = atoi(c+1);
1171           const char* t = c;
1172           while (isdigit(*++t));
1173           res = objc_read_array (stream, t, len, va_arg(args, void*));
1174           t = __objc_skip_type (t);
1175           if (*t != _C_ARY_E)
1176             __objc_fatal("expected `]', got: %s", t);
1177         }
1178         break; 
1179         
1180       default:
1181         fprintf(stderr, "objc_read_type: cannot parse typespec: %s\n", type);
1182         abort();
1183       }
1184     }
1185   va_end(args);
1186   return res;
1187 }
1188
1189 /*
1190 ** Write an array of COUNT elements of TYPE from the memory address DATA.
1191 ** This is equivalent of objc_write_type (stream, "[N<type>]", data)
1192 */
1193
1194 int
1195 objc_write_array (TypedStream* stream, const char* type,
1196                   int count, const void* data)
1197 {
1198   int off = objc_sizeof_type(type);
1199   const char* where = data;
1200
1201   while (count-- > 0)
1202     {
1203       objc_write_type(stream, type, where);
1204       where += off;
1205     }
1206   return 1;
1207 }
1208
1209 /*
1210 ** Read an array of COUNT elements of TYPE into the memory address
1211 ** DATA.  The memory pointed to by data is supposed to be allocated
1212 ** by the callee.  This is equivalent of 
1213 **   objc_read_type (stream, "[N<type>]", data)
1214 */
1215
1216 int
1217 objc_read_array (TypedStream* stream, const char* type,
1218                  int count, void* data)
1219 {
1220   int off = objc_sizeof_type(type);
1221   char* where = (char*)data;
1222
1223   while (count-- > 0)
1224     {
1225       objc_read_type(stream, type, where);
1226       where += off;
1227     }
1228   return 1;
1229 }
1230
1231 static int 
1232 __objc_fread(FILE* file, char* data, int len)
1233 {
1234   return fread(data, len, 1, file);
1235 }
1236
1237 static int 
1238 __objc_fwrite(FILE* file, char* data, int len)
1239 {
1240   return fwrite(data, len, 1, file);
1241 }
1242
1243 static int
1244 __objc_feof(FILE* file)
1245 {
1246   return feof(file);
1247 }
1248
1249 static int 
1250 __objc_no_write(FILE* file, char* data, int len)
1251 {
1252   __objc_fatal ("TypedStream not open for writing");
1253 }
1254
1255 static int 
1256 __objc_no_read(FILE* file, char* data, int len)
1257 {
1258   __objc_fatal ("TypedStream not open for reading");
1259 }
1260
1261 static int
1262 __objc_read_typed_stream_signature (TypedStream* stream)
1263 {
1264   char buffer[80];
1265   int pos = 0;
1266   do
1267     (*stream->read)(stream->physical, buffer+pos, 1);
1268   while (buffer[pos++] != '\0');
1269   sscanf (buffer, "GNU TypedStream %d", &stream->version);
1270   if (stream->version != OBJC_TYPED_STREAM_VERSION)
1271     __objc_fatal ("cannot handle TypedStream version %d", stream->version);
1272 }
1273
1274 static int
1275 __objc_write_typed_stream_signature (TypedStream* stream)
1276 {
1277   char buffer[80];
1278   sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
1279   stream->version = OBJC_TYPED_STREAM_VERSION;
1280   (*stream->write)(stream->physical, buffer, strlen(buffer)+1);
1281 }
1282
1283 /*
1284 ** Open the stream PHYSICAL in MODE
1285 */
1286
1287 TypedStream* 
1288 objc_open_typed_stream (FILE* physical, int mode)
1289 {
1290   int fflush(FILE*);
1291
1292   TypedStream* s = (TypedStream*)malloc(sizeof(TypedStream));
1293
1294   s->mode = mode;
1295   s->physical = physical;
1296   s->stream_table = hash_new(64,
1297                              (hash_func_type)hash_ptr,
1298                              (compare_func_type)compare_ptrs);
1299   s->eof = (objc_typed_eof_func)__objc_feof;
1300   s->flush = (objc_typed_flush_func)fflush;
1301   if (mode == OBJC_READONLY)
1302     {
1303       s->class_table = hash_new(8, (hash_func_type)hash_string,
1304                                 (compare_func_type)compare_strings);
1305       s->read = (objc_typed_read_func)__objc_fread;
1306       s->write = (objc_typed_write_func)__objc_no_write;
1307       __objc_read_typed_stream_signature (s);
1308     }
1309   else if (mode == OBJC_WRITEONLY)
1310     {
1311       s->class_table = 0;
1312       s->read = (objc_typed_read_func)__objc_no_read;
1313       s->write = (objc_typed_write_func)__objc_fwrite;
1314       __objc_write_typed_stream_signature (s);
1315     }      
1316   else
1317     {
1318       objc_close_typed_stream (s);
1319       return NULL;
1320     }
1321   s->type = OBJC_FILE_STREAM;
1322   return s;
1323 }
1324
1325 /*
1326 ** Open the file named by FILE_NAME in MODE
1327 */
1328
1329 TypedStream*
1330 objc_open_typed_stream_for_file (const char* file_name, int mode)
1331 {
1332   FILE* file = NULL;
1333   TypedStream* s;
1334
1335   if (mode == OBJC_READONLY)
1336     file = fopen (file_name, "r");
1337   else
1338     file = fopen (file_name, "w");
1339
1340   if (file)
1341     {
1342       s = objc_open_typed_stream (file, mode);
1343       if (s)
1344         s->type |= OBJC_MANAGED_STREAM;
1345       return s;
1346     }
1347   else
1348     return NULL;
1349 }
1350
1351 /*
1352 ** Close STREAM freeing the structure it self.  If it was opened with 
1353 ** objc_open_typed_stream_for_file, the file will also be closed.
1354 */
1355
1356 void
1357 objc_close_typed_stream (TypedStream* stream)
1358 {
1359   if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
1360     fclose ((FILE*)stream->physical);
1361   hash_delete (stream->stream_table);
1362   if (stream->mode == OBJC_READONLY)
1363     hash_delete (stream->class_table);
1364   free (stream);
1365 }
1366
1367 BOOL
1368 objc_end_of_typed_stream (TypedStream* stream)
1369 {
1370   return (*stream->eof)(stream->physical);
1371 }
1372
1373 void
1374 objc_flush_typed_stream (TypedStream* stream)
1375 {
1376   (*stream->flush)(stream->physical);
1377 }
1378