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 uint8_t* Stream::getRawBufferAddr() {
     83     return NULL;
     84 }
     85 
     86 jobject Stream::getRawBuffer() {
     87     return NULL;
     88 }
     89 
     90 int Stream::getRawBufferSize() {
     91     return 0;
     92 }
     93 
     94 uint8_t* MemoryStream::getRawBufferAddr() {
     95     return mBuffer;
     96 }
     97 
     98 jobject MemoryStream::getRawBuffer() {
     99     return mRawBuffer;
    100 }
    101 
    102 int MemoryStream::getRawBufferSize() {
    103     if (mRawBuffer != NULL) {
    104         return mRemaining;
    105     } else {
    106         return 0;
    107     }
    108 }
    109 
    110 size_t MemoryStream::doRead(void* buffer, size_t size) {
    111     size = min(size, mRemaining);
    112     memcpy(buffer, mBuffer, size);
    113     mBuffer += size;
    114     mRemaining -= size;
    115     return size;
    116 }
    117 
    118 size_t FileStream::doRead(void* buffer, size_t size) {
    119     return fread(buffer, 1, size, mFd);
    120 }
    121 
    122 size_t JavaInputStream::doRead(void* dstBuffer, size_t size) {
    123     size_t totalBytesRead = 0;
    124 
    125     do {
    126         size_t requested = min(size, mByteArrayLength);
    127 
    128         jint bytesRead = mEnv->CallIntMethod(mInputStream,
    129                 gInputStreamClassInfo.read, mByteArray, 0, requested);
    130         if (mEnv->ExceptionCheck() || bytesRead < 0) {
    131             return 0;
    132         }
    133 
    134         mEnv->GetByteArrayRegion(mByteArray, 0, bytesRead, (jbyte*)dstBuffer);
    135         dstBuffer = (char*)dstBuffer + bytesRead;
    136         totalBytesRead += bytesRead;
    137         size -= bytesRead;
    138     } while (size > 0);
    139 
    140     return totalBytesRead;
    141 }
    142 
    143 jint JavaStream_OnLoad(JNIEnv* env) {
    144     // Skip the verbose logging on error for these, as they won't be subject
    145     // to obfuscators or similar and are thus unlikely to ever fail
    146     jclass inputStreamClazz = env->FindClass("java/io/InputStream");
    147     if (!inputStreamClazz) {
    148         return -1;
    149     }
    150     gInputStreamClassInfo.read = env->GetMethodID(inputStreamClazz, "read", "([BII)I");
    151     gInputStreamClassInfo.reset = env->GetMethodID(inputStreamClazz, "reset", "()V");
    152     if (!gInputStreamClassInfo.read || !gInputStreamClassInfo.reset) {
    153         return -1;
    154     }
    155     return 0;
    156 }
    157