//
//  MP4Atom.m
//  Encoder Demo
//
//  Created by Geraint Davies on 15/01/2013.
//  Copyright (c) 2013 GDCL http://www.gdcl.co.uk/license.htm
//

#import "MP4Atom.h"

static unsigned int to_host(unsigned char* p)
{
    return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
}

@implementation MP4Atom

+ (MP4Atom*) atomAt:(int64_t) offset size:(int) length type:(OSType) fourcc inFile:(NSFileHandle*) handle
{
    MP4Atom* atom = [MP4Atom alloc];
    if (![atom init:offset size:length type:fourcc inFile:handle])
    {
        return nil;
    }
    return atom;
}

- (BOOL) init:(int64_t) offset size:(int) length type:(OSType) fourcc inFile:(NSFileHandle*) handle
{
    _file = handle;
    _offset = offset;
    _length = length;
    _type = fourcc;
    _nextChild = 0;
    
    return YES;
}

- (NSData*) readAt:(int64_t) offset size:(int) length
{
    [_file seekToFileOffset:_offset + offset];
    return [_file readDataOfLength:length];
}

- (BOOL) setChildOffset:(int64_t) offset
{
    _nextChild = offset;
    return YES;
}

- (MP4Atom*) nextChild
{
    if (_nextChild <= (_length - 8))
    {
        [_file seekToFileOffset:_offset + _nextChild];
        NSData* data = [_file readDataOfLength:8];
        int cHeader = 8;
        unsigned char* p = (unsigned char*) [data bytes];
        int64_t len = to_host(p);
        OSType fourcc = to_host(p + 4);
        if (len == 1)
        {
            // 64-bit extended length
            cHeader+= 8;
            data = [_file readDataOfLength:8];
            p = (unsigned char*) [data bytes];
            len = to_host(p);
            len = (len << 32) + to_host(p + 4);
        }
        else if (len == 0)
        {
            // whole remaining parent space
            len = _length - _nextChild;
        }
        if (fourcc == (OSType)('uuid'))
        {
            cHeader += 16;
        }
        if ((len < 0) || ((len + _nextChild) > _length))
        {
            return nil;
        }
        int64_t offset = _nextChild + cHeader;
        _nextChild += len;
        len -= cHeader;
        return [MP4Atom atomAt:offset+_offset size:(int)len type:fourcc inFile:_file];
    }
    return nil;
}

- (MP4Atom*) childOfType:(OSType) fourcc startAt:(int64_t) offset
{
    [self setChildOffset:offset];
    MP4Atom* child = nil;
    do {
        child = [self nextChild];
    } while ((child != nil) && (child.type != fourcc));
    return child;
}

@end
