//
// $Id: PointerData.m,v 1.4 2005/05/23 05:35:09 will_mason Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004
 * Will Mason
 *
 * Portions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Copyright (c) 1996,1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Copyright (c) 1997
 * Moscow Center for SPARC Technology
 *
 * Copyright (c) 1999 
 * Boris Fomitchev
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * You may contact the author at will_mason@users.sourceforge.net.
 */

#import "PointerData.h"
#import "Macros.h"
#import "InStreamPackage.h"
#import <Foundation/NSData.h>
#import <stdlib.h>
#import <string.h>

@implementation OLPointerData

- (id) initWithAllocator: (OLAllocator*)alloc
{
    [super init];
#if !defined(GNUSTEP)
    bytes = NULL;
    numberOfBytes = 0;
    capacity = 0;
#else
    allocator = OBJ_RETAIN(alloc);
    data = [[alloc allocateObject: [NSMutableData class]] init];
#endif
    return self;
}

- (id) initWithAllocator: (OLAllocator*)alloc size: (unsigned)sz;
{
    [super init];
#if !defined(GNUSTEP)
    bytes = malloc(sz);
    capacity = numberOfBytes = sz;
#else
    allocator = OBJ_RETAIN(alloc);
    data = [[alloc allocateObject: [NSMutableData class]]
        initWithLength: sz];
#endif
    return self;
}

- (void) dealloc
{
    // the bytes don't leak under Next runtime, as they will be owned by the
    // object decoding the pointer
#if !!defined(GNUSTEP)
    OBJ_COND_AUTORELEASE(data);
    OBJ_RELEASE(allocator);
#endif
    [super dealloc];
}

- (uint8_t*) bytes
{
#if !defined(GNUSTEP)
    return bytes;
#else
    return [data mutableBytes];
#endif
}

- (void) grow: (unsigned)amount
{
#if !defined(GNUSTEP)
    uint8_t* newBytes;
    unsigned newNumberOfBytes = numberOfBytes + amount;

    if (bytes == NULL)
    {
        capacity = amount + 1;
        numberOfBytes = amount;
        bytes = malloc(capacity);
    }
    else if (newNumberOfBytes > capacity)
    {
        capacity = MAX(newNumberOfBytes + 1, capacity * 2 + 1);
        newBytes = malloc(capacity);
        memcpy(newBytes, bytes, numberOfBytes);
        free(bytes);
        bytes = newBytes;
        numberOfBytes = newNumberOfBytes;
    }
    else
    {
        numberOfBytes = newNumberOfBytes;
    }
#else
    [data increaseLengthBy: amount];
#endif
}

- (void) nullTerminate
{
#if !defined(GNUSTEP)
    [self grow: 1];
    bytes[numberOfBytes - 1] = 0;
#else
    uint8_t zero = 0;
    [data appendBytes: &zero length: 1];
#endif
}

- (void) readFromStream: (OLInStream*)stream count: (unsigned)amount
{
    unsigned currentLength;

#if !defined(GNUSTEP)
    currentLength = numberOfBytes;
    [self grow: amount];
    [stream completelyReadBytes: bytes + currentLength count: amount];
#else
    currentLength = [data length];
    [self grow: amount];
    [stream completelyReadBytes: [data mutableBytes] + currentLength count: amount];
#endif
}

@end
