/* Implementation for GSCoder
 *
 * Copyright (C)  1993  The Board of Trustees of  
 * The Leland Stanford Junior University.  All Rights Reserved.
 *
 * Authors: Pau Kunz
 *
 * This file is part of an Objective-C library
 *
 * GSCoder.m,v 1.9 1995/07/03 18:15:17 pfkeb Exp
 */
 
/* Based on 
 * (Preliminary Documentation) Copyright (c) 1994 by NeXT Computer, Inc.  
 * All Rights Reserved.
 *
 * An implementation of NSCoder that uses GNU TypedStream
 *
 */
 
#include "GSCoder.h"

#include <Foundation/NSString.h>
#include <appkit/graphics.h>
#ifdef __NeXT__
#include <objc/objc-runtime.h>
#include <gnuarchive/encoding.h>
#include <gnuarchive/objc/typedstream.h>
#else
#include <objc/encoding.h>
#include <objc/typedstream.h>
#endif
#include <streams/streams.h>
#include <stdarg.h>           /* for ANSI programs */
#include <stdlib.h>

#define CODER_MAX_VAR_ARGS 10

@implementation GSCoder

// Encoding Data

- (void)encodeArrayOfObjCType:(const char *)types
                        count:(unsigned)count
                           at:(const void *)array
{
    objc_write_array( stream, types, count, array);
    return;  
}
		
- (void)encodeBycopyObject:(id)anObject;
{
    [self encodeObject:anObject];
    return;
}

- (void)encodeConditionalObject:(id)anObject;
{
    [self encodeObject:anObject];
    return;
}
  
// - (void)encodeDataObject:(NSData *)data;
 
- (void)encodeObject:(id)anObject
{
    objc_write_object( stream, anObject);
    return;
}

- (void)encodeObjectReference:(id)anObject
{
    objc_write_object_reference( stream, anObject);
    return;
}

// - (void)encodePropertyList:(id)plist;
// - (void)encodePoint:(NSPoint)point;
- (void)encodeRect:(NXRect)rect
{
    int box[4];
    
    box[0] = rect.origin.x;
    box[1] = rect.origin.y;
    box[2] = rect.size.width;
    box[3] = rect.size.height;
    [self encodeArrayOfObjCType:"i" count:4 at:box];
    return;
}
 
- (void)encodeRootObject:(id)rootObject
{
    objc_write_root_object( stream, rootObject);
    return;
}

- (void)encodeSize:(NXSize)size
{
    int		rect[2];
    
    rect[0] = size.width;
    rect[1] = size.height;
    [self encodeArrayOfObjCType:"i" count:2 at:rect];
    return;
}

- (void)encodeColor:(NXColor *)aColor
{
    char	*nullstring = "";
    
    [self encodeArrayOfObjCType:"S" count:6 at:&aColor->colorField];
    if ( aColor->str ) {
	[self encodeValueOfObjCType:"*" at:&aColor->str];
    } else {
	[self encodeValueOfObjCType:"*" at:&nullstring];
    }
    return;
}

- (void)encodeValueOfObjCType:(const char *)type
                           at:(const void *)address
{
    objc_write_type( stream, type, address );
    return;
}
	
- (void)encodeValuesOfObjCTypes:(const char *)types,  ...
{
    va_list	args;
    const char	*c;
    char	*where[CODER_MAX_VAR_ARGS];
    int		i;

    va_start(args, types);
    for ( c = types, i = 0; *c; c = objc_skip_typespec(c) ) {
        if ( i < CODER_MAX_VAR_ARGS ) {
            where[i++] = va_arg(args, char*);
	} else {
	    printf( "[NXCoder decodeValuesOfObjCTypes]:"
	    	    " Maximum number of args exceeded\n");
	    return;
	}
    }
    va_end(args);
    objc_write_types(stream, types, where[0], where[1], where[2], where[3],
	           where[4], where[5], where[6], where[7], where[8], where[9]);
    return;
}

// Decoding Data

- (void)decodeArrayOfObjCType:(const char *)types
                        count:(unsigned)count
                           at:(void *)address
{
    objc_read_array( stream, types, count, address );
    return;
}
		
// - (NSData *)decodeDataObject;
 
- (id)decodeObject
{
    id 	object;
    
    objc_read_object( stream, &object );
    return object;
}

// - (id)decodePropertyList;
// - (NSPoint)decodePoint;

- (NXRect)decodeRect
{
    NXRect	rect;
    int		box[4];

    [self decodeArrayOfObjCType:"i" count:4 at:box];
    rect.origin.x = box[0];
    rect.origin.y = box[1];
    rect.size.width = box[2];
    rect.size.height = box[3];
    return rect;
}

- (NXSize)decodeSize
{
    NXSize	size;
    int		rect[2];

    [self decodeArrayOfObjCType:"i" count:2 at:rect];
    size.width = rect[0];
    size.height = rect[1];
    return size;
}
 
- (NXColor) decodeColor
{
    NXColor color;
    
    [self decodeArrayOfObjCType:"S" count:6 at:&color.colorField];
    [self decodeValueOfObjCType:"*" at:&color.str];
    if ( !strcmp( color.str, "" ) ) {
        free((char *)color.str);
	color.str = NULL;
    }
    return color;
}
   
- (void)decodeValueOfObjCType:(const char *)type
                           at:(void *)address
 /*
  * Deserializes data of Objective C type type residing at address address. 
  * You are responsible for releasing the resulting objects. 
  */
{
    objc_read_type( stream, type, address );
    return;
}

- (void)decodeValuesOfObjCTypes:(const char *)types, ...
{
    va_list	args;
    const char	*c;
    char	*where[CODER_MAX_VAR_ARGS];
    int		i;

    va_start(args, types);
    for ( c = types, i = 0; *c; c = objc_skip_typespec(c) ) {
        if ( i < CODER_MAX_VAR_ARGS ) {
            where[i++] = va_arg(args, char*);
	} else {
	    printf( "[NXCoder decodeValuesOfObjCTypes]:"
	    	    " Maximum number of args exceeded\n");
	    return;
	}
    }
    va_end(args);
    objc_read_types(stream, types, where[0], where[1], where[2], where[3],
	           where[4], where[5], where[6], where[7], where[8], where[9]);
    return;
}
 
 
// Managing Zones

// - (NSZone *)objectZone;
// - (void)setObjectZone:(NSZone *)zone;


// Getting a Version

// - (unsigned int)systemVersion;
 
- (unsigned int)versionForClassName:(NSString *)className
{
    const char	*name = [className cString];
    id	aClass;

#ifdef __NeXT__
    aClass = objc_lookUpClass(name);  
#else
    aClass = objc_lookup_class(name);
#endif    
    return objc_get_stream_class_version( stream, aClass );
}

@end
