home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / gnu / gcc-2.5.8-src.lha / src / amiga / gcc-2.5.8 / objc / archive.c next >
Encoding:
C/C++ Source or Header  |  1993-11-06  |  34.5 KB  |  1,496 lines

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