1 | // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "bin/filter.h" |
6 | |
7 | #include "bin/dartutils.h" |
8 | #include "bin/io_buffer.h" |
9 | |
10 | #include "include/dart_api.h" |
11 | |
12 | namespace dart { |
13 | namespace bin { |
14 | |
15 | const int = 16; |
16 | const int = 32; |
17 | |
18 | static const int kFilterPointerNativeField = 0; |
19 | |
20 | static Dart_Handle GetFilter(Dart_Handle filter_obj, Filter** filter) { |
21 | ASSERT(filter != NULL); |
22 | Filter* result; |
23 | Dart_Handle err = Filter::GetFilterNativeField(filter_obj, &result); |
24 | if (Dart_IsError(err)) { |
25 | return err; |
26 | } |
27 | if (result == NULL) { |
28 | return Dart_NewApiError("Filter was destroyed" ); |
29 | } |
30 | |
31 | *filter = result; |
32 | return Dart_Null(); |
33 | } |
34 | |
35 | static Dart_Handle CopyDictionary(Dart_Handle dictionary_obj, |
36 | uint8_t** dictionary) { |
37 | ASSERT(dictionary != NULL); |
38 | uint8_t* src = NULL; |
39 | intptr_t size; |
40 | Dart_TypedData_Type type; |
41 | |
42 | Dart_Handle err = Dart_ListLength(dictionary_obj, &size); |
43 | if (Dart_IsError(err)) { |
44 | return err; |
45 | } |
46 | |
47 | uint8_t* result = new uint8_t[size]; |
48 | if (result == NULL) { |
49 | return Dart_NewApiError("Could not allocate new dictionary" ); |
50 | } |
51 | |
52 | err = Dart_TypedDataAcquireData(dictionary_obj, &type, |
53 | reinterpret_cast<void**>(&src), &size); |
54 | if (!Dart_IsError(err)) { |
55 | memmove(result, src, size); |
56 | Dart_TypedDataReleaseData(dictionary_obj); |
57 | } else { |
58 | err = Dart_ListGetAsBytes(dictionary_obj, 0, result, size); |
59 | if (Dart_IsError(err)) { |
60 | delete[] result; |
61 | return err; |
62 | } |
63 | } |
64 | |
65 | *dictionary = result; |
66 | return Dart_Null(); |
67 | } |
68 | |
69 | void FUNCTION_NAME(Filter_CreateZLibInflate)(Dart_NativeArguments args) { |
70 | Dart_Handle filter_obj = Dart_GetNativeArgument(args, 0); |
71 | Dart_Handle window_bits_obj = Dart_GetNativeArgument(args, 1); |
72 | int64_t window_bits = DartUtils::GetIntegerValue(window_bits_obj); |
73 | Dart_Handle dict_obj = Dart_GetNativeArgument(args, 2); |
74 | Dart_Handle raw_obj = Dart_GetNativeArgument(args, 3); |
75 | bool raw = DartUtils::GetBooleanValue(raw_obj); |
76 | |
77 | Dart_Handle err; |
78 | uint8_t* dictionary = NULL; |
79 | intptr_t dictionary_length = 0; |
80 | if (!Dart_IsNull(dict_obj)) { |
81 | err = CopyDictionary(dict_obj, &dictionary); |
82 | if (Dart_IsError(err)) { |
83 | Dart_PropagateError(err); |
84 | } |
85 | ASSERT(dictionary != NULL); |
86 | dictionary_length = 0; |
87 | err = Dart_ListLength(dict_obj, &dictionary_length); |
88 | if (Dart_IsError(err)) { |
89 | delete[] dictionary; |
90 | Dart_PropagateError(err); |
91 | } |
92 | } |
93 | |
94 | ZLibInflateFilter* filter = new ZLibInflateFilter( |
95 | static_cast<int32_t>(window_bits), dictionary, dictionary_length, raw); |
96 | if (filter == NULL) { |
97 | delete[] dictionary; |
98 | Dart_PropagateError( |
99 | Dart_NewApiError("Could not allocate ZLibInflateFilter" )); |
100 | } |
101 | if (!filter->Init()) { |
102 | delete filter; |
103 | Dart_ThrowException( |
104 | DartUtils::NewInternalError("Failed to create ZLibInflateFilter" )); |
105 | } |
106 | err = Filter::SetFilterAndCreateFinalizer( |
107 | filter_obj, filter, sizeof(*filter) + dictionary_length); |
108 | if (Dart_IsError(err)) { |
109 | delete filter; |
110 | Dart_PropagateError(err); |
111 | } |
112 | } |
113 | |
114 | void FUNCTION_NAME(Filter_CreateZLibDeflate)(Dart_NativeArguments args) { |
115 | Dart_Handle filter_obj = Dart_GetNativeArgument(args, 0); |
116 | Dart_Handle gzip_obj = Dart_GetNativeArgument(args, 1); |
117 | bool gzip = DartUtils::GetBooleanValue(gzip_obj); |
118 | Dart_Handle level_obj = Dart_GetNativeArgument(args, 2); |
119 | int64_t level = |
120 | DartUtils::GetInt64ValueCheckRange(level_obj, kMinInt32, kMaxInt32); |
121 | Dart_Handle window_bits_obj = Dart_GetNativeArgument(args, 3); |
122 | int64_t window_bits = DartUtils::GetIntegerValue(window_bits_obj); |
123 | Dart_Handle mLevel_obj = Dart_GetNativeArgument(args, 4); |
124 | int64_t mem_level = DartUtils::GetIntegerValue(mLevel_obj); |
125 | Dart_Handle strategy_obj = Dart_GetNativeArgument(args, 5); |
126 | int64_t strategy = DartUtils::GetIntegerValue(strategy_obj); |
127 | Dart_Handle dict_obj = Dart_GetNativeArgument(args, 6); |
128 | Dart_Handle raw_obj = Dart_GetNativeArgument(args, 7); |
129 | bool raw = DartUtils::GetBooleanValue(raw_obj); |
130 | |
131 | Dart_Handle err; |
132 | uint8_t* dictionary = NULL; |
133 | intptr_t dictionary_length = 0; |
134 | if (!Dart_IsNull(dict_obj)) { |
135 | err = CopyDictionary(dict_obj, &dictionary); |
136 | if (Dart_IsError(err)) { |
137 | Dart_PropagateError(err); |
138 | } |
139 | ASSERT(dictionary != NULL); |
140 | dictionary_length = 0; |
141 | err = Dart_ListLength(dict_obj, &dictionary_length); |
142 | if (Dart_IsError(err)) { |
143 | delete[] dictionary; |
144 | Dart_PropagateError(err); |
145 | } |
146 | } |
147 | |
148 | ZLibDeflateFilter* filter = new ZLibDeflateFilter( |
149 | gzip, static_cast<int32_t>(level), static_cast<int32_t>(window_bits), |
150 | static_cast<int32_t>(mem_level), static_cast<int32_t>(strategy), |
151 | dictionary, dictionary_length, raw); |
152 | if (filter == NULL) { |
153 | delete[] dictionary; |
154 | Dart_PropagateError( |
155 | Dart_NewApiError("Could not allocate ZLibDeflateFilter" )); |
156 | } |
157 | if (!filter->Init()) { |
158 | delete filter; |
159 | Dart_ThrowException( |
160 | DartUtils::NewInternalError("Failed to create ZLibDeflateFilter" )); |
161 | } |
162 | Dart_Handle result = Filter::SetFilterAndCreateFinalizer( |
163 | filter_obj, filter, sizeof(*filter) + dictionary_length); |
164 | if (Dart_IsError(result)) { |
165 | delete filter; |
166 | Dart_PropagateError(result); |
167 | } |
168 | } |
169 | |
170 | void FUNCTION_NAME(Filter_Process)(Dart_NativeArguments args) { |
171 | Dart_Handle filter_obj = Dart_GetNativeArgument(args, 0); |
172 | Dart_Handle data_obj = Dart_GetNativeArgument(args, 1); |
173 | intptr_t start = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 2)); |
174 | intptr_t end = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 3)); |
175 | intptr_t chunk_length = end - start; |
176 | intptr_t length; |
177 | Dart_TypedData_Type type; |
178 | uint8_t* buffer = NULL; |
179 | |
180 | Filter* filter = NULL; |
181 | Dart_Handle err = GetFilter(filter_obj, &filter); |
182 | if (Dart_IsError(err)) { |
183 | Dart_PropagateError(err); |
184 | } |
185 | |
186 | Dart_Handle result = Dart_TypedDataAcquireData( |
187 | data_obj, &type, reinterpret_cast<void**>(&buffer), &length); |
188 | if (!Dart_IsError(result)) { |
189 | ASSERT(type == Dart_TypedData_kUint8 || type == Dart_TypedData_kInt8); |
190 | if (type != Dart_TypedData_kUint8 && type != Dart_TypedData_kInt8) { |
191 | Dart_TypedDataReleaseData(data_obj); |
192 | Dart_ThrowException(DartUtils::NewInternalError( |
193 | "Invalid argument passed to Filter_Process" )); |
194 | } |
195 | uint8_t* zlib_buffer = new uint8_t[chunk_length]; |
196 | if (zlib_buffer == NULL) { |
197 | Dart_TypedDataReleaseData(data_obj); |
198 | Dart_PropagateError(Dart_NewApiError("Could not allocate zlib buffer" )); |
199 | } |
200 | |
201 | memmove(zlib_buffer, buffer + start, chunk_length); |
202 | Dart_TypedDataReleaseData(data_obj); |
203 | buffer = zlib_buffer; |
204 | } else { |
205 | err = Dart_ListLength(data_obj, &length); |
206 | if (Dart_IsError(err)) { |
207 | Dart_PropagateError(err); |
208 | } |
209 | buffer = new uint8_t[chunk_length]; |
210 | if (buffer == NULL) { |
211 | Dart_PropagateError(Dart_NewApiError("Could not allocate buffer" )); |
212 | } |
213 | err = Dart_ListGetAsBytes(data_obj, start, buffer, chunk_length); |
214 | if (Dart_IsError(err)) { |
215 | delete[] buffer; |
216 | Dart_PropagateError(err); |
217 | } |
218 | } |
219 | // Process will take ownership of buffer, if successful. |
220 | if (!filter->Process(buffer, chunk_length)) { |
221 | delete[] buffer; |
222 | Dart_ThrowException(DartUtils::NewInternalError( |
223 | "Call to Process while still processing data" )); |
224 | } |
225 | } |
226 | |
227 | void FUNCTION_NAME(Filter_Processed)(Dart_NativeArguments args) { |
228 | Dart_Handle filter_obj = Dart_GetNativeArgument(args, 0); |
229 | Dart_Handle flush_obj = Dart_GetNativeArgument(args, 1); |
230 | bool flush = DartUtils::GetBooleanValue(flush_obj); |
231 | Dart_Handle end_obj = Dart_GetNativeArgument(args, 2); |
232 | bool end = DartUtils::GetBooleanValue(end_obj); |
233 | |
234 | Filter* filter = NULL; |
235 | Dart_Handle err = GetFilter(filter_obj, &filter); |
236 | if (Dart_IsError(err)) { |
237 | Dart_PropagateError(err); |
238 | } |
239 | |
240 | intptr_t read = filter->Processed( |
241 | filter->processed_buffer(), filter->processed_buffer_size(), flush, end); |
242 | if (read < 0) { |
243 | Dart_ThrowException( |
244 | DartUtils::NewDartFormatException("Filter error, bad data" )); |
245 | } else if (read == 0) { |
246 | Dart_SetReturnValue(args, Dart_Null()); |
247 | } else { |
248 | uint8_t* io_buffer; |
249 | Dart_Handle result = IOBuffer::Allocate(read, &io_buffer); |
250 | if (Dart_IsNull(result)) { |
251 | Dart_SetReturnValue(args, DartUtils::NewDartOSError()); |
252 | return; |
253 | } |
254 | memmove(io_buffer, filter->processed_buffer(), read); |
255 | Dart_SetReturnValue(args, result); |
256 | } |
257 | } |
258 | |
259 | static void DeleteFilter(void* isolate_data, void* filter_pointer) { |
260 | Filter* filter = reinterpret_cast<Filter*>(filter_pointer); |
261 | delete filter; |
262 | } |
263 | |
264 | Dart_Handle Filter::SetFilterAndCreateFinalizer(Dart_Handle filter, |
265 | Filter* filter_pointer, |
266 | intptr_t size) { |
267 | Dart_Handle err = |
268 | Dart_SetNativeInstanceField(filter, kFilterPointerNativeField, |
269 | reinterpret_cast<intptr_t>(filter_pointer)); |
270 | if (Dart_IsError(err)) { |
271 | return err; |
272 | } |
273 | Dart_NewFinalizableHandle(filter, reinterpret_cast<void*>(filter_pointer), |
274 | size, DeleteFilter); |
275 | return err; |
276 | } |
277 | |
278 | Dart_Handle Filter::GetFilterNativeField(Dart_Handle filter, |
279 | Filter** filter_pointer) { |
280 | return Dart_GetNativeInstanceField( |
281 | filter, kFilterPointerNativeField, |
282 | reinterpret_cast<intptr_t*>(filter_pointer)); |
283 | } |
284 | |
285 | ZLibDeflateFilter::~ZLibDeflateFilter() { |
286 | delete[] dictionary_; |
287 | delete[] current_buffer_; |
288 | if (initialized()) { |
289 | deflateEnd(&stream_); |
290 | } |
291 | } |
292 | |
293 | bool ZLibDeflateFilter::Init() { |
294 | int window_bits = window_bits_; |
295 | if ((raw_ || gzip_) && (window_bits == 8)) { |
296 | // zlib deflater does not work with windows size of 8 bits. Old versions |
297 | // of zlib would silently upgrade window size to 9 bits, newer versions |
298 | // return Z_STREAM_ERROR if window size is 8 bits but the stream header |
299 | // is suppressed. To maintain the old behavior upgrade window size here. |
300 | // This is safe because you can inflate a stream deflated with zlib |
301 | // using 9-bits with 8-bits window. |
302 | // For more details see https://crbug.com/691074. |
303 | window_bits = 9; |
304 | } |
305 | if (raw_) { |
306 | window_bits = -window_bits; |
307 | } else if (gzip_) { |
308 | window_bits += kZLibFlagUseGZipHeader; |
309 | } |
310 | stream_.next_in = Z_NULL; |
311 | stream_.zalloc = Z_NULL; |
312 | stream_.zfree = Z_NULL; |
313 | stream_.opaque = Z_NULL; |
314 | int result = deflateInit2(&stream_, level_, Z_DEFLATED, window_bits, |
315 | mem_level_, strategy_); |
316 | if (result != Z_OK) { |
317 | return false; |
318 | } |
319 | if ((dictionary_ != NULL) && !gzip_ && !raw_) { |
320 | result = deflateSetDictionary(&stream_, dictionary_, dictionary_length_); |
321 | delete[] dictionary_; |
322 | dictionary_ = NULL; |
323 | if (result != Z_OK) { |
324 | return false; |
325 | } |
326 | } |
327 | set_initialized(true); |
328 | return true; |
329 | } |
330 | |
331 | bool ZLibDeflateFilter::Process(uint8_t* data, intptr_t length) { |
332 | if (current_buffer_ != NULL) { |
333 | return false; |
334 | } |
335 | stream_.avail_in = length; |
336 | stream_.next_in = current_buffer_ = data; |
337 | return true; |
338 | } |
339 | |
340 | intptr_t ZLibDeflateFilter::Processed(uint8_t* buffer, |
341 | intptr_t length, |
342 | bool flush, |
343 | bool end) { |
344 | stream_.avail_out = length; |
345 | stream_.next_out = buffer; |
346 | bool error = false; |
347 | switch ( |
348 | deflate(&stream_, end ? Z_FINISH : flush ? Z_SYNC_FLUSH : Z_NO_FLUSH)) { |
349 | case Z_STREAM_END: |
350 | case Z_BUF_ERROR: |
351 | case Z_OK: { |
352 | intptr_t processed = length - stream_.avail_out; |
353 | if (processed == 0) { |
354 | break; |
355 | } |
356 | return processed; |
357 | } |
358 | |
359 | default: |
360 | case Z_STREAM_ERROR: |
361 | error = true; |
362 | } |
363 | |
364 | delete[] current_buffer_; |
365 | current_buffer_ = NULL; |
366 | // Either 0 Byte processed or error |
367 | return error ? -1 : 0; |
368 | } |
369 | |
370 | ZLibInflateFilter::~ZLibInflateFilter() { |
371 | delete[] dictionary_; |
372 | delete[] current_buffer_; |
373 | if (initialized()) { |
374 | inflateEnd(&stream_); |
375 | } |
376 | } |
377 | |
378 | bool ZLibInflateFilter::Init() { |
379 | int window_bits = |
380 | raw_ ? -window_bits_ : window_bits_ | kZLibFlagAcceptAnyHeader; |
381 | |
382 | stream_.next_in = Z_NULL; |
383 | stream_.avail_in = 0; |
384 | stream_.zalloc = Z_NULL; |
385 | stream_.zfree = Z_NULL; |
386 | stream_.opaque = Z_NULL; |
387 | int result = inflateInit2(&stream_, window_bits); |
388 | if (result != Z_OK) { |
389 | return false; |
390 | } |
391 | set_initialized(true); |
392 | return true; |
393 | } |
394 | |
395 | bool ZLibInflateFilter::Process(uint8_t* data, intptr_t length) { |
396 | if (current_buffer_ != NULL) { |
397 | return false; |
398 | } |
399 | stream_.avail_in = length; |
400 | stream_.next_in = current_buffer_ = data; |
401 | return true; |
402 | } |
403 | |
404 | intptr_t ZLibInflateFilter::Processed(uint8_t* buffer, |
405 | intptr_t length, |
406 | bool flush, |
407 | bool end) { |
408 | stream_.avail_out = length; |
409 | stream_.next_out = buffer; |
410 | bool error = false; |
411 | int v; |
412 | switch (v = inflate(&stream_, |
413 | end ? Z_FINISH : flush ? Z_SYNC_FLUSH : Z_NO_FLUSH)) { |
414 | case Z_STREAM_END: |
415 | case Z_BUF_ERROR: |
416 | case Z_OK: { |
417 | intptr_t processed = length - stream_.avail_out; |
418 | if (processed == 0) { |
419 | break; |
420 | } |
421 | return processed; |
422 | } |
423 | |
424 | case Z_NEED_DICT: |
425 | if (dictionary_ == NULL) { |
426 | error = true; |
427 | } else { |
428 | int result = |
429 | inflateSetDictionary(&stream_, dictionary_, dictionary_length_); |
430 | delete[] dictionary_; |
431 | dictionary_ = NULL; |
432 | error = result != Z_OK; |
433 | } |
434 | if (error) { |
435 | break; |
436 | } else { |
437 | return Processed(buffer, length, flush, end); |
438 | } |
439 | |
440 | default: |
441 | case Z_MEM_ERROR: |
442 | case Z_DATA_ERROR: |
443 | case Z_STREAM_ERROR: |
444 | error = true; |
445 | } |
446 | |
447 | delete[] current_buffer_; |
448 | current_buffer_ = NULL; |
449 | // Either 0 Byte processed or error |
450 | return error ? -1 : 0; |
451 | } |
452 | |
453 | } // namespace bin |
454 | } // namespace dart |
455 | |