1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "android_webview/native/input_stream_impl.h" 6 7 #include "base/android/jni_android.h" 8 // Disable "Warnings treated as errors" for input_stream_jni as it's a Java 9 // system class and we have to generate C++ hooks for all methods in the class 10 // even if they're unused. 11 #pragma GCC diagnostic push 12 #pragma GCC diagnostic ignored "-Wunused-function" 13 #include "jni/InputStream_jni.h" 14 #pragma GCC diagnostic pop 15 #include "net/base/io_buffer.h" 16 17 using base::android::AttachCurrentThread; 18 using base::android::ClearException; 19 using base::android::JavaRef; 20 using JNI_InputStream::Java_InputStream_available; 21 using JNI_InputStream::Java_InputStream_close; 22 using JNI_InputStream::Java_InputStream_skip; 23 using JNI_InputStream::Java_InputStream_readI_AB_I_I; 24 25 namespace android_webview { 26 27 bool RegisterInputStream(JNIEnv* env) { 28 return JNI_InputStream::RegisterNativesImpl(env); 29 } 30 31 // Maximum number of bytes to be read in a single read. 32 const int InputStreamImpl::kBufferSize = 4096; 33 34 //static 35 const InputStreamImpl* InputStreamImpl::FromInputStream( 36 const InputStream* input_stream) { 37 return static_cast<const InputStreamImpl*>(input_stream); 38 } 39 40 // TODO: Use unsafe version for all Java_InputStream methods in this file 41 // once BUG 157880 is fixed and implement graceful exception handling. 42 43 InputStreamImpl::InputStreamImpl() { 44 } 45 46 InputStreamImpl::InputStreamImpl(const JavaRef<jobject>& stream) 47 : jobject_(stream) { 48 DCHECK(!stream.is_null()); 49 } 50 51 InputStreamImpl::~InputStreamImpl() { 52 JNIEnv* env = AttachCurrentThread(); 53 Java_InputStream_close(env, jobject_.obj()); 54 } 55 56 bool InputStreamImpl::BytesAvailable(int* bytes_available) const { 57 JNIEnv* env = AttachCurrentThread(); 58 int bytes = Java_InputStream_available(env, jobject_.obj()); 59 if (ClearException(env)) 60 return false; 61 *bytes_available = bytes; 62 return true; 63 } 64 65 bool InputStreamImpl::Skip(int64_t n, int64_t* bytes_skipped) { 66 JNIEnv* env = AttachCurrentThread(); 67 int bytes = Java_InputStream_skip(env, jobject_.obj(), n); 68 if (ClearException(env)) 69 return false; 70 if (bytes > n) 71 return false; 72 *bytes_skipped = bytes; 73 return true; 74 } 75 76 bool InputStreamImpl::Read(net::IOBuffer* dest, int length, int* bytes_read) { 77 JNIEnv* env = AttachCurrentThread(); 78 if (!buffer_.obj()) { 79 // Allocate transfer buffer. 80 base::android::ScopedJavaLocalRef<jbyteArray> temp( 81 env, env->NewByteArray(kBufferSize)); 82 buffer_.Reset(temp); 83 if (ClearException(env)) 84 return false; 85 } 86 87 int remaining_length = length; 88 char* dest_write_ptr = dest->data(); 89 jbyteArray buffer = buffer_.obj(); 90 *bytes_read = 0; 91 92 while (remaining_length > 0) { 93 const int max_transfer_length = std::min(remaining_length, kBufferSize); 94 const int transfer_length = Java_InputStream_readI_AB_I_I( 95 env, jobject_.obj(), buffer, 0, max_transfer_length); 96 if (ClearException(env)) 97 return false; 98 99 if (transfer_length < 0) // EOF 100 break; 101 102 // Note: it is possible, yet unlikely, that the Java InputStream returns 103 // a transfer_length == 0 from time to time. In such cases we just continue 104 // the read until we get either valid data or reach EOF. 105 if (transfer_length == 0) 106 continue; 107 108 DCHECK_GE(max_transfer_length, transfer_length); 109 DCHECK_GE(env->GetArrayLength(buffer), transfer_length); 110 111 // This check is to prevent a malicious InputStream implementation from 112 // overrunning the |dest| buffer. 113 if (transfer_length > max_transfer_length) 114 return false; 115 116 // Copy the data over to the provided C++ IOBuffer. 117 DCHECK_GE(remaining_length, transfer_length); 118 env->GetByteArrayRegion(buffer, 0, transfer_length, 119 reinterpret_cast<jbyte*>(dest_write_ptr)); 120 if (ClearException(env)) 121 return false; 122 123 remaining_length -= transfer_length; 124 dest_write_ptr += transfer_length; 125 } 126 // bytes_read can be strictly less than the req. length if EOF is encountered. 127 DCHECK(remaining_length >= 0 && remaining_length <= length); 128 *bytes_read = length - remaining_length; 129 return true; 130 } 131 132 } // namespace android_webview 133