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