ftp.nice.ch/pub/next/developer/resources/libraries/libobjects.0.1.0.s.tar.gz#/libobjects-0.1.0/BinaryCoder.m

This is BinaryCoder.m in view mode; [Download] [Up]

/* Implementation of GNU Objective-C binary coder object for use serializing
   Copyright (C) 1994 Free Software Foundation, Inc.
   
   Written by:  R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
   Date: July 1994
   
   This file is part of the GNU Objective C Class Library.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */ 

#include <objects/stdobjects.h>
#include <objects/BinaryCoder.h>
#include <objects/MemoryStream.h>
#include <assert.h>
#include <objects/StdioStream.h>
#include <objects/TextCoder.h>

#define CONCRETE_FORMAT_VERSION 0

static BOOL debug_binary_coder = NO;

@implementation BinaryCoder

+ setDebugging: (BOOL)f
{
  debug_binary_coder = f;
  return self;
}

+ (TextCoder*) debugStderrCoder
{
  static TextCoder* c = nil;

  if (!c)
    c = [[TextCoder alloc] initEncodingOnStream:[StdioStream standardError]];
  return c;
}

+ (int) coderConcreteFormatVersion
{
  return CONCRETE_FORMAT_VERSION;
}

/* Careful, this shouldn't contain newlines */
+ (const char *) coderSignature
{
  return "GNU Objective C Class Library BinaryCoder";
}

- doInitOnStream: (Stream *)s isDecoding: (BOOL)f
{
  [super doInitOnStream:s isDecoding:f];
  return self;
}

- (void) encodeValueOfSimpleType: (const char*)type 
   at: (const void*)d 
   withName: (const char *)name
{
  unsigned char size;

  if (debug_binary_coder)
    {
      [[BinaryCoder debugStderrCoder] 
       encodeValueOfSimpleType:type
       at:d
       withName:name];
    }
  assert(type);
  assert(*type != '@');
  assert(*type != '^');
  assert(*type != ':');
  assert(*type != '{');
  assert(*type != '[');

  /* A fairly stupid, inefficient binary encoding.  This could use 
     some improvement.  For instance, we could compress the sign
     information and the type information.
     It could probably also use some portability fixes. */
  [stream writeByte:*type];
  size = objc_sizeof_type(type);
  [stream writeByte:size];
  switch (*type)
    {
    case _C_CHARPTR:
      {
	int length = strlen(*(char**)d);
	[self encodeValueOfSimpleType:@encode(int)
	      at:&length withName:"BinaryCoder char* length"];
	[stream writeBytes:*(char**)d length:length];
	break;
      }

    case _C_CHR:
      if (*(char*)d < 0)
	[stream writeByte:1];
      else
	[stream writeByte:0];
    case _C_UCHR:
      [stream writeByte:*(unsigned char*)d];
      break;

    case _C_SHT:
      if (*(short*)d < 0)
	[stream writeByte:1];
      else
	[stream writeByte:0];
    case _C_USHT:
      {
	unsigned char *buf = alloca(size);
	short s = *(short*)d;
	int count = size;
	if (s < 0) s = -s;
	for (; count--; s >>= 8)
	  buf[count] = (char) (s % 0x100);
	[stream writeBytes:buf length:size];
	break;
      }

    case _C_INT:
      if (*(int*)d < 0)
	[stream writeByte:1];
      else
	[stream writeByte:0];
    case _C_UINT:
      {
	unsigned char *buf = alloca(size);
	int s = *(int*)d;
	int count = size;
	if (s < 0) s = -s;
	for (; count--; s >>= 8)
	  buf[count] = (char) (s % 0x100);
	[stream writeBytes:buf length:size];
	break;
      }

    case _C_LNG:
      if (*(long*)d < 0)
	[stream writeByte:1];
      else
	[stream writeByte:0];
    case _C_ULNG:
      {
	unsigned char *buf = alloca(size);
	long s = *(long*)d;
	int count = size;
	if (s < 0) s = -s;
	for (; count--; s >>= 8)
	  buf[count] = (char) (s % 0x100);
	[stream writeBytes:buf length:size];
	break;
      }

    /* Two quickie kludges to make archiving of floats and doubles work */
    case _C_FLT:
      {
	char buf[64];
	char *s = buf;
	sprintf(buf, "%f", *(float*)d);
	[self encodeValueOfSimpleType:@encode(char*)
	      at:&s withName:"BinaryCoder float"];
	break;
      }
    case _C_DBL:
      {
	char buf[64];
	char *s = buf;
	sprintf(buf, "%f", *(double*)d);
	[self encodeValueOfSimpleType:@encode(char*)
	      at:&s withName:"BinaryCoder double"];
	break;
      }
    default:
      [self error:"Unrecognized Type %s", type];
    }
}

- (void) decodeValueOfSimpleType: (const char*)type
   at: (void*)d 
   withName: (const char **)namePtr
{
  char encoded_type;
  unsigned char encoded_size;
  unsigned char encoded_sign = 0;

  assert(type);
  assert(*type != '@');
  assert(*type != '^');
  assert(*type != ':');
  assert(*type != '{');
  assert(*type != '[');

  [stream readByte:&encoded_type];
  if (encoded_type != *type 
      && !((encoded_type=='c' || encoded_type=='C') 
	   && (*type=='c' || *type=='C')))
    [self error:"Expected type \"%c\", got type \"%c\"", *type, encoded_type];
  [stream readByte:&encoded_size];
  switch (encoded_type)
    {
    case _C_CHARPTR:
      {
	int length;
	[self decodeValueOfSimpleType:@encode(int)
	      at:&length withName:NULL];
	OBJC_MALLOC(*(char**)d, char, length+1);
	[stream readBytes:*(char**)d length:length];
	(*(char**)d)[length] = '\0';
	break;
      }

    case _C_CHR:
      [stream readByte:&encoded_sign];
    case _C_UCHR:
      [stream readByte:(unsigned char*)d];
      if (encoded_sign)
	*(char*)d = *(char*)d * -1;
      break;

    case _C_SHT:
      [stream readByte:&encoded_sign];
    case _C_USHT:
      {
	unsigned char *buf = alloca(encoded_size);
	int i;
	short s = 0;
	[stream readBytes:buf length:encoded_size];
	for (i = 0; i < sizeof(short); i++)
	  {
	    s <<= 8;
	    s += buf[i];
	  }
	if (encoded_sign)
	  s = -s;
	*(short*)d = s;
	break;
      }

    case _C_INT:
      [stream readByte:&encoded_sign];
    case _C_UINT:
      {
	unsigned char *buf = alloca(encoded_size);
	int i;
	int s = 0;
	[stream readBytes:buf length:encoded_size];
	for (i = 0; i < sizeof(int); i++)
	  {
	    s <<= 8;
	    s += buf[i];
	  }
	if (encoded_sign)
	  s = -s;
	*(int*)d = s;
	break;
      }

    case _C_LNG:
      [stream readByte:&encoded_sign];
    case _C_ULNG:
      {
	unsigned char *buf = alloca(encoded_size);
	int i;
	long s = 0;
	[stream readBytes:buf length:encoded_size];
	for (i = 0; i < sizeof(long); i++)
	  {
	    s <<= 8;
	    s += buf[i];
	  }
	if (encoded_sign)
	  s = -s;
	*(long*)d = s;
	break;
      }

  /* Two quickie kludges to make archiving of floats and doubles work */
    case _C_FLT:
      {
	char *buf;
	[self decodeValueOfSimpleType:@encode(char*) at:&buf withName:NULL];
	if (sscanf(buf, "%f", (float*)d) != 1)
	  [self error:"expected float, got %s", buf];
	(*objc_free)(buf);
	break;
      }
    case _C_DBL:
      {
	char *buf;
	[self decodeValueOfSimpleType:@encode(char*) at:&buf withName:NULL];
	if (sscanf(buf, "%lf", (double*)d) != 1)
	  [self error:"expected double, got %s", buf];
	(*objc_free)(buf);
	break;
      }
    default:
      [self error:"Unrecognized Type %s", type];
    }

  if (debug_binary_coder)
    {
      [[BinaryCoder debugStderrCoder] 
       encodeValueOfSimpleType:type
       at:d
       withName:"decoding unnamed"];
    }
}

- (void) encodeName: (const char *)name
{
  if (debug_binary_coder)
    [[BinaryCoder debugStderrCoder]
     encodeName:name];
}

@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.