// Copyright 1997-1999 Omni Development, Inc.  All rights reserved.
//
// This software may only be used and reproduced according to the
// terms in the file OmniSourceLicense.html, which should be
// distributed with this project and can also be found at
// http://www.omnigroup.com/DeveloperResources/OmniSourceLicense.html.

#import "OWDataStreamScanner.h"

#import <Foundation/Foundation.h>
#import <OmniBase/OmniBase.h>
#import <OmniFoundation/OmniFoundation.h>

#import "OWDataStreamCursor.h"

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OWF/Content.subproj/OWDataStreamScanner.m,v 1.6 1999/07/17 02:48:22 kc Exp $")

@interface OWDataStreamScanner (Private)
@end

static unsigned int OWDataStreamScannerDefaultBufferLength = 8192;

@implementation OWDataStreamScanner

- initWithCursor:(OWDataStreamCursor *)aStreamCursor bufferLength:(unsigned int)aBufferLength;
{
    if (!(self = [super init]))
	return nil;

    streamCursor = [aStreamCursor retain];
    bufferLength = aBufferLength;

    // Make sure the buffer length is evenly divisible by two, or -fetchMoreData might have trouble with some encodings.
    if (bufferLength % 2 != 0)
        bufferLength++;

    buffer = (unichar *)NSZoneMalloc([self zone], bufferLength * sizeof(unichar));

    return self;
}

- initWithCursor:(OWDataStreamCursor *)aStreamCursor;
{
    return [self initWithCursor:aStreamCursor bufferLength:OWDataStreamScannerDefaultBufferLength];
}

- (void)dealloc;
{
    [streamCursor release];
    NSZoneFree(NSZoneFromPointer(buffer), buffer);
    [super dealloc];
}

// OWScanner subclass

- (BOOL)fetchMoreData;
{
    unsigned int length;
    unsigned char *sourcePointer;
    unichar *destinationPointer;

    if ([streamCursor stringDecoder])
        return [self fetchMoreDataFromString:[streamCursor readString]];

    switch ([streamCursor stringEncoding]) {
        case NSASCIIStringEncoding:
        case NSISOLatin1StringEncoding:
            length = [streamCursor readMaximumBytes:bufferLength intoBuffer:buffer];
            // Now, go through the buffer distributing those bytes (casting char to unichar, implicitly padding the top byte).
            destinationPointer = buffer + length - 1;
            sourcePointer = ((unsigned char *)buffer) + length - 1;
            while (destinationPointer >= buffer) {
                *destinationPointer-- = (unichar)*sourcePointer--;
            }
                return [self fetchMoreDataFromCharacters:buffer length:length freeWhenDone:NO];
        case NSUnicodeStringEncoding:
            length = [streamCursor readMaximumBytes:bufferLength * sizeof(unichar) intoBuffer:buffer];
            return [self fetchMoreDataFromCharacters:buffer length:length freeWhenDone:NO];
        default:
            return [self fetchMoreDataFromString:[streamCursor readString]];
    }
}

- (void)setScanLocation:(unsigned int)aLocation;
{
    if (aLocation >= inputStringPosition) {
	unsigned int inputLocation = aLocation - inputStringPosition;

        if (inputBuffer + inputLocation < scanEnd) {
            scanLocation = inputBuffer + inputLocation;
        } else {
	    scanEnd = inputBuffer;
	    scanLocation = scanEnd;
	    [streamCursor skipBytes:inputLocation - (scanEnd - inputBuffer)];
	    inputStringPosition = aLocation;
	}
    } else {
	scanEnd = inputBuffer;
	scanLocation = scanEnd;
	[streamCursor seekToOffset:aLocation fromPosition:OWCursorSeekFromStart];
	inputStringPosition = aLocation;
    }
}

- (void)skipCharacters:(int)anOffset;
{
    if (scanLocation + anOffset < inputBuffer) {
	[self setScanLocation:inputStringPosition + (scanLocation - inputBuffer) + anOffset];
	return;
    }
    scanLocation += anOffset;
    if (scanLocation >= scanEnd) {
	[streamCursor skipBytes:scanLocation - scanEnd];
	inputStringPosition += (scanLocation - inputBuffer);
	scanEnd = inputBuffer;
	scanLocation = scanEnd;
    }
}

@end
