Annotation of GNUtools/cc/objc/archive.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.