src/Chunk.cpp
author Jens Alfke <jens@mooseyard.com>
Sun Sep 20 21:25:47 2009 -0700 (2009-09-20)
changeset 2 851de24ecb61
parent 0 31a43d94cc26
permissions -rw-r--r--
Added library target, changed some build settings, and fixed 64-to-32-bit conversion warnings.
jens@0
     1
/*
jens@0
     2
 *  Chunk.cpp
jens@0
     3
 *  Ottoman
jens@0
     4
 *
jens@0
     5
 *  Created by Jens Alfke on 8/27/09.
jens@0
     6
 *  Copyright 2009 Jens Alfke. All rights reserved.
jens@0
     7
 *  BSD-Licensed: See the file "LICENSE.txt" for details.
jens@0
     8
 */
jens@0
     9
jens@0
    10
#include "Chunk.h"
jens@0
    11
#include <assert.h>
jens@0
    12
#include <errno.h>
jens@0
    13
#include <stddef.h>
jens@0
    14
jens@0
    15
namespace Mooseyard {
jens@0
    16
    
jens@0
    17
    uint16_t Chunk::type() const {
jens@0
    18
        return _keyLength == 0xFFFF ?(uint16_t)_type :KeyValueChunk::kChunkType;
jens@0
    19
    }
jens@0
    20
    
jens@0
    21
    const KeyValueChunk* Chunk::asKeyValue() const {
jens@0
    22
        return _keyLength == 0xFFFF ?NULL :(const KeyValueChunk*)this;
jens@0
    23
    }
jens@0
    24
jens@0
    25
    size_t Chunk::writeMultiple (File *file, uint16_t type,
jens@0
    26
                                 Blob blobs[], int count)  throw(File::Error) {
jens@0
    27
        assert(type != KeyValueChunk::kChunkType);
jens@0
    28
        Blob nuBlobs[count+1];
jens@0
    29
        uint32_t size = sizeof(Chunk);
jens@0
    30
        for (int i=0; i<count; i++) {
jens@0
    31
            nuBlobs[i+1] = blobs[i];
jens@0
    32
            size += blobs[i].length;
jens@0
    33
        }
jens@0
    34
        Chunk chunk(size, type);
jens@0
    35
        nuBlobs[0] = Blob(&chunk, sizeof(chunk));
jens@0
    36
        return file->writeMultiple(nuBlobs, count+1);
jens@0
    37
    }
jens@0
    38
    
jens@0
    39
    size_t Chunk::writePadding (File *file) {
jens@2
    40
        off_t padding = file->position() & 0x03;
jens@0
    41
        if (padding == 0)
jens@0
    42
            return 0;
jens@0
    43
        else {
jens@0
    44
            padding = 4 - padding;
jens@0
    45
            uint32_t zero = 0;
jens@2
    46
            Blob pad(&zero, (size_t)padding);
jens@0
    47
            return writeMultiple(file, kChunkTypePadding, &pad, 1);
jens@0
    48
        }
jens@0
    49
    }
jens@0
    50
    
jens@0
    51
    
jens@0
    52
    
jens@0
    53
    void KeyValueChunk::validate() const  throw(File::Error) {
jens@0
    54
        if (_keyLength >= 0xFFFFU)
jens@0
    55
            throw File::Error(ERANGE, "Invalid key length (0xFFFF)");
jens@0
    56
        if (valuePtr() > end())
jens@0
    57
            throw File::Error(ERANGE, "Bad KeyValueChunk (key-length too large to fit)");
jens@0
    58
    }
jens@0
    59
    
jens@0
    60
    Blob KeyValueChunk::key() const {
jens@0
    61
        return Blob(&_keyLength +1, _keyLength);  // KeyValueChunk doesn't have _type
jens@0
    62
    }
jens@0
    63
    
jens@0
    64
    const char* KeyValueChunk::valuePtr() const {
jens@0
    65
        size_t vptr = (size_t) key().end();
jens@0
    66
        vptr = (vptr+3) & ~3;     // 4-byte align
jens@0
    67
        return (const char*)vptr;
jens@0
    68
    }
jens@0
    69
    
jens@0
    70
    Blob KeyValueChunk::value() const {
jens@0
    71
        const char *vp = valuePtr();
jens@0
    72
        return Blob(vp, (const char*)end()-vp);
jens@0
    73
    }
jens@0
    74
    
jens@0
    75
    bool KeyValueChunk::hasKey (Blob key) const {
jens@0
    76
        return key.length==_keyLength 
jens@0
    77
            && memcmp(key.bytes, &_keyLength +1, key.length)==0;
jens@0
    78
    }
jens@0
    79
    
jens@0
    80
    size_t KeyValueChunk::write (File* file, FilePosition pos, Blob key, Blob value)  throw(File::Error) {
jens@0
    81
        if (key.length >= 0xFFFFU)
jens@0
    82
            throw File::Error(ERANGE, "Key too long (>=64k)");
jens@0
    83
        uint16_t keyLength = key.length;
jens@0
    84
        uint32_t size = sizeof(uint32_t) + sizeof(uint16_t) + keyLength;
jens@0
    85
        size_t pad = (pos + size) & 0x3;
jens@0
    86
        if (pad)
jens@0
    87
            pad = 4-pad;
jens@0
    88
        uint32_t zeros = 0;
jens@0
    89
        size += pad + value.length;
jens@0
    90
        
jens@0
    91
        Chunk chunk(size, KeyValueChunk::kChunkType);
jens@0
    92
        chunk._keyLength = keyLength;
jens@0
    93
        Blob b[4] = {
jens@0
    94
            Blob(&chunk, sizeof(chunk._size)+sizeof(chunk._keyLength)),
jens@0
    95
            key,
jens@0
    96
            Blob(&zeros, pad),
jens@0
    97
            value};
jens@0
    98
        return file->writeMultiple(b,4);
jens@0
    99
    }
jens@0
   100
jens@0
   101
    
jens@0
   102
    
jens@0
   103
    ChunkIterator::ChunkIterator (File* file, FilePosition start)
jens@0
   104
        :_file(file),
jens@0
   105
         _pos(start),
jens@2
   106
         _length((FilePosition)_file->length()),
jens@0
   107
         _chunk(NULL)
jens@0
   108
    { 
jens@0
   109
        _loadChunk();
jens@0
   110
    }
jens@0
   111
    
jens@0
   112
    void ChunkIterator::_loadChunk() {
jens@0
   113
        if (_pos < _length) {
jens@0
   114
            _chunk = (const Chunk*) _file->mappedPosition(_pos);
jens@0
   115
            if (_chunk->size() < sizeof(Chunk) || _pos+_chunk->size() > _length)
jens@0
   116
                _chunk = NULL;
jens@0
   117
        } else {
jens@0
   118
            _chunk = NULL;
jens@0
   119
        }
jens@0
   120
jens@0
   121
    }
jens@0
   122
    
jens@0
   123
    bool ChunkIterator::atEOF() const {
jens@0
   124
        return _pos == _length;
jens@0
   125
    }
jens@0
   126
    
jens@0
   127
    bool ChunkIterator::next() {
jens@0
   128
        if (_chunk) {
jens@0
   129
            _pos += _chunk->size();
jens@0
   130
            _loadChunk();
jens@0
   131
        }
jens@0
   132
        return _chunk != NULL;
jens@0
   133
    }
jens@0
   134
    
jens@0
   135
}