// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "bin/dartutils.h" #include "bin/filter.h" #include "bin/io_buffer.h" #include "include/dart_api.h" namespace dart { namespace bin { const int kZLibFlagUseGZipHeader = 16; const int kZLibFlagAcceptAnyHeader = 32; static const int kFilterPointerNativeField = 0; static Filter* GetFilter(Dart_Handle filter_obj) { Filter* filter; Dart_Handle result = Filter::GetFilterPointerNativeField(filter_obj, &filter); if (Dart_IsError(result)) { Dart_PropagateError(result); } if (filter == NULL) { Dart_ThrowException(DartUtils::NewInternalError("Filter destroyed")); } return filter; } static void EndFilter(Dart_Handle filter_obj, Filter* filter) { Filter::SetFilterPointerNativeField(filter_obj, NULL); delete filter; } static uint8_t* copyDictionary(Dart_Handle dictionary_obj) { uint8_t* src = NULL; intptr_t size; Dart_TypedData_Type type; if (Dart_IsError(Dart_ListLength(dictionary_obj, &size))) { Dart_ThrowException(DartUtils::NewInternalError( "Failed to get the zlib dictionary length")); } uint8_t* dictionary = new uint8_t[size]; if (dictionary == NULL) { Dart_ThrowException(DartUtils::NewInternalError( "Failed to allocate buffer for the zlib dictionary")); } Dart_Handle result = Dart_TypedDataAcquireData( dictionary_obj, &type, reinterpret_cast(&src), &size); if (!Dart_IsError(result)) { memmove(dictionary, src, size); Dart_TypedDataReleaseData(dictionary_obj); } else { if (Dart_IsError(Dart_ListGetAsBytes(dictionary_obj, 0, dictionary, size))) { Dart_ThrowException(DartUtils::NewInternalError( "Failed to get the zlib dictionary")); } } return dictionary; } void FUNCTION_NAME(Filter_CreateZLibInflate)(Dart_NativeArguments args) { Dart_Handle filter_obj = Dart_GetNativeArgument(args, 0); Dart_Handle window_bits_obj = Dart_GetNativeArgument(args, 1); int64_t window_bits = DartUtils::GetIntegerValue(window_bits_obj); Dart_Handle dict_obj = Dart_GetNativeArgument(args, 2); uint8_t* dictionary = NULL; intptr_t dictionary_length = 0; if (!Dart_IsNull(dict_obj)) { dictionary = copyDictionary(dict_obj); if (dictionary != NULL) { dictionary_length = 0; Dart_ListLength(dict_obj, &dictionary_length); } } Dart_Handle raw_obj = Dart_GetNativeArgument(args, 3); bool raw; if (Dart_IsError(Dart_BooleanValue(raw_obj, &raw))) { Dart_ThrowException(DartUtils::NewInternalError( "Failed to get 'raw' parameter")); } Filter* filter = new ZLibInflateFilter(static_cast(window_bits), dictionary, dictionary_length, raw); if (!filter->Init()) { delete filter; Dart_ThrowException(DartUtils::NewInternalError( "Failed to create ZLibInflateFilter")); } Dart_Handle result = Filter::SetFilterPointerNativeField(filter_obj, filter); if (Dart_IsError(result)) { delete filter; Dart_PropagateError(result); } } void FUNCTION_NAME(Filter_CreateZLibDeflate)(Dart_NativeArguments args) { Dart_Handle filter_obj = Dart_GetNativeArgument(args, 0); Dart_Handle gzip_obj = Dart_GetNativeArgument(args, 1); bool gzip = DartUtils::GetBooleanValue(gzip_obj); Dart_Handle level_obj = Dart_GetNativeArgument(args, 2); int64_t level = DartUtils::GetInt64ValueCheckRange(level_obj, kMinInt32, kMaxInt32); Dart_Handle window_bits_obj = Dart_GetNativeArgument(args, 3); int64_t window_bits = DartUtils::GetIntegerValue(window_bits_obj); Dart_Handle mLevel_obj = Dart_GetNativeArgument(args, 4); int64_t mem_level = DartUtils::GetIntegerValue(mLevel_obj); Dart_Handle strategy_obj = Dart_GetNativeArgument(args, 5); int64_t strategy = DartUtils::GetIntegerValue(strategy_obj); Dart_Handle dict_obj = Dart_GetNativeArgument(args, 6); uint8_t* dictionary = NULL; intptr_t dictionary_length = 0; if (!Dart_IsNull(dict_obj)) { dictionary = copyDictionary(dict_obj); if (dictionary != NULL) { dictionary_length = 0; Dart_ListLength(dict_obj, &dictionary_length); } } Dart_Handle raw_obj = Dart_GetNativeArgument(args, 7); bool raw = DartUtils::GetBooleanValue(raw_obj); Filter* filter = new ZLibDeflateFilter(gzip, static_cast(level), static_cast(window_bits), static_cast(mem_level), static_cast(strategy), dictionary, dictionary_length, raw); if (!filter->Init()) { delete filter; Dart_ThrowException(DartUtils::NewInternalError( "Failed to create ZLibDeflateFilter")); } Dart_Handle result = Filter::SetFilterPointerNativeField(filter_obj, filter); if (Dart_IsError(result)) { delete filter; Dart_PropagateError(result); } } void FUNCTION_NAME(Filter_Process)(Dart_NativeArguments args) { Dart_Handle filter_obj = Dart_GetNativeArgument(args, 0); Filter* filter = GetFilter(filter_obj); Dart_Handle data_obj = Dart_GetNativeArgument(args, 1); intptr_t start = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 2)); intptr_t end = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 3)); intptr_t chunk_length = end - start; intptr_t length; Dart_TypedData_Type type; uint8_t* buffer = NULL; Dart_Handle result = Dart_TypedDataAcquireData( data_obj, &type, reinterpret_cast(&buffer), &length); if (!Dart_IsError(result)) { uint8_t* zlib_buffer = new uint8_t[chunk_length]; if (zlib_buffer == NULL) { Dart_TypedDataReleaseData(data_obj); Dart_ThrowException(DartUtils::NewInternalError( "Failed to allocate buffer for zlib")); } memmove(zlib_buffer, buffer + start, chunk_length); Dart_TypedDataReleaseData(data_obj); buffer = zlib_buffer; } else { if (Dart_IsError(Dart_ListLength(data_obj, &length))) { Dart_ThrowException(DartUtils::NewInternalError( "Failed to get list length")); } buffer = new uint8_t[chunk_length]; if (Dart_IsError(Dart_ListGetAsBytes( data_obj, start, buffer, chunk_length))) { delete[] buffer; Dart_ThrowException(DartUtils::NewInternalError( "Failed to get list bytes")); } } // Process will take ownership of buffer, if successful. if (!filter->Process(buffer, chunk_length)) { delete[] buffer; EndFilter(filter_obj, filter); Dart_ThrowException(DartUtils::NewInternalError( "Call to Process while still processing data")); } } void FUNCTION_NAME(Filter_Processed)(Dart_NativeArguments args) { Dart_Handle filter_obj = Dart_GetNativeArgument(args, 0); Filter* filter = GetFilter(filter_obj); Dart_Handle flush_obj = Dart_GetNativeArgument(args, 1); bool flush; if (Dart_IsError(Dart_BooleanValue(flush_obj, &flush))) { Dart_ThrowException(DartUtils::NewInternalError( "Failed to get 'flush' parameter")); } Dart_Handle end_obj = Dart_GetNativeArgument(args, 2); bool end; if (Dart_IsError(Dart_BooleanValue(end_obj, &end))) { Dart_ThrowException(DartUtils::NewInternalError( "Failed to get 'end' parameter")); } intptr_t read = filter->Processed(filter->processed_buffer(), filter->processed_buffer_size(), flush, end); if (read < 0) { // Error, end filter. EndFilter(filter_obj, filter); Dart_ThrowException(DartUtils::NewInternalError( "Filter error, bad data")); } else if (read == 0) { Dart_SetReturnValue(args, Dart_Null()); } else { uint8_t* io_buffer; Dart_Handle result = IOBuffer::Allocate(read, &io_buffer); memmove(io_buffer, filter->processed_buffer(), read); Dart_SetReturnValue(args, result); } } void FUNCTION_NAME(Filter_End)(Dart_NativeArguments args) { Dart_Handle filter_obj = Dart_GetNativeArgument(args, 0); Filter* filter = GetFilter(filter_obj); EndFilter(filter_obj, filter); } Dart_Handle Filter::SetFilterPointerNativeField(Dart_Handle filter, Filter* filter_pointer) { return Dart_SetNativeInstanceField( filter, kFilterPointerNativeField, reinterpret_cast(filter_pointer)); } Dart_Handle Filter::GetFilterPointerNativeField(Dart_Handle filter, Filter** filter_pointer) { return Dart_GetNativeInstanceField( filter, kFilterPointerNativeField, reinterpret_cast(filter_pointer)); } ZLibDeflateFilter::~ZLibDeflateFilter() { delete[] dictionary_; delete[] current_buffer_; if (initialized()) deflateEnd(&stream_); } bool ZLibDeflateFilter::Init() { int window_bits = window_bits_; if (raw_) { window_bits = -window_bits; } else if (gzip_) { window_bits += kZLibFlagUseGZipHeader; } stream_.next_in = Z_NULL; stream_.zalloc = Z_NULL; stream_.zfree = Z_NULL; stream_.opaque = Z_NULL; int result = deflateInit2(&stream_, level_, Z_DEFLATED, window_bits, mem_level_, strategy_); if (result != Z_OK) { return false; } if (dictionary_ != NULL && !gzip_ && !raw_) { result = deflateSetDictionary(&stream_, dictionary_, dictionary_length_); delete[] dictionary_; dictionary_ = NULL; if (result != Z_OK) { return false; } } set_initialized(true); return true; } bool ZLibDeflateFilter::Process(uint8_t* data, intptr_t length) { if (current_buffer_ != NULL) return false; stream_.avail_in = length; stream_.next_in = current_buffer_ = data; return true; } intptr_t ZLibDeflateFilter::Processed(uint8_t* buffer, intptr_t length, bool flush, bool end) { stream_.avail_out = length; stream_.next_out = buffer; bool error = false; switch (deflate(&stream_, end ? Z_FINISH : flush ? Z_SYNC_FLUSH : Z_NO_FLUSH)) { case Z_STREAM_END: case Z_BUF_ERROR: case Z_OK: { intptr_t processed = length - stream_.avail_out; if (processed == 0) { break; } return processed; } default: case Z_STREAM_ERROR: error = true; } delete[] current_buffer_; current_buffer_ = NULL; // Either 0 Byte processed or error return error ? -1 : 0; } ZLibInflateFilter::~ZLibInflateFilter() { delete[] dictionary_; delete[] current_buffer_; if (initialized()) inflateEnd(&stream_); } bool ZLibInflateFilter::Init() { int window_bits = raw_ ? -window_bits_ : window_bits_ | kZLibFlagAcceptAnyHeader; stream_.next_in = Z_NULL; stream_.avail_in = 0; stream_.zalloc = Z_NULL; stream_.zfree = Z_NULL; stream_.opaque = Z_NULL; int result = inflateInit2(&stream_, window_bits); if (result != Z_OK) { return false; } set_initialized(true); return true; } bool ZLibInflateFilter::Process(uint8_t* data, intptr_t length) { if (current_buffer_ != NULL) return false; stream_.avail_in = length; stream_.next_in = current_buffer_ = data; return true; } intptr_t ZLibInflateFilter::Processed(uint8_t* buffer, intptr_t length, bool flush, bool end) { stream_.avail_out = length; stream_.next_out = buffer; bool error = false; int v; switch (v = inflate(&stream_, end ? Z_FINISH : flush ? Z_SYNC_FLUSH : Z_NO_FLUSH)) { case Z_STREAM_END: case Z_BUF_ERROR: case Z_OK: { intptr_t processed = length - stream_.avail_out; if (processed == 0) { break; } return processed; } case Z_NEED_DICT: if (dictionary_ == NULL) { error = true; } else { int result = inflateSetDictionary(&stream_, dictionary_, dictionary_length_); delete[] dictionary_; dictionary_ = NULL; error = result != Z_OK; } if (error) { break; } else { return Processed(buffer, length, flush, end); } default: case Z_MEM_ERROR: case Z_DATA_ERROR: case Z_STREAM_ERROR: error = true; } delete[] current_buffer_; current_buffer_ = NULL; // Either 0 Byte processed or error return error ? -1 : 0; } } // namespace bin } // namespace dart