diff options
Diffstat (limited to 'framesequence/jni/Stream.cpp')
-rw-r--r-- | framesequence/jni/Stream.cpp | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/framesequence/jni/Stream.cpp b/framesequence/jni/Stream.cpp new file mode 100644 index 0000000..b2e0c39 --- /dev/null +++ b/framesequence/jni/Stream.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2013 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. + */ + +#define LOG_TAG "Stream" + +#include "Stream.h" + +#include <string.h> + +#include "JNIHelpers.h" +#include "utils/log.h" +#include "utils/math.h" + +static struct { + jmethodID read; + jmethodID reset; +} gInputStreamClassInfo; + +Stream::Stream() + : mPeekBuffer(0) + , mPeekSize(0) + , mPeekOffset(0) { +} + +Stream::~Stream() { + delete mPeekBuffer; +} + +size_t Stream::peek(void* buffer, size_t size) { + size_t peek_remaining = mPeekSize - mPeekOffset; + if (size > peek_remaining) { + char* old_peek = mPeekBuffer; + mPeekBuffer = new char[size]; + if (old_peek) { + memcpy(mPeekBuffer, old_peek + mPeekOffset, peek_remaining); + delete old_peek; + } + size_t read = doRead(mPeekBuffer + mPeekOffset, size - peek_remaining); + mPeekOffset = 0; + mPeekSize = peek_remaining + read; + } + size = min(size, mPeekSize - mPeekOffset); + memcpy(buffer, mPeekBuffer + mPeekOffset, size); + return size; +} + +size_t Stream::read(void* buffer, size_t size) { + size_t bytes_read = 0; + size_t peek_remaining = mPeekSize - mPeekOffset; + if (peek_remaining) { + bytes_read = min(size, peek_remaining); + memcpy(buffer, mPeekBuffer + mPeekOffset, bytes_read); + mPeekOffset += bytes_read; + if (mPeekOffset == mPeekSize) { + delete mPeekBuffer; + mPeekBuffer = 0; + mPeekOffset = 0; + mPeekSize = 0; + } + size -= bytes_read; + buffer = ((char*) buffer) + bytes_read; + } + if (size) { + bytes_read += doRead(buffer, size); + } + return bytes_read; +} + +size_t MemoryStream::doRead(void* buffer, size_t size) { + size = min(size, mRemaining); + memcpy(buffer, mBuffer, size); + mBuffer += size; + mRemaining -= size; + return size; +} + +size_t FileStream::doRead(void* buffer, size_t size) { + return fread(buffer, 1, size, mFd); +} + +size_t JavaInputStream::doRead(void* dstBuffer, size_t size) { + size_t totalBytesRead = 0; + + do { + size_t requested = min(size, mByteArrayLength); + + jint bytesRead = mEnv->CallIntMethod(mInputStream, + gInputStreamClassInfo.read, mByteArray, 0, requested); + if (mEnv->ExceptionCheck() || bytesRead < 0) { + return 0; + } + + mEnv->GetByteArrayRegion(mByteArray, 0, bytesRead, (jbyte*)dstBuffer); + dstBuffer = (char*)dstBuffer + bytesRead; + totalBytesRead += bytesRead; + size -= bytesRead; + } while (size > 0); + + return totalBytesRead; +} + +jint JavaStream_OnLoad(JNIEnv* env) { + // Skip the verbose logging on error for these, as they won't be subject + // to obfuscators or similar and are thus unlikely to ever fail + jclass inputStreamClazz = env->FindClass("java/io/InputStream"); + if (!inputStreamClazz) { + return -1; + } + gInputStreamClassInfo.read = env->GetMethodID(inputStreamClazz, "read", "([BII)I"); + gInputStreamClassInfo.reset = env->GetMethodID(inputStreamClazz, "reset", "()V"); + if (!gInputStreamClassInfo.read || !gInputStreamClassInfo.reset) { + return -1; + } + return 0; +} |