OLD | NEW |
| (Empty) |
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/browser/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/InputStreamUtil_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 | |
21 namespace android_webview { | |
22 | |
23 namespace { | |
24 | |
25 // This should be the same as InputStramUtil.EXCEPTION_THROWN_STATUS. | |
26 const int kExceptionThrownStatusCode = -2; | |
27 } | |
28 | |
29 // Maximum number of bytes to be read in a single read. | |
30 const int InputStreamImpl::kBufferSize = 4096; | |
31 | |
32 // static | |
33 const InputStreamImpl* InputStreamImpl::FromInputStream( | |
34 const InputStream* input_stream) { | |
35 return static_cast<const InputStreamImpl*>(input_stream); | |
36 } | |
37 | |
38 // TODO: Use unsafe version for all Java_InputStream methods in this file | |
39 // once BUG 157880 is fixed and implement graceful exception handling. | |
40 | |
41 InputStreamImpl::InputStreamImpl() {} | |
42 | |
43 InputStreamImpl::InputStreamImpl(const JavaRef<jobject>& stream) | |
44 : jobject_(stream) { | |
45 DCHECK(!stream.is_null()); | |
46 } | |
47 | |
48 InputStreamImpl::~InputStreamImpl() { | |
49 JNIEnv* env = AttachCurrentThread(); | |
50 Java_InputStreamUtil_close(env, jobject_); | |
51 } | |
52 | |
53 bool InputStreamImpl::BytesAvailable(int* bytes_available) const { | |
54 JNIEnv* env = AttachCurrentThread(); | |
55 int bytes = Java_InputStreamUtil_available(env, jobject_); | |
56 if (bytes == kExceptionThrownStatusCode) | |
57 return false; | |
58 *bytes_available = bytes; | |
59 return true; | |
60 } | |
61 | |
62 bool InputStreamImpl::Skip(int64_t n, int64_t* bytes_skipped) { | |
63 JNIEnv* env = AttachCurrentThread(); | |
64 int bytes = Java_InputStreamUtil_skip(env, jobject_, n); | |
65 if (bytes < 0) | |
66 return false; | |
67 if (bytes > n) | |
68 return false; | |
69 *bytes_skipped = bytes; | |
70 return true; | |
71 } | |
72 | |
73 bool InputStreamImpl::Read(net::IOBuffer* dest, int length, int* bytes_read) { | |
74 JNIEnv* env = AttachCurrentThread(); | |
75 if (!buffer_.obj()) { | |
76 // Allocate transfer buffer. | |
77 base::android::ScopedJavaLocalRef<jbyteArray> temp( | |
78 env, env->NewByteArray(kBufferSize)); | |
79 buffer_.Reset(temp); | |
80 if (ClearException(env)) | |
81 return false; | |
82 } | |
83 | |
84 int remaining_length = length; | |
85 char* dest_write_ptr = dest->data(); | |
86 *bytes_read = 0; | |
87 | |
88 while (remaining_length > 0) { | |
89 const int max_transfer_length = std::min(remaining_length, kBufferSize); | |
90 const int transfer_length = Java_InputStreamUtil_read( | |
91 env, jobject_, buffer_, 0, max_transfer_length); | |
92 if (transfer_length == kExceptionThrownStatusCode) | |
93 return false; | |
94 | |
95 if (transfer_length < 0) // EOF | |
96 break; | |
97 | |
98 // Note: it is possible, yet unlikely, that the Java InputStream returns | |
99 // a transfer_length == 0 from time to time. In such cases we just continue | |
100 // the read until we get either valid data or reach EOF. | |
101 if (transfer_length == 0) | |
102 continue; | |
103 | |
104 DCHECK_GE(max_transfer_length, transfer_length); | |
105 DCHECK_GE(env->GetArrayLength(buffer_.obj()), transfer_length); | |
106 | |
107 // This check is to prevent a malicious InputStream implementation from | |
108 // overrunning the |dest| buffer. | |
109 if (transfer_length > max_transfer_length) | |
110 return false; | |
111 | |
112 // Copy the data over to the provided C++ IOBuffer. | |
113 DCHECK_GE(remaining_length, transfer_length); | |
114 env->GetByteArrayRegion(buffer_.obj(), 0, transfer_length, | |
115 reinterpret_cast<jbyte*>(dest_write_ptr)); | |
116 if (ClearException(env)) | |
117 return false; | |
118 | |
119 remaining_length -= transfer_length; | |
120 dest_write_ptr += transfer_length; | |
121 } | |
122 // bytes_read can be strictly less than the req. length if EOF is encountered. | |
123 DCHECK_GE(remaining_length, 0); | |
124 DCHECK_LE(remaining_length, length); | |
125 *bytes_read = length - remaining_length; | |
126 return true; | |
127 } | |
128 | |
129 } // namespace android_webview | |
OLD | NEW |