1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/Chunk.cpp Sun Sep 20 15:14:12 2009 -0700
1.3 @@ -0,0 +1,135 @@
1.4 +/*
1.5 + * Chunk.cpp
1.6 + * Ottoman
1.7 + *
1.8 + * Created by Jens Alfke on 8/27/09.
1.9 + * Copyright 2009 Jens Alfke. All rights reserved.
1.10 + * BSD-Licensed: See the file "LICENSE.txt" for details.
1.11 + */
1.12 +
1.13 +#include "Chunk.h"
1.14 +#include <assert.h>
1.15 +#include <errno.h>
1.16 +#include <stddef.h>
1.17 +
1.18 +namespace Mooseyard {
1.19 +
1.20 + uint16_t Chunk::type() const {
1.21 + return _keyLength == 0xFFFF ?(uint16_t)_type :KeyValueChunk::kChunkType;
1.22 + }
1.23 +
1.24 + const KeyValueChunk* Chunk::asKeyValue() const {
1.25 + return _keyLength == 0xFFFF ?NULL :(const KeyValueChunk*)this;
1.26 + }
1.27 +
1.28 + size_t Chunk::writeMultiple (File *file, uint16_t type,
1.29 + Blob blobs[], int count) throw(File::Error) {
1.30 + assert(type != KeyValueChunk::kChunkType);
1.31 + Blob nuBlobs[count+1];
1.32 + uint32_t size = sizeof(Chunk);
1.33 + for (int i=0; i<count; i++) {
1.34 + nuBlobs[i+1] = blobs[i];
1.35 + size += blobs[i].length;
1.36 + }
1.37 + Chunk chunk(size, type);
1.38 + nuBlobs[0] = Blob(&chunk, sizeof(chunk));
1.39 + return file->writeMultiple(nuBlobs, count+1);
1.40 + }
1.41 +
1.42 + size_t Chunk::writePadding (File *file) {
1.43 + int padding = file->position() & 0x03;
1.44 + if (padding == 0)
1.45 + return 0;
1.46 + else {
1.47 + padding = 4 - padding;
1.48 + uint32_t zero = 0;
1.49 + Blob pad(&zero, padding);
1.50 + return writeMultiple(file, kChunkTypePadding, &pad, 1);
1.51 + }
1.52 + }
1.53 +
1.54 +
1.55 +
1.56 + void KeyValueChunk::validate() const throw(File::Error) {
1.57 + if (_keyLength >= 0xFFFFU)
1.58 + throw File::Error(ERANGE, "Invalid key length (0xFFFF)");
1.59 + if (valuePtr() > end())
1.60 + throw File::Error(ERANGE, "Bad KeyValueChunk (key-length too large to fit)");
1.61 + }
1.62 +
1.63 + Blob KeyValueChunk::key() const {
1.64 + return Blob(&_keyLength +1, _keyLength); // KeyValueChunk doesn't have _type
1.65 + }
1.66 +
1.67 + const char* KeyValueChunk::valuePtr() const {
1.68 + size_t vptr = (size_t) key().end();
1.69 + vptr = (vptr+3) & ~3; // 4-byte align
1.70 + return (const char*)vptr;
1.71 + }
1.72 +
1.73 + Blob KeyValueChunk::value() const {
1.74 + const char *vp = valuePtr();
1.75 + return Blob(vp, (const char*)end()-vp);
1.76 + }
1.77 +
1.78 + bool KeyValueChunk::hasKey (Blob key) const {
1.79 + return key.length==_keyLength
1.80 + && memcmp(key.bytes, &_keyLength +1, key.length)==0;
1.81 + }
1.82 +
1.83 + size_t KeyValueChunk::write (File* file, FilePosition pos, Blob key, Blob value) throw(File::Error) {
1.84 + if (key.length >= 0xFFFFU)
1.85 + throw File::Error(ERANGE, "Key too long (>=64k)");
1.86 + uint16_t keyLength = key.length;
1.87 + uint32_t size = sizeof(uint32_t) + sizeof(uint16_t) + keyLength;
1.88 + size_t pad = (pos + size) & 0x3;
1.89 + if (pad)
1.90 + pad = 4-pad;
1.91 + uint32_t zeros = 0;
1.92 + size += pad + value.length;
1.93 +
1.94 + Chunk chunk(size, KeyValueChunk::kChunkType);
1.95 + chunk._keyLength = keyLength;
1.96 + Blob b[4] = {
1.97 + Blob(&chunk, sizeof(chunk._size)+sizeof(chunk._keyLength)),
1.98 + key,
1.99 + Blob(&zeros, pad),
1.100 + value};
1.101 + return file->writeMultiple(b,4);
1.102 + }
1.103 +
1.104 +
1.105 +
1.106 + ChunkIterator::ChunkIterator (File* file, FilePosition start)
1.107 + :_file(file),
1.108 + _pos(start),
1.109 + _length(_file->length()),
1.110 + _chunk(NULL)
1.111 + {
1.112 + _loadChunk();
1.113 + }
1.114 +
1.115 + void ChunkIterator::_loadChunk() {
1.116 + if (_pos < _length) {
1.117 + _chunk = (const Chunk*) _file->mappedPosition(_pos);
1.118 + if (_chunk->size() < sizeof(Chunk) || _pos+_chunk->size() > _length)
1.119 + _chunk = NULL;
1.120 + } else {
1.121 + _chunk = NULL;
1.122 + }
1.123 +
1.124 + }
1.125 +
1.126 + bool ChunkIterator::atEOF() const {
1.127 + return _pos == _length;
1.128 + }
1.129 +
1.130 + bool ChunkIterator::next() {
1.131 + if (_chunk) {
1.132 + _pos += _chunk->size();
1.133 + _loadChunk();
1.134 + }
1.135 + return _chunk != NULL;
1.136 + }
1.137 +
1.138 +}