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