Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "Stream"
     18 
     19 #include "Stream.h"
     20 
     21 #include <string.h>
     22 
     23 #include "JNIHelpers.h"
     24 #include "utils/log.h"
     25 #include "utils/math.h"
     26 
     27 static struct {
     28     jmethodID read;
     29     jmethodID reset;
     30 } gInputStreamClassInfo;
     31 
     32 Stream::Stream()
     33     : mPeekBuffer(0)
     34     , mPeekSize(0)
     35     , mPeekOffset(0) {
     36 }
     37 
     38 Stream::~Stream() {
     39     delete mPeekBuffer;
     40 }
     41 
     42 size_t Stream::peek(void* buffer, size_t size) {
     43     size_t peek_remaining = mPeekSize - mPeekOffset;
     44     if (size > peek_remaining) {
     45         char* old_peek = mPeekBuffer;
     46         mPeekBuffer = new char[size];
     47         if (old_peek) {
     48             memcpy(mPeekBuffer, old_peek + mPeekOffset, peek_remaining);
     49             delete old_peek;
     50         }
     51         size_t read = doRead(mPeekBuffer + mPeekOffset, size - peek_remaining);
     52         mPeekOffset = 0;
     53         mPeekSize = peek_remaining + read;
     54     }
     55     size = min(size, mPeekSize - mPeekOffset);
     56     memcpy(buffer, mPeekBuffer + mPeekOffset, size);
     57     return size;
     58 }
     59 
     60 size_t Stream::read(void* buffer, size_t size) {
     61     size_t bytes_read = 0;
     62     size_t peek_remaining = mPeekSize - mPeekOffset;
     63     if (peek_remaining) {
     64         bytes_read = min(size, peek_remaining);
     65         memcpy(buffer, mPeekBuffer + mPeekOffset, bytes_read);
     66         mPeekOffset += bytes_read;
     67         if (mPeekOffset == mPeekSize) {
     68             delete mPeekBuffer;
     69             mPeekBuffer = 0;
     70             mPeekOffset = 0;
     71             mPeekSize = 0;
     72         }
     73         size -= bytes_read;
     74         buffer = ((char*) buffer) + bytes_read;
     75     }
     76     if (size) {
     77         bytes_read += doRead(buffer, size);
     78     }
     79     return bytes_read;
     80 }
     81 
     82 size_t MemoryStream::doRead(void* buffer, size_t size) {
     83     size = min(size, mRemaining);
     84     memcpy(buffer, mBuffer, size);
     85     mBuffer += size;
     86     mRemaining -= size;
     87     return size;
     88 }
     89 
     90 size_t FileStream::doRead(void* buffer, size_t size) {
     91     return fread(buffer, 1, size, mFd);
     92 }
     93 
     94 size_t JavaInputStream::doRead(void* dstBuffer, size_t size) {
     95     size_t totalBytesRead = 0;
     96 
     97     do {
     98         size_t requested = min(size, mByteArrayLength);
     99 
    100         jint bytesRead = mEnv->CallIntMethod(mInputStream,
    101                 gInputStreamClassInfo.read, mByteArray, 0, requested);
    102         if (mEnv->ExceptionCheck() || bytesRead < 0) {
    103             return 0;
    104         }
    105 
    106         mEnv->GetByteArrayRegion(mByteArray, 0, bytesRead, (jbyte*)dstBuffer);
    107         dstBuffer = (char*)dstBuffer + bytesRead;
    108         totalBytesRead += bytesRead;
    109         size -= bytesRead;
    110     } while (size > 0);
    111 
    112     return totalBytesRead;
    113 }
    114 
    115 jint JavaStream_OnLoad(JNIEnv* env) {
    116     // Skip the verbose logging on error for these, as they won't be subject
    117     // to obfuscators or similar and are thus unlikely to ever fail
    118     jclass inputStreamClazz = env->FindClass("java/io/InputStream");
    119     if (!inputStreamClazz) {
    120         return -1;
    121     }
    122     gInputStreamClassInfo.read = env->GetMethodID(inputStreamClazz, "read", "([BII)I");
    123     gInputStreamClassInfo.reset = env->GetMethodID(inputStreamClazz, "reset", "()V");
    124     if (!gInputStreamClassInfo.read || !gInputStreamClassInfo.reset) {
    125         return -1;
    126     }
    127     return 0;
    128 }
    129