| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 "MemoryOutputStream.h"
|
|
|
| namespace rocketmq {
|
| MemoryOutputStream::MemoryOutputStream(const size_t initialSize)
|
| : blockToUse(&internalBlock),
|
| externalData(NULL),
|
| position(0),
|
| size(0),
|
| availableSize(0) {
|
| internalBlock.setSize(initialSize, false);
|
| }
|
|
|
| MemoryOutputStream::MemoryOutputStream(MemoryBlock& memoryBlockToWriteTo,
|
| const bool appendToExistingBlockContent)
|
| : blockToUse(&memoryBlockToWriteTo),
|
| externalData(NULL),
|
| position(0),
|
| size(0),
|
| availableSize(0) {
|
| if (appendToExistingBlockContent)
|
| position = size = memoryBlockToWriteTo.getSize();
|
| }
|
|
|
| MemoryOutputStream::MemoryOutputStream(void* destBuffer, size_t destBufferSize)
|
| : blockToUse(NULL),
|
| externalData(destBuffer),
|
| position(0),
|
| size(0),
|
| availableSize(destBufferSize) {}
|
|
|
| MemoryOutputStream::~MemoryOutputStream() { trimExternalBlockSize(); }
|
|
|
| void MemoryOutputStream::flush() { trimExternalBlockSize(); }
|
|
|
| void MemoryOutputStream::trimExternalBlockSize() {
|
| if (blockToUse != &internalBlock && blockToUse != NULL)
|
| blockToUse->setSize(size, false);
|
| }
|
|
|
| void MemoryOutputStream::preallocate(const size_t bytesToPreallocate) {
|
| if (blockToUse != NULL) blockToUse->ensureSize(bytesToPreallocate + 1);
|
| }
|
|
|
| void MemoryOutputStream::reset() {
|
| position = 0;
|
| size = 0;
|
| }
|
|
|
| char* MemoryOutputStream::prepareToWrite(size_t numBytes) {
|
| size_t storageNeeded = position + numBytes;
|
|
|
| char* data;
|
|
|
| if (blockToUse != NULL) {
|
| if (storageNeeded >= (unsigned int)(blockToUse->getSize()))
|
| blockToUse->ensureSize(
|
| (storageNeeded + std::min(storageNeeded / 2, (size_t)(1024 * 1024)) +
|
| 32) &
|
| ~31u);
|
|
|
| data = static_cast<char*>(blockToUse->getData());
|
| } else {
|
| if (storageNeeded > availableSize) return NULL;
|
|
|
| data = static_cast<char*>(externalData);
|
| }
|
|
|
| char* const writePointer = data + position;
|
| position += numBytes;
|
| size = std::max(size, position);
|
| return writePointer;
|
| }
|
|
|
| bool MemoryOutputStream::write(const void* const buffer, size_t howMany) {
|
| if (howMany == 0) return true;
|
|
|
| if (char* dest = prepareToWrite(howMany)) {
|
| memcpy(dest, buffer, howMany);
|
| return true;
|
| }
|
|
|
| return false;
|
| }
|
|
|
| bool MemoryOutputStream::writeRepeatedByte(uint8 byte, size_t howMany) {
|
| if (howMany == 0) return true;
|
|
|
| if (char* dest = prepareToWrite(howMany)) {
|
| memset(dest, byte, howMany);
|
| return true;
|
| }
|
|
|
| return false;
|
| }
|
|
|
| MemoryBlock MemoryOutputStream::getMemoryBlock() const {
|
| return MemoryBlock(getData(), getDataSize());
|
| }
|
|
|
| const void* MemoryOutputStream::getData() const {
|
| if (blockToUse == NULL) return externalData;
|
|
|
| if ((unsigned int)blockToUse->getSize() > size)
|
| static_cast<char*>(blockToUse->getData())[size] = 0;
|
|
|
| return blockToUse->getData();
|
| }
|
|
|
| bool MemoryOutputStream::setPosition(int64 newPosition) {
|
| if (newPosition <= (int64)size) {
|
| // ok to seek backwards
|
| if (newPosition < 0)
|
| position = 0;
|
| else
|
| position = (int64)size < newPosition ? size : newPosition;
|
| return true;
|
| }
|
|
|
| // can't move beyond the end of the stream..
|
| return false;
|
| }
|
|
|
| int64 MemoryOutputStream::writeFromInputStream(InputStream& source,
|
| int64 maxNumBytesToWrite) {
|
| // before writing from an input, see if we can preallocate to make it more
|
| // efficient..
|
| int64 availableData = source.getTotalLength() - source.getPosition();
|
|
|
| if (availableData > 0) {
|
| if (maxNumBytesToWrite > availableData || maxNumBytesToWrite < 0)
|
| maxNumBytesToWrite = availableData;
|
|
|
| if (blockToUse != NULL)
|
| preallocate(blockToUse->getSize() + (size_t)maxNumBytesToWrite);
|
| }
|
|
|
| return OutputStream::writeFromInputStream(source, maxNumBytesToWrite);
|
| }
|
|
|
| OutputStream& operator<<(OutputStream& stream,
|
| const MemoryOutputStream& streamToRead) {
|
| const size_t dataSize = streamToRead.getDataSize();
|
|
|
| if (dataSize > 0) stream.write(streamToRead.getData(), dataSize);
|
|
|
| return stream;
|
| }
|
| }
|