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