12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "android_webview/native/input_stream_impl.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/android/jni_android.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Disable "Warnings treated as errors" for input_stream_jni as it's a Java
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// system class and we have to generate C++ hooks for all methods in the class
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// even if they're unused.
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#pragma GCC diagnostic push
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#pragma GCC diagnostic ignored "-Wunused-function"
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "jni/InputStreamUtil_jni.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#pragma GCC diagnostic pop
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/io_buffer.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::android::AttachCurrentThread;
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::android::ClearException;
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::android::JavaRef;
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace android_webview {
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace {
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// This should be the same as InputStramUtil.EXCEPTION_THROWN_STATUS.
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kExceptionThrownStatusCode = -2;
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool RegisterInputStream(JNIEnv* env) {
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return RegisterNativesImpl(env);
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Maximum number of bytes to be read in a single read.
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int InputStreamImpl::kBufferSize = 4096;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//static
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const InputStreamImpl* InputStreamImpl::FromInputStream(
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        const InputStream* input_stream) {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return static_cast<const InputStreamImpl*>(input_stream);
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO: Use unsafe version for all Java_InputStream methods in this file
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// once BUG 157880 is fixed and implement graceful exception handling.
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputStreamImpl::InputStreamImpl() {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputStreamImpl::InputStreamImpl(const JavaRef<jobject>& stream)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : jobject_(stream) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!stream.is_null());
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputStreamImpl::~InputStreamImpl() {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Java_InputStreamUtil_close(env, jobject_.obj());
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InputStreamImpl::BytesAvailable(int* bytes_available) const {
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int bytes = Java_InputStreamUtil_available(env, jobject_.obj());
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (bytes == kExceptionThrownStatusCode)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *bytes_available = bytes;
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InputStreamImpl::Skip(int64_t n, int64_t* bytes_skipped) {
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int bytes = Java_InputStreamUtil_skip(env, jobject_.obj(), n);
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (bytes < 0)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (bytes > n)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *bytes_skipped = bytes;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InputStreamImpl::Read(net::IOBuffer* dest, int length, int* bytes_read) {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!buffer_.obj()) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Allocate transfer buffer.
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::android::ScopedJavaLocalRef<jbyteArray> temp(
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        env, env->NewByteArray(kBufferSize));
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    buffer_.Reset(temp);
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (ClearException(env))
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
90d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int remaining_length = length;
91d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  char* dest_write_ptr = dest->data();
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  jbyteArray buffer = buffer_.obj();
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *bytes_read = 0;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
95d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  while (remaining_length > 0) {
96d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const int max_transfer_length = std::min(remaining_length, kBufferSize);
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const int transfer_length = Java_InputStreamUtil_read(
98d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        env, jobject_.obj(), buffer, 0, max_transfer_length);
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (transfer_length == kExceptionThrownStatusCode)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (transfer_length < 0)  // EOF
103d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      break;
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
105d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Note: it is possible, yet unlikely, that the Java InputStream returns
106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // a transfer_length == 0 from time to time. In such cases we just continue
107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // the read until we get either valid data or reach EOF.
108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (transfer_length == 0)
109d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      continue;
110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
111d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DCHECK_GE(max_transfer_length, transfer_length);
112d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DCHECK_GE(env->GetArrayLength(buffer), transfer_length);
113d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // This check is to prevent a malicious InputStream implementation from
115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // overrunning the |dest| buffer.
116d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (transfer_length > max_transfer_length)
117d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return false;
118d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
119d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Copy the data over to the provided C++ IOBuffer.
120d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DCHECK_GE(remaining_length, transfer_length);
121d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    env->GetByteArrayRegion(buffer, 0, transfer_length,
122d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        reinterpret_cast<jbyte*>(dest_write_ptr));
123d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (ClearException(env))
124d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return false;
125d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
126d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    remaining_length -= transfer_length;
127d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    dest_write_ptr += transfer_length;
128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
129d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // bytes_read can be strictly less than the req. length if EOF is encountered.
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_GE(remaining_length, 0);
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_LE(remaining_length, length);
132d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  *bytes_read = length - remaining_length;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace android_webview
137