diff options
Diffstat (limited to 'libs/protoutil/src/EncodedBuffer.cpp')
-rw-r--r-- | libs/protoutil/src/EncodedBuffer.cpp | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/libs/protoutil/src/EncodedBuffer.cpp b/libs/protoutil/src/EncodedBuffer.cpp new file mode 100644 index 000000000000..3a5e2e9ef5d0 --- /dev/null +++ b/libs/protoutil/src/EncodedBuffer.cpp @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/util/EncodedBuffer.h> +#include <android/util/protobuf.h> + +#include <stdlib.h> + +namespace android { +namespace util { + +const size_t BUFFER_SIZE = 8 * 1024; // 8 KB + +EncodedBuffer::Pointer::Pointer() : Pointer(BUFFER_SIZE) +{ +} + +EncodedBuffer::Pointer::Pointer(size_t chunkSize) + :mIndex(0), + mOffset(0) +{ + mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize; +} + +size_t +EncodedBuffer::Pointer::pos() const +{ + return mIndex * mChunkSize + mOffset; +} + +size_t +EncodedBuffer::Pointer::index() const +{ + return mIndex; +} + +size_t +EncodedBuffer::Pointer::offset() const +{ + return mOffset; +} + +EncodedBuffer::Pointer* +EncodedBuffer::Pointer::move(size_t amt) +{ + size_t newOffset = mOffset + amt; + mIndex += newOffset / mChunkSize; + mOffset = newOffset % mChunkSize; + return this; +} + +EncodedBuffer::Pointer* +EncodedBuffer::Pointer::rewind() +{ + mIndex = 0; + mOffset = 0; + return this; +} + +EncodedBuffer::Pointer +EncodedBuffer::Pointer::copy() const +{ + Pointer p = Pointer(mChunkSize); + p.mIndex = mIndex; + p.mOffset = mOffset; + return p; +} + +// =========================================================== +EncodedBuffer::EncodedBuffer() : EncodedBuffer(0) +{ +} + +EncodedBuffer::EncodedBuffer(size_t chunkSize) + :mBuffers() +{ + mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize; + mWp = Pointer(mChunkSize); + mEp = Pointer(mChunkSize); +} + +EncodedBuffer::~EncodedBuffer() +{ + for (size_t i=0; i<mBuffers.size(); i++) { + uint8_t* buf = mBuffers[i]; + free(buf); + } +} + +inline uint8_t* +EncodedBuffer::at(const Pointer& p) const +{ + return mBuffers[p.index()] + p.offset(); +} + +void +EncodedBuffer::clear() +{ + mWp.rewind(); + mEp.rewind(); +} + +/******************************** Write APIs ************************************************/ +size_t +EncodedBuffer::size() const +{ + return mWp.pos(); +} + +EncodedBuffer::Pointer* +EncodedBuffer::wp() +{ + return &mWp; +} + +uint8_t* +EncodedBuffer::writeBuffer() +{ + // This prevents write pointer move too fast than allocating the buffer. + if (mWp.index() > mBuffers.size()) return NULL; + uint8_t* buf = NULL; + if (mWp.index() == mBuffers.size()) { + buf = (uint8_t*)malloc(mChunkSize); + + if (buf == NULL) return NULL; // This indicates NO_MEMORY + + mBuffers.push_back(buf); + } + return at(mWp); +} + +size_t +EncodedBuffer::currentToWrite() +{ + return mChunkSize - mWp.offset(); +} + +void +EncodedBuffer::writeRawByte(uint8_t val) +{ + *writeBuffer() = val; + mWp.move(); +} + +size_t +EncodedBuffer::writeRawVarint64(uint64_t val) +{ + size_t size = 0; + while (true) { + size++; + if ((val & ~0x7F) == 0) { + writeRawByte((uint8_t) val); + return size; + } else { + writeRawByte((uint8_t)((val & 0x7F) | 0x80)); + val >>= 7; + } + } +} + +size_t +EncodedBuffer::writeRawVarint32(uint32_t val) +{ + uint64_t v =(uint64_t)val; + return writeRawVarint64(v); +} + +void +EncodedBuffer::writeRawFixed32(uint32_t val) +{ + writeRawByte((uint8_t) val); + writeRawByte((uint8_t) (val>>8)); + writeRawByte((uint8_t) (val>>16)); + writeRawByte((uint8_t) (val>>24)); +} + +void +EncodedBuffer::writeRawFixed64(uint64_t val) +{ + writeRawByte((uint8_t) val); + writeRawByte((uint8_t) (val>>8)); + writeRawByte((uint8_t) (val>>16)); + writeRawByte((uint8_t) (val>>24)); + writeRawByte((uint8_t) (val>>32)); + writeRawByte((uint8_t) (val>>40)); + writeRawByte((uint8_t) (val>>48)); + writeRawByte((uint8_t) (val>>56)); +} + +size_t +EncodedBuffer::writeHeader(uint32_t fieldId, uint8_t wireType) +{ + return writeRawVarint32((fieldId << FIELD_ID_SHIFT) | wireType); +} + +/******************************** Edit APIs ************************************************/ +EncodedBuffer::Pointer* +EncodedBuffer::ep() +{ + return &mEp; +} + +uint8_t +EncodedBuffer::readRawByte() +{ + uint8_t val = *at(mEp); + mEp.move(); + return val; +} + +uint64_t +EncodedBuffer::readRawVarint() +{ + uint64_t val = 0, shift = 0; + size_t start = mEp.pos(); + while (true) { + uint8_t byte = readRawByte(); + val += (byte & 0x7F) << shift; + if ((byte & 0x80) == 0) break; + shift += 7; + } + return val; +} + +uint32_t +EncodedBuffer::readRawFixed32() +{ + uint32_t val = 0; + for (auto i=0; i<32; i+=8) { + val += (uint32_t)readRawByte() << i; + } + return val; +} + +uint64_t +EncodedBuffer::readRawFixed64() +{ + uint64_t val = 0; + for (auto i=0; i<64; i+=8) { + val += (uint64_t)readRawByte() << i; + } + return val; +} + +void +EncodedBuffer::editRawFixed32(size_t pos, uint32_t val) +{ + size_t oldPos = mEp.pos(); + mEp.rewind()->move(pos); + for (auto i=0; i<32; i+=8) { + *at(mEp) = (uint8_t) (val >> i); + mEp.move(); + } + mEp.rewind()->move(oldPos); +} + +void +EncodedBuffer::copy(size_t srcPos, size_t size) +{ + if (size == 0) return; + Pointer cp(mChunkSize); + cp.move(srcPos); + + while (cp.pos() < srcPos + size) { + writeRawByte(*at(cp)); + cp.move(); + } +} + +/********************************* Read APIs ************************************************/ +EncodedBuffer::iterator +EncodedBuffer::begin() const +{ + return EncodedBuffer::iterator(*this); +} + +EncodedBuffer::iterator::iterator(const EncodedBuffer& buffer) + :mData(buffer), + mRp(buffer.mChunkSize) +{ +} + +size_t +EncodedBuffer::iterator::size() const +{ + return mData.size(); +} + +size_t +EncodedBuffer::iterator::bytesRead() const +{ + return mRp.pos(); +} + +EncodedBuffer::Pointer* +EncodedBuffer::iterator::rp() +{ + return &mRp; +} + +uint8_t const* +EncodedBuffer::iterator::readBuffer() +{ + return hasNext() ? const_cast<uint8_t const*>(mData.at(mRp)) : NULL; +} + +size_t +EncodedBuffer::iterator::currentToRead() +{ + return (mData.mWp.index() > mRp.index()) ? + mData.mChunkSize - mRp.offset() : + mData.mWp.offset() - mRp.offset(); +} + +bool +EncodedBuffer::iterator::hasNext() +{ + return mRp.pos() < mData.mWp.pos(); +} + +uint8_t +EncodedBuffer::iterator::next() +{ + uint8_t res = *(mData.at(mRp)); + mRp.move(); + return res; +} + +uint64_t +EncodedBuffer::iterator::readRawVarint() +{ + uint64_t val = 0, shift = 0; + while (true) { + uint8_t byte = next(); + val += (byte & 0x7F) << shift; + if ((byte & 0x80) == 0) break; + shift += 7; + } + return val; +} + +} // util +} // android |