#import "NSDataExtensions.h"
#import "NSMutableDataExtensions.h"
#import "NSStringExtensions.h"


@implementation NSData (Byte)

/* 1 byte */ 

    byte deserializeByteAtIndex(NSData* data, unsigned index) {
        byte buf;
        void* src = (void*) [data bytes] + index;
        memcpy(&buf, src, 1);
        return buf;
    }
    
    - (byte)  deserializeByteAtIndex:  (unsigned) index; {
        byte buf;
        void* src = (void*) [self bytes] + index;
        memcpy(&buf, src, 1);
        return buf;
    }

/* 1 byte */ 

    byte1 deserializeByte1AtIndex(NSData* data, unsigned index) {
        byte buf;
        void* src = (void*) [data bytes] + index;
        memcpy(&buf, src, 1);
        return buf;
    }
    
    - (byte1) deserializeByte1AtIndex: (unsigned) index; {
        byte buf;
        void* src = (void*) [self bytes] + index;
        memcpy(&buf, src, 1);
        return buf;
    }

/* 2 byte */ 

    byte2 deserializeByte2AtIndex(NSData* data, unsigned index) {
        byte2 buf;
        void* src = (void*) [data bytes] + index;
        memcpy(&buf, src, 2);
        return buf;
    }
    
    - (byte2) deserializeByte2AtIndex: (unsigned) index; {
        byte2 buf;
        void* src = (void*) [self bytes] + index;
        memcpy(&buf, src, 2);
        return buf;
    }

/* 4 byte */ 

    byte4 deserializeByte4AtIndex(NSData* data, unsigned index) {
        byte4 buf;
        void* src = (void*) [data bytes] + index;
        memcpy(&buf, src, 4);
        return buf;
    }
        
    - (byte4) deserializeByte4AtIndex: (unsigned) index; {
        byte4 buf;
        void* src = (void*) [self bytes] + index;
        memcpy(&buf, src, 4);
        return buf;
    }
    
/* 8 byte */ 

    byte8 deserializeByte8AtIndex(NSData* data, unsigned index) {
        byte8 buf;
        void* src = (void*) [data bytes] + index;
        memcpy(&buf, src, 8);
        return buf;
    }
    
    - (byte8) deserializeByte8AtIndex: (unsigned) index; {
        byte8 buf;
        void* src = (void*) [self bytes] + index;
        memcpy(&buf, src, 8);
        return buf;
    }

/* 16 byte */ 

    byte16 deserializeByte16AtIndex(NSData* data, unsigned index) {
        byte16 buf;
        void* src = (void*) [data bytes] + index;
        memcpy(&buf, src, 16);
        return buf;
    }
    
    - (byte16) deserializeByte16AtIndex: (unsigned) index; {
        byte16 buf;
        void* src = (void*) [self bytes] + index;
        memcpy(&buf, src, 16);
        return buf;
    }

/* NSData  */ 

    - (NSData*) deserializeDataAtIndex: (unsigned) index; {
        NSRange r = {index, [self length]-index};
        return [self subdataWithRange: r];
    }

@end






@implementation NSData (Components)

- (NSArray*) componentsSeparatedByByte:  (byte) partition;
{
    NSMutableArray* responses = [[NSMutableArray alloc] init];
    NSMutableData* buffer = nil;
    byte i, value;

    for (i=0; i < [self length]; i++)
    {
        if (!buffer) 
            buffer = [[[NSMutableData alloc] init] autorelease];
        
        if ((value = [self deserializeByteAtIndex: i]) == partition) {
            [responses addObject: buffer];
            buffer = nil;
        } else {
            [buffer appendByte: value];
        }
    }

    if (buffer) 
        [responses addObject: buffer];
    
    return [responses autorelease];
}

- (NSArray*) componentsSeparatedByByte2: (byte) value;
{
    /* not yet needed */
    return nil;
}

@end






@implementation NSData (String)

- (NSString*) string; {
    return [NSString stringWithData: self];
}

- (NSData*) dataInRange: (NSRange) range; {
    return [self subdataWithRange: range];
}

- (NSString*) stringInRange: (NSRange) range; {
    return [NSString stringWithData: [self subdataWithRange: range]];
}

- (NSData*) dataFromIndex: (int) index; {
    NSRange r = {index, [self length]-index};
    return [self subdataWithRange: r];
}

- (NSString*) stringFromIndex: (int) index; {
    NSRange r = {index, [self length]-index};
    return [self stringInRange: r];
}

- (NSString*) deserializeStringAtIndex: (int) index; {
    NSRange r = {index, [self length]-index};
    return [self stringInRange: r];
}

@end






@implementation NSData (Subdata)

/* SEPARATED COMPONENTS */

    - (NSArray*) componentsSeparatedByData: (NSData*) pattern; {
        return [self componentsSeparatedByString: [pattern string]];
    }
    
    - (NSArray*) componentsSeparatedByString: (NSString*) pattern; 
    {
        id stringComponents = [[self string] componentsSeparatedByString: pattern];
        id dataComponents = [[NSMutableArray alloc] init];
        unsigned i;
        
        for (i=0; i<[stringComponents count]; i++) {
            [dataComponents addObject: [[stringComponents objectAtIndex: i] data]];
        }
        
        return [dataComponents autorelease];
    }


/* INDEX */

    - (int) indexOfData: (NSData*) pattern; {
        return [self indexOfData: pattern fromIndex: 0];
    }
    
    - (int) indexOfData: (NSData*) pattern fromIndex: (int) index;
    {
        int position;
        
        for (position = index; position <= (int)([self length] - [pattern length]); position++)
        {
            NSRange r = {position, [pattern length]};
            id probe = [self subdataWithRange: r];
            if ([pattern isEqual: probe])
                return position;
        }
        
        return -1;
    }

    - (int) indexOfString: (NSString*) pattern; {
        return [self indexOfData: [pattern data] fromIndex: 0];
    }
    
    - (int) indexOfString: (NSString*) pattern fromIndex: (int) index; {
        return [self indexOfData: [pattern data] fromIndex: index];
    }


/* SUBDATA UP TO PATTERN */

    - (NSData*) getDataUpToData: (NSData*) pattern; {
        return [self getDataUpToData: pattern fromIndex: 0];
    }
    
    - (NSData*) getDataUpToString: (NSString*) pattern; {
        return [self getDataUpToString: pattern fromIndex: 0];
    }
    
    - (NSData*) getDataUpToData: (NSData*) pattern fromIndex: (int) startIndex; 
    {
        int dataIndex = [self indexOfData: pattern fromIndex: startIndex];
        if (dataIndex < 0) 
            return nil;

        return [self subdataWithRange: NSMakeRange(startIndex, dataIndex + [pattern length])];
    }

    - (NSData*) getDataUpToString: (NSString*) pattern fromIndex: (int) index; {
        return [self getDataUpToData: [pattern data] fromIndex: index];
    }

@end