// 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 kZlibFlagMemUsage = 8; const int kZLibFlagWindowBits = 15; const int kZLibFlagUseGZipHeader = 16; const int kZLibFlagAcceptAnyHeader = 32; static const int kFilterPointerNativeField = 0; 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; } void EndFilter(Dart_Handle filter_obj, Filter* filter) { Filter::SetFilterPointerNativeField(filter_obj, NULL); delete filter; } void FUNCTION_NAME(Filter_CreateZLibInflate)(Dart_NativeArguments args) { Dart_Handle filter_obj = Dart_GetNativeArgument(args, 0); Filter* filter = new ZLibInflateFilter(); if (filter == NULL || !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); Dart_Handle level_obj = Dart_GetNativeArgument(args, 2); bool gzip; if (Dart_IsError(Dart_BooleanValue(gzip_obj, &gzip))) { Dart_ThrowException(DartUtils::NewInternalError( "Failed to get 'gzip' parameter")); } int64_t level; if (Dart_IsError(Dart_IntegerToInt64(level_obj, &level))) { Dart_ThrowException(DartUtils::NewInternalError( "Failed to get 'level' parameter")); } Filter* filter = new ZLibDeflateFilter(gzip, level); if (filter == NULL || !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[] current_buffer_; if (initialized()) deflateEnd(&stream_); } bool ZLibDeflateFilter::Init() { stream_.zalloc = Z_NULL; stream_.zfree = Z_NULL; stream_.opaque = Z_NULL; int result = deflateInit2( &stream_, level_, Z_DEFLATED, kZLibFlagWindowBits | (gzip_ ? kZLibFlagUseGZipHeader : 0), kZlibFlagMemUsage, Z_DEFAULT_STRATEGY); if (result == Z_OK) { set_initialized(true); return true; } return false; } 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; 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) { delete[] current_buffer_; current_buffer_ = NULL; return 0; } else { // We processed data, should be called again. return processed; } } default: case Z_STREAM_ERROR: // An error occoured. delete[] current_buffer_; current_buffer_ = NULL; return -1; } } ZLibInflateFilter::~ZLibInflateFilter() { delete[] current_buffer_; if (initialized()) inflateEnd(&stream_); } bool ZLibInflateFilter::Init() { stream_.zalloc = Z_NULL; stream_.zfree = Z_NULL; stream_.opaque = Z_NULL; int result = inflateInit2(&stream_, kZLibFlagWindowBits | kZLibFlagAcceptAnyHeader); if (result == Z_OK) { set_initialized(true); return true; } return false; } 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; switch (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) { delete[] current_buffer_; current_buffer_ = NULL; return 0; } else { // We processed data, should be called again. return processed; } } default: case Z_MEM_ERROR: case Z_NEED_DICT: case Z_DATA_ERROR: case Z_STREAM_ERROR: // An error occoured. delete[] current_buffer_; current_buffer_ = NULL; return -1; } } } // namespace bin } // namespace dart