/***************************************************************************** * Author: Valient Gough * ***************************************************************************** * Copyright (c) 2004, Valient Gough * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "base/ConfigVar.h" #include "base/Error.h" #include #include namespace encfs { #ifndef MIN inline int MIN(int a, int b) { return (a < b) ? a : b; } #endif ConfigVar::ConfigVar() : pd(new ConfigVarData) { pd->offset = 0; } ConfigVar::ConfigVar(const std::string &buf) : pd(new ConfigVarData) { pd->buffer = buf; pd->offset = 0; } ConfigVar::ConfigVar(const ConfigVar &src) { pd = src.pd; } ConfigVar::~ConfigVar() { pd.reset(); } ConfigVar &ConfigVar::operator=(const ConfigVar &src) { if (src.pd == pd) return *this; else pd = src.pd; return *this; } void ConfigVar::resetOffset() { pd->offset = 0; } int ConfigVar::read(byte *buffer_, int bytes) const { int toCopy = MIN(bytes, pd->buffer.size() - pd->offset); if (toCopy > 0) memcpy(buffer_, pd->buffer.data() + pd->offset, toCopy); pd->offset += toCopy; return toCopy; } int ConfigVar::write(const byte *data, int bytes) { if (pd->buffer.size() == (unsigned int)pd->offset) { pd->buffer.append((const char *)data, bytes); } else { pd->buffer.insert(pd->offset, (const char *)data, bytes); } pd->offset += bytes; return bytes; } int ConfigVar::size() const { return pd->buffer.size(); } const char *ConfigVar::buffer() const { return pd->buffer.data(); } int ConfigVar::at() const { return pd->offset; } void ConfigVar::writeString(const char *data, int bytes) { writeInt(bytes); write((const byte *)data, bytes); } // convert integer to BER encoded integer void ConfigVar::writeInt(int val) { // we can represent 7 bits per char output, so a 32bit number may take up // to 5 bytes. // first byte: 0x0000007f 0111,1111 // second byte: 0x00003f80 0011,1111 1000,0000 // third byte: 0x001fb000 0000,0000 0001,1111 1100,0000 0000,0000 // fourth byte: 0x0fe00000 0000,1111 1110,0000 // fifth byte: 0xf0000000 1111,0000 byte digit[5]; digit[4] = (byte)((val & 0x0000007f)); digit[3] = 0x80 | (byte)((val & 0x00003f80) >> 7); digit[2] = 0x80 | (byte)((val & 0x001fc000) >> 14); digit[1] = 0x80 | (byte)((val & 0x0fe00000) >> 21); digit[0] = 0x80 | (byte)((val & 0xf0000000) >> 28); // find the starting point - we only need to output starting at the most // significant non-zero digit.. int start = 0; while (digit[start] == 0x80) ++start; write(digit + start, 5 - start); } int ConfigVar::readInt() const { const byte *buf = (const byte *)buffer(); int bytes = this->size(); int offset = at(); int value = 0; bool highBitSet; rAssert(offset < bytes); do { byte tmp = buf[offset++]; highBitSet = tmp & 0x80; value = (value << 7) | (int)(tmp & 0x7f); } while (highBitSet && offset < bytes); pd->offset = offset; // should never end up with a negative number.. rAssert(value >= 0); return value; } int ConfigVar::readInt(int defaultValue) const { int bytes = this->size(); int offset = at(); if (offset >= bytes) return defaultValue; else return readInt(); } bool ConfigVar::readBool(bool defaultValue) const { int tmp = readInt(defaultValue ? 1 : 0); return (tmp != 0); } ConfigVar &operator<<(ConfigVar &src, bool value) { src.writeInt(value ? 1 : 0); return src; } ConfigVar &operator<<(ConfigVar &src, int var) { src.writeInt(var); return src; } ConfigVar &operator<<(ConfigVar &src, const std::string &str) { src.writeString(str.data(), str.length()); return src; } const ConfigVar &operator>>(const ConfigVar &src, bool &result) { int tmp = src.readInt(); result = (tmp != 0); return src; } const ConfigVar &operator>>(const ConfigVar &src, int &result) { result = src.readInt(); return src; } const ConfigVar &operator>>(const ConfigVar &src, std::string &result) { int length = src.readInt(); LOG_IF(WARNING, length <= 0) << "Invalid config length " << length; int readLen; byte tmpBuf[32]; if (length > (int)sizeof(tmpBuf)) { byte *ptr = new byte[length]; readLen = src.read(ptr, length); result.assign((char *)ptr, length); delete[] ptr; } else { readLen = src.read(tmpBuf, length); result.assign((char *)tmpBuf, length); } if (readLen != length) { VLOG(1) << "string encoded as size " << length << " bytes, read " << readLen; } rAssert(readLen == length); return src; } } // namespace encfs