diff options
-rw-r--r-- | ppapi/api/trusted/ppb_char_set_trusted.idl | 95 | ||||
-rw-r--r-- | ppapi/c/trusted/ppb_char_set_trusted.h | 124 | ||||
-rw-r--r-- | ppapi/ppapi_shared.gypi | 4 | ||||
-rw-r--r-- | ppapi/proxy/interface_list.cc | 1 | ||||
-rw-r--r-- | ppapi/shared_impl/ppb_char_set_shared.cc | 154 | ||||
-rw-r--r-- | ppapi/shared_impl/ppb_char_set_shared.h | 33 | ||||
-rw-r--r-- | ppapi/shared_impl/private/ppb_char_set_shared.cc | 239 | ||||
-rw-r--r-- | ppapi/shared_impl/private/ppb_char_set_shared.h | 46 | ||||
-rw-r--r-- | ppapi/tests/test_char_set.cc | 192 | ||||
-rw-r--r-- | ppapi/tests/test_char_set.h | 4 | ||||
-rw-r--r-- | ppapi/thunk/interfaces_ppb_private.h | 2 | ||||
-rw-r--r-- | ppapi/thunk/ppb_char_set_thunk.cc | 73 | ||||
-rw-r--r-- | webkit/plugins/ppapi/plugin_module.cc | 1 |
13 files changed, 754 insertions, 214 deletions
diff --git a/ppapi/api/trusted/ppb_char_set_trusted.idl b/ppapi/api/trusted/ppb_char_set_trusted.idl new file mode 100644 index 0000000..61bd8d5 --- /dev/null +++ b/ppapi/api/trusted/ppb_char_set_trusted.idl @@ -0,0 +1,95 @@ +/* Copyright (c) 2012 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + * This file defines the <code>PPB_CharSet_Trusted</code> interface. + */ + +label Chrome { + M18 = 1.0 +}; + +[assert_size(4)] enum PP_CharSet_Trusted_ConversionError { + /** + * Causes the entire conversion to fail if an error is encountered. The + * conversion function will return NULL. + */ + PP_CHARSET_TRUSTED_CONVERSIONERROR_FAIL, + + /** + * Silently skips over errors. Unrepresentable characters and input encoding + * errors will be removed from the output. + */ + PP_CHARSET_TRUSTED_CONVERSIONERROR_SKIP, + + /** + * Replaces the error or unrepresentable character with a substitution + * character. When converting to a Unicode character set (UTF-8 or UTF-16) it + * will use the unicode "substitution character" U+FFFD. When converting to + * another character set, the character will be charset-specific. For many + * languages this will be the representation of the '?' character. + */ + PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE +}; + +/** + * The <code>PPB_CharSet_Trusted</code> interface provides functions for + * converting between character sets. + * + * This inteface is provided for trusted plugins only since in Native Client it + * would require an expensive out-of-process IPC call for each conversion, + * which makes performance unacceptable. Native Client plugins should include + * ICU or some other library if they need this feature. + */ +interface PPB_CharSet_Trusted { + /** + * Converts the UTF-16 string pointed to by |*utf16| to an 8-bit string in + * the specified code page. |utf16_len| is measured in UTF-16 units, not + * bytes. This value may not be NULL. + * + * The given output buffer will be filled up to output_length bytes with the + * result. output_length will be updated with the number of bytes required + * for the given string. The output buffer may be null to just retrieve the + * required buffer length. + * + * This function will return PP_FALSE if there was an error converting the + * string and you requested PP_CHARSET_CONVERSIONERROR_FAIL, or the output + * character set was unknown. Otherwise, it will return PP_TRUE. + */ + PP_Bool UTF16ToCharSet([in, size_as=utf16_len] uint16_t[] utf16, + [in] uint32_t utf16_len, + [in] str_t output_char_set, + [in] PP_CharSet_Trusted_ConversionError on_error, + [out] str_t output_buffer, + [inout] uint32_t output_length); + + /** + * Same as UTF16ToCharSet except converts in the other direction. The input + * is in the given charset, and the |input_len| is the number of bytes in + * the |input| string. + * + * Note that the output_utf16_length is measured in UTF-16 characters. + * + * Since UTF16 can represent every Unicode character, the only time the + * replacement character will be used is if the encoding in the input string + * is incorrect. + */ + PP_Bool CharSetToUTF16([in] str_t input, + [in] uint32_t input_len, + [in] str_t input_char_set, + [in] PP_CharSet_Trusted_ConversionError on_error, + [out] uint16_t output_buffer, + [inout] uint32_t output_utf16_length); + + /** + * Returns a string var representing the current multi-byte character set of + * the current system. + * + * WARNING: You really shouldn't be using this function unless you're dealing + * with legacy data. You should be using UTF-8 or UTF-16 and you don't have + * to worry about the character sets. + */ + PP_Var GetDefaultCharSet([in] PP_Instance instance); +}; diff --git a/ppapi/c/trusted/ppb_char_set_trusted.h b/ppapi/c/trusted/ppb_char_set_trusted.h new file mode 100644 index 0000000..8fecb42 --- /dev/null +++ b/ppapi/c/trusted/ppb_char_set_trusted.h @@ -0,0 +1,124 @@ +/* Copyright (c) 2012 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* From trusted/ppb_char_set_trusted.idl modified Wed Feb 8 16:34:25 2012. */ + +#ifndef PPAPI_C_TRUSTED_PPB_CHAR_SET_TRUSTED_H_ +#define PPAPI_C_TRUSTED_PPB_CHAR_SET_TRUSTED_H_ + +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_macros.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/c/pp_var.h" + +#define PPB_CHARSET_TRUSTED_INTERFACE_1_0 "PPB_CharSet_Trusted;1.0" +#define PPB_CHARSET_TRUSTED_INTERFACE PPB_CHARSET_TRUSTED_INTERFACE_1_0 + +/** + * @file + * + * This file defines the <code>PPB_CharSet_Trusted</code> interface. + */ + + +/** + * @addtogroup Enums + * @{ + */ +typedef enum { + /** + * Causes the entire conversion to fail if an error is encountered. The + * conversion function will return NULL. + */ + PP_CHARSET_TRUSTED_CONVERSIONERROR_FAIL, + /** + * Silently skips over errors. Unrepresentable characters and input encoding + * errors will be removed from the output. + */ + PP_CHARSET_TRUSTED_CONVERSIONERROR_SKIP, + /** + * Replaces the error or unrepresentable character with a substitution + * character. When converting to a Unicode character set (UTF-8 or UTF-16) it + * will use the unicode "substitution character" U+FFFD. When converting to + * another character set, the character will be charset-specific. For many + * languages this will be the representation of the '?' character. + */ + PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE +} PP_CharSet_Trusted_ConversionError; +PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_CharSet_Trusted_ConversionError, 4); +/** + * @} + */ + +/** + * @addtogroup Interfaces + * @{ + */ +/** + * The <code>PPB_CharSet_Trusted</code> interface provides functions for + * converting between character sets. + * + * This inteface is provided for trusted plugins only since in Native Client it + * would require an expensive out-of-process IPC call for each conversion, + * which makes performance unacceptable. Native Client plugins should include + * ICU or some other library if they need this feature. + */ +struct PPB_CharSet_Trusted_1_0 { + /** + * Converts the UTF-16 string pointed to by |*utf16| to an 8-bit string in + * the specified code page. |utf16_len| is measured in UTF-16 units, not + * bytes. This value may not be NULL. + * + * The given output buffer will be filled up to output_length bytes with the + * result. output_length will be updated with the number of bytes required + * for the given string. The output buffer may be null to just retrieve the + * required buffer length. + * + * This function will return PP_FALSE if there was an error converting the + * string and you requested PP_CHARSET_CONVERSIONERROR_FAIL, or the output + * character set was unknown. Otherwise, it will return PP_TRUE. + */ + PP_Bool (*UTF16ToCharSet)(const uint16_t utf16[], + uint32_t utf16_len, + const char* output_char_set, + PP_CharSet_Trusted_ConversionError on_error, + char* output_buffer, + uint32_t* output_length); + /** + * Same as UTF16ToCharSet except converts in the other direction. The input + * is in the given charset, and the |input_len| is the number of bytes in + * the |input| string. + * + * Note that the output_utf16_length is measured in UTF-16 characters. + * + * Since UTF16 can represent every Unicode character, the only time the + * replacement character will be used is if the encoding in the input string + * is incorrect. + */ + PP_Bool (*CharSetToUTF16)(const char* input, + uint32_t input_len, + const char* input_char_set, + PP_CharSet_Trusted_ConversionError on_error, + uint16_t* output_buffer, + uint32_t* output_utf16_length); + /** + * Returns a string var representing the current multi-byte character set of + * the current system. + * + * WARNING: You really shouldn't be using this function unless you're dealing + * with legacy data. You should be using UTF-8 or UTF-16 and you don't have + * to worry about the character sets. + */ + struct PP_Var (*GetDefaultCharSet)(PP_Instance instance); +}; + +typedef struct PPB_CharSet_Trusted_1_0 PPB_CharSet_Trusted; +/** + * @} + */ + +#endif /* PPAPI_C_TRUSTED_PPB_CHAR_SET_TRUSTED_H_ */ + diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi index 9047e54..b7e82c1 100644 --- a/ppapi/ppapi_shared.gypi +++ b/ppapi/ppapi_shared.gypi @@ -72,8 +72,6 @@ 'shared_impl/ppb_audio_input_shared.h', 'shared_impl/ppb_audio_shared.cc', 'shared_impl/ppb_audio_shared.h', - 'shared_impl/ppb_char_set_shared.cc', - 'shared_impl/ppb_char_set_shared.h', 'shared_impl/ppb_crypto_shared.cc', 'shared_impl/ppb_device_ref_shared.cc', 'shared_impl/ppb_device_ref_shared.h', @@ -128,6 +126,8 @@ 'shared_impl/private/net_address_private_impl.cc', 'shared_impl/private/net_address_private_impl.h', + 'shared_impl/private/ppb_char_set_shared.cc', + 'shared_impl/private/ppb_char_set_shared.h', 'shared_impl/private/ppb_font_shared.cc', 'shared_impl/private/ppb_font_shared.h', diff --git a/ppapi/proxy/interface_list.cc b/ppapi/proxy/interface_list.cc index f33d17e..c37da44 100644 --- a/ppapi/proxy/interface_list.cc +++ b/ppapi/proxy/interface_list.cc @@ -59,6 +59,7 @@ #include "ppapi/c/private/ppb_tcp_socket_private.h" #include "ppapi/c/private/ppb_udp_socket_private.h" #include "ppapi/c/trusted/ppb_broker_trusted.h" +#include "ppapi/c/trusted/ppb_char_set_trusted.h" #include "ppapi/c/trusted/ppb_file_io_trusted.h" #include "ppapi/c/trusted/ppb_url_loader_trusted.h" #include "ppapi/proxy/interface_proxy.h" diff --git a/ppapi/shared_impl/ppb_char_set_shared.cc b/ppapi/shared_impl/ppb_char_set_shared.cc deleted file mode 100644 index e8cadab..0000000 --- a/ppapi/shared_impl/ppb_char_set_shared.cc +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ppapi/shared_impl/ppb_char_set_shared.h" - -#include "base/i18n/icu_string_conversions.h" -#include "ppapi/c/dev/ppb_memory_dev.h" -#include "ppapi/thunk/thunk.h" -#include "unicode/ucnv.h" -#include "unicode/ucnv_cb.h" -#include "unicode/ucnv_err.h" -#include "unicode/ustring.h" - -namespace ppapi { - -namespace { - -// Converts the given PP error handling behavior to the version in base, -// placing the result in |*result| and returning true on success. Returns false -// if the enum is invalid. -bool PPToBaseConversionError(PP_CharSet_ConversionError on_error, - base::OnStringConversionError::Type* result) { - switch (on_error) { - case PP_CHARSET_CONVERSIONERROR_FAIL: - *result = base::OnStringConversionError::FAIL; - return true; - case PP_CHARSET_CONVERSIONERROR_SKIP: - *result = base::OnStringConversionError::SKIP; - return true; - case PP_CHARSET_CONVERSIONERROR_SUBSTITUTE: - *result = base::OnStringConversionError::SUBSTITUTE; - return true; - default: - return false; - } -} - -} // namespace - -// static -// The "substitution" behavior of this function does not match the -// implementation in base, so we partially duplicate the code from -// icu_string_conversions.cc with the correct error handling setup required -// by the PPAPI interface. -char* PPB_CharSet_Shared::UTF16ToCharSet( - const uint16_t* utf16, - uint32_t utf16_len, - const char* output_char_set, - PP_CharSet_ConversionError on_error, - uint32_t* output_length) { - if (!utf16 || !output_char_set || !output_length) - return NULL; - - *output_length = 0; - - UErrorCode status = U_ZERO_ERROR; - UConverter* converter = ucnv_open(output_char_set, &status); - if (!U_SUCCESS(status)) - return NULL; - - int encoded_max_length = UCNV_GET_MAX_BYTES_FOR_STRING(utf16_len, - ucnv_getMaxCharSize(converter)); - - // Setup our error handler. - switch (on_error) { - case PP_CHARSET_CONVERSIONERROR_FAIL: - ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_STOP, 0, - NULL, NULL, &status); - break; - case PP_CHARSET_CONVERSIONERROR_SKIP: - ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SKIP, 0, - NULL, NULL, &status); - break; - case PP_CHARSET_CONVERSIONERROR_SUBSTITUTE: { - // ICU sets the substitution char for some character sets (like latin1) - // to be the ASCII "substitution character" (26). We want to use '?' - // instead for backwards-compat with Windows behavior. - char subst_chars[32]; - int8_t subst_chars_len = 32; - ucnv_getSubstChars(converter, subst_chars, &subst_chars_len, &status); - if (subst_chars_len == 1 && subst_chars[0] == 26) { - // Override to the question mark character if possible. When using - // setSubstString, the input is a Unicode character. The function will - // try to convert it to the destination character set and fail if that - // can not be converted to the destination character set. - // - // We just ignore any failure. If the dest char set has no - // representation for '?', then we'll just stick to the ICU default - // substitution character. - UErrorCode subst_status = U_ZERO_ERROR; - UChar question_mark = '?'; - ucnv_setSubstString(converter, &question_mark, 1, &subst_status); - } - - ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SUBSTITUTE, 0, - NULL, NULL, &status); - break; - } - default: - return NULL; - } - - // ucnv_fromUChars returns size not including terminating null. - char* encoded = static_cast<char*>( - thunk::GetPPB_Memory_Dev_0_1_Thunk()->MemAlloc(encoded_max_length + 1)); - int actual_size = ucnv_fromUChars(converter, encoded, - encoded_max_length, reinterpret_cast<const UChar*>(utf16), utf16_len, - &status); - ucnv_close(converter); - if (!U_SUCCESS(status)) { - thunk::GetPPB_Memory_Dev_0_1_Thunk()->MemFree(encoded); - return NULL; - } - encoded[actual_size] = 0; - *output_length = actual_size; - return encoded; -} - -// static -uint16_t* PPB_CharSet_Shared::CharSetToUTF16( - const char* input, - uint32_t input_len, - const char* input_char_set, - PP_CharSet_ConversionError on_error, - uint32_t* output_length) { - if (!input || !input_char_set || !output_length) - return NULL; - - *output_length = 0; - - base::OnStringConversionError::Type base_on_error; - if (!PPToBaseConversionError(on_error, &base_on_error)) - return NULL; // Invalid enum value. - - // We can convert this call to the implementation in base to avoid code - // duplication, although this does introduce an extra copy of the data. - string16 output; - if (!base::CodepageToUTF16(std::string(input, input_len), input_char_set, - base_on_error, &output)) - return NULL; - - uint16_t* ret_buf = static_cast<uint16_t*>( - thunk::GetPPB_Memory_Dev_0_1_Thunk()->MemAlloc( - (output.size() + 1) * sizeof(uint16_t))); - if (!ret_buf) - return NULL; - - *output_length = static_cast<uint32_t>(output.size()); - memcpy(ret_buf, output.c_str(), (output.size() + 1) * sizeof(uint16_t)); - return ret_buf; -} - -} // namespace ppapi diff --git a/ppapi/shared_impl/ppb_char_set_shared.h b/ppapi/shared_impl/ppb_char_set_shared.h deleted file mode 100644 index 4243267..0000000 --- a/ppapi/shared_impl/ppb_char_set_shared.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PPAPI_SHARED_IMPL_PPB_CHAR_SET_SHARED_H_ -#define PPAPI_SHARED_IMPL_PPB_CHAR_SET_SHARED_H_ - -#include "base/basictypes.h" -#include "ppapi/c/dev/ppb_char_set_dev.h" -#include "ppapi/shared_impl/ppapi_shared_export.h" - -namespace ppapi { - -// Contains the implementation of character set conversion that is shared -// between the proxy and the renderer. -class PPAPI_SHARED_EXPORT PPB_CharSet_Shared { - public: - static char* UTF16ToCharSet(const uint16_t* utf16, - uint32_t utf16_len, - const char* output_char_set, - PP_CharSet_ConversionError on_error, - uint32_t* output_length); - - static uint16_t* CharSetToUTF16(const char* input, - uint32_t input_len, - const char* input_char_set, - PP_CharSet_ConversionError on_error, - uint32_t* output_length); -}; - -} // namespace ppapi - -#endif // PPAPI_SHARED_IMPL_PPB_CHAR_SET_SHARED_H_ diff --git a/ppapi/shared_impl/private/ppb_char_set_shared.cc b/ppapi/shared_impl/private/ppb_char_set_shared.cc new file mode 100644 index 0000000..8424b00 --- /dev/null +++ b/ppapi/shared_impl/private/ppb_char_set_shared.cc @@ -0,0 +1,239 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/shared_impl/private/ppb_char_set_shared.h" + +#include <algorithm> + +#include "base/i18n/icu_string_conversions.h" +#include "ppapi/c/dev/ppb_memory_dev.h" +#include "ppapi/thunk/thunk.h" +#include "unicode/ucnv.h" +#include "unicode/ucnv_cb.h" +#include "unicode/ucnv_err.h" +#include "unicode/ustring.h" + +namespace ppapi { + +namespace { + +PP_CharSet_Trusted_ConversionError DeprecatedToConversionError( + PP_CharSet_ConversionError on_error) { + switch (on_error) { + case PP_CHARSET_CONVERSIONERROR_SKIP: + return PP_CHARSET_TRUSTED_CONVERSIONERROR_SKIP; + case PP_CHARSET_CONVERSIONERROR_SUBSTITUTE: + return PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE; + case PP_CHARSET_CONVERSIONERROR_FAIL: + default: + return PP_CHARSET_TRUSTED_CONVERSIONERROR_FAIL; + } +} + +// Converts the given PP error handling behavior to the version in base, +// placing the result in |*result| and returning true on success. Returns false +// if the enum is invalid. +bool PPToBaseConversionError(PP_CharSet_Trusted_ConversionError on_error, + base::OnStringConversionError::Type* result) { + switch (on_error) { + case PP_CHARSET_TRUSTED_CONVERSIONERROR_FAIL: + *result = base::OnStringConversionError::FAIL; + return true; + case PP_CHARSET_TRUSTED_CONVERSIONERROR_SKIP: + *result = base::OnStringConversionError::SKIP; + return true; + case PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE: + *result = base::OnStringConversionError::SUBSTITUTE; + return true; + default: + return false; + } +} + +} // namespace + +// static +// The "substitution" behavior of this function does not match the +// implementation in base, so we partially duplicate the code from +// icu_string_conversions.cc with the correct error handling setup required +// by the PPAPI interface. +char* PPB_CharSet_Shared::UTF16ToCharSetDeprecated( + const uint16_t* utf16, + uint32_t utf16_len, + const char* output_char_set, + PP_CharSet_ConversionError deprecated_on_error, + uint32_t* output_length) { + *output_length = 0; + PP_CharSet_Trusted_ConversionError on_error = DeprecatedToConversionError( + deprecated_on_error); + + // Compute required length. + uint32_t required_length = 0; + UTF16ToCharSet(utf16, utf16_len, output_char_set, on_error, NULL, + &required_length); + + // Our output is null terminated, so need one more byte. + char* ret_buf = static_cast<char*>( + thunk::GetPPB_Memory_Dev_0_1_Thunk()->MemAlloc(required_length + 1)); + + // Do the conversion into the buffer. + PP_Bool result = UTF16ToCharSet(utf16, utf16_len, output_char_set, on_error, + ret_buf, &required_length); + if (result == PP_FALSE) { + thunk::GetPPB_Memory_Dev_0_1_Thunk()->MemFree(ret_buf); + return NULL; + } + ret_buf[required_length] = 0; // Null terminate. + *output_length = required_length; + return ret_buf; +} + +// static +PP_Bool PPB_CharSet_Shared::UTF16ToCharSet( + const uint16_t utf16[], + uint32_t utf16_len, + const char* output_char_set, + PP_CharSet_Trusted_ConversionError on_error, + char* output_buffer, + uint32_t* output_length) { + if (!utf16 || !output_char_set || !output_length) { + *output_length = 0; + return PP_FALSE; + } + + UErrorCode status = U_ZERO_ERROR; + UConverter* converter = ucnv_open(output_char_set, &status); + if (!U_SUCCESS(status)) { + *output_length = 0; + return PP_FALSE; + } + + // Setup our error handler. + switch (on_error) { + case PP_CHARSET_CONVERSIONERROR_FAIL: + ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_STOP, 0, + NULL, NULL, &status); + break; + case PP_CHARSET_CONVERSIONERROR_SKIP: + ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SKIP, 0, + NULL, NULL, &status); + break; + case PP_CHARSET_CONVERSIONERROR_SUBSTITUTE: { + // ICU sets the substitution char for some character sets (like latin1) + // to be the ASCII "substitution character" (26). We want to use '?' + // instead for backwards-compat with Windows behavior. + char subst_chars[32]; + int8_t subst_chars_len = 32; + ucnv_getSubstChars(converter, subst_chars, &subst_chars_len, &status); + if (subst_chars_len == 1 && subst_chars[0] == 26) { + // Override to the question mark character if possible. When using + // setSubstString, the input is a Unicode character. The function will + // try to convert it to the destination character set and fail if that + // can not be converted to the destination character set. + // + // We just ignore any failure. If the dest char set has no + // representation for '?', then we'll just stick to the ICU default + // substitution character. + UErrorCode subst_status = U_ZERO_ERROR; + UChar question_mark = '?'; + ucnv_setSubstString(converter, &question_mark, 1, &subst_status); + } + + ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SUBSTITUTE, 0, + NULL, NULL, &status); + break; + } + default: + *output_length = 0; + ucnv_close(converter); + return PP_FALSE; + } + + // ucnv_fromUChars returns required size not including terminating null. + *output_length = static_cast<uint32_t>(ucnv_fromUChars( + converter, output_buffer, output_buffer ? *output_length : 0, + reinterpret_cast<const UChar*>(utf16), utf16_len, &status)); + + ucnv_close(converter); + if (status == U_BUFFER_OVERFLOW_ERROR) { + // Don't treat this as a fatal error since we need to return the string + // size. + return PP_TRUE; + } else if (!U_SUCCESS(status)) { + *output_length = 0; + return PP_FALSE; + } + return PP_TRUE; +} + +// static +uint16_t* PPB_CharSet_Shared::CharSetToUTF16Deprecated( + const char* input, + uint32_t input_len, + const char* input_char_set, + PP_CharSet_ConversionError deprecated_on_error, + uint32_t* output_length) { + *output_length = 0; + PP_CharSet_Trusted_ConversionError on_error = DeprecatedToConversionError( + deprecated_on_error); + + // Compute required length. + uint32_t required_length = 0; + CharSetToUTF16(input, input_len, input_char_set, on_error, NULL, + &required_length); + + // Our output is null terminated, so need one more byte. + uint16_t* ret_buf = static_cast<uint16_t*>( + thunk::GetPPB_Memory_Dev_0_1_Thunk()->MemAlloc( + (required_length + 1) * sizeof(uint16_t))); + + // Do the conversion into the buffer. + PP_Bool result = CharSetToUTF16(input, input_len, input_char_set, on_error, + ret_buf, &required_length); + if (result == PP_FALSE) { + thunk::GetPPB_Memory_Dev_0_1_Thunk()->MemFree(ret_buf); + return NULL; + } + ret_buf[required_length] = 0; // Null terminate. + *output_length = required_length; + return ret_buf; +} + +PP_Bool PPB_CharSet_Shared::CharSetToUTF16( + const char* input, + uint32_t input_len, + const char* input_char_set, + PP_CharSet_Trusted_ConversionError on_error, + uint16_t* output_buffer, + uint32_t* output_utf16_length) { + if (!input || !input_char_set || !output_utf16_length) { + *output_utf16_length = 0; + return PP_FALSE; + } + + base::OnStringConversionError::Type base_on_error; + if (!PPToBaseConversionError(on_error, &base_on_error)) { + *output_utf16_length = 0; + return PP_FALSE; // Invalid enum value. + } + + // We can convert this call to the implementation in base to avoid code + // duplication, although this does introduce an extra copy of the data. + string16 output; + if (!base::CodepageToUTF16(std::string(input, input_len), input_char_set, + base_on_error, &output)) { + *output_utf16_length = 0; + return PP_FALSE; + } + + if (output_buffer) { + memcpy(output_buffer, output.c_str(), + std::min(*output_utf16_length, static_cast<uint32_t>(output.size())) + * sizeof(uint16_t)); + } + *output_utf16_length = static_cast<uint32_t>(output.size()); + return PP_TRUE; +} + +} // namespace ppapi diff --git a/ppapi/shared_impl/private/ppb_char_set_shared.h b/ppapi/shared_impl/private/ppb_char_set_shared.h new file mode 100644 index 0000000..96c3ba2 --- /dev/null +++ b/ppapi/shared_impl/private/ppb_char_set_shared.h @@ -0,0 +1,46 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_SHARED_IMPL_PPB_CHAR_SET_SHARED_H_ +#define PPAPI_SHARED_IMPL_PPB_CHAR_SET_SHARED_H_ + +#include "base/basictypes.h" +#include "ppapi/c/dev/ppb_char_set_dev.h" +#include "ppapi/c/trusted/ppb_char_set_trusted.h" +#include "ppapi/shared_impl/ppapi_shared_export.h" + +namespace ppapi { + +// Contains the implementation of character set conversion that is shared +// between the proxy and the renderer. +class PPAPI_SHARED_EXPORT PPB_CharSet_Shared { + public: + static char* UTF16ToCharSetDeprecated(const uint16_t* utf16, + uint32_t utf16_len, + const char* output_char_set, + PP_CharSet_ConversionError on_error, + uint32_t* output_length); + static PP_Bool UTF16ToCharSet(const uint16_t utf16[], + uint32_t utf16_len, + const char* output_char_set, + PP_CharSet_Trusted_ConversionError on_error, + char* output_buffer, + uint32_t* output_length); + + static uint16_t* CharSetToUTF16Deprecated(const char* input, + uint32_t input_len, + const char* input_char_set, + PP_CharSet_ConversionError on_error, + uint32_t* output_length); + static PP_Bool CharSetToUTF16(const char* input, + uint32_t input_len, + const char* input_char_set, + PP_CharSet_Trusted_ConversionError on_error, + uint16_t* output_buffer, + uint32_t* output_utf16_length); +}; + +} // namespace ppapi + +#endif // PPAPI_SHARED_IMPL_PPB_CHAR_SET_SHARED_H_ diff --git a/ppapi/tests/test_char_set.cc b/ppapi/tests/test_char_set.cc index b1bbe54..dfff9ed 100644 --- a/ppapi/tests/test_char_set.cc +++ b/ppapi/tests/test_char_set.cc @@ -1,10 +1,11 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ppapi/tests/test_char_set.h" #include "ppapi/c/dev/ppb_char_set_dev.h" +#include "ppapi/c/trusted/ppb_char_set_trusted.h" #include "ppapi/cpp/dev/memory_dev.h" #include "ppapi/cpp/module.h" #include "ppapi/tests/testing_instance.h" @@ -19,16 +20,21 @@ TestCharSet::TestCharSet(TestingInstance* instance) bool TestCharSet::Init() { char_set_interface_ = static_cast<const PPB_CharSet_Dev*>( pp::Module::Get()->GetBrowserInterface(PPB_CHAR_SET_DEV_INTERFACE)); - return !!char_set_interface_; + char_set_trusted_interface_ = static_cast<const PPB_CharSet_Trusted*>( + pp::Module::Get()->GetBrowserInterface(PPB_CHARSET_TRUSTED_INTERFACE)); + return char_set_interface_ && char_set_trusted_interface_; } void TestCharSet::RunTests(const std::string& filter) { + RUN_TEST(UTF16ToCharSetDeprecated, filter); RUN_TEST(UTF16ToCharSet, filter); + RUN_TEST(CharSetToUTF16Deprecated, filter); RUN_TEST(CharSetToUTF16, filter); RUN_TEST(GetDefaultCharSet, filter); } -std::string TestCharSet::TestUTF16ToCharSet() { +// TODO(brettw) remove this when the old interface is removed. +std::string TestCharSet::TestUTF16ToCharSetDeprecated() { // Empty string. std::vector<uint16_t> utf16; utf16.push_back(0); @@ -102,7 +108,117 @@ std::string TestCharSet::TestUTF16ToCharSet() { PASS(); } -std::string TestCharSet::TestCharSetToUTF16() { +std::string TestCharSet::TestUTF16ToCharSet() { + // Empty string. + std::vector<uint16_t> utf16; + utf16.push_back(0); + std::string output_buffer; + uint32_t utf8result_len = static_cast<uint32_t>(output_buffer.size()); + PP_Bool result = char_set_trusted_interface_->UTF16ToCharSet( + &utf16[0], 0, "latin1", PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE, + &output_buffer[0], &utf8result_len); + ASSERT_TRUE(result == PP_TRUE); + ASSERT_TRUE(utf8result_len == 0); + + // No output buffer returns length of string. + utf16 = UTF8ToUTF16("hello"); + utf8result_len = 0; + result = char_set_trusted_interface_->UTF16ToCharSet( + &utf16[0], static_cast<uint32_t>(utf16.size()), "latin1", + PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE, NULL, &utf8result_len); + ASSERT_TRUE(result == PP_TRUE); + ASSERT_TRUE(utf8result_len == 5); + + // Giving too small of a buffer just fills in that many items and gives us + // the desired size. + output_buffer.resize(100); + utf8result_len = 2; + output_buffer[utf8result_len] = '$'; // Barrier character. + result = char_set_trusted_interface_->UTF16ToCharSet( + &utf16[0], static_cast<uint32_t>(utf16.size()), "latin1", + PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE, + &output_buffer[0], &utf8result_len); + ASSERT_TRUE(result == PP_TRUE); + ASSERT_TRUE(utf8result_len == 5); + ASSERT_TRUE(output_buffer[0] == 'h' && output_buffer[1] == 'e' && + output_buffer[2] == '$'); + + // Try round-tripping some English & Chinese from UTF-8 through UTF-16 + std::string utf8source("Hello, world. \xe4\xbd\xa0\xe5\xa5\xbd"); + utf16 = UTF8ToUTF16(utf8source); + output_buffer.resize(100); + utf8result_len = static_cast<uint32_t>(output_buffer.size()); + result = char_set_trusted_interface_->UTF16ToCharSet( + &utf16[0], static_cast<uint32_t>(utf16.size()), + "Utf-8", PP_CHARSET_TRUSTED_CONVERSIONERROR_FAIL, + &output_buffer[0], &utf8result_len); + ASSERT_TRUE(result == PP_TRUE); + output_buffer.resize(utf8result_len); + ASSERT_TRUE(utf8source == output_buffer); + + // Test an un-encodable character with various modes. + utf16 = UTF8ToUTF16("h\xe4\xbd\xa0i"); + + // Fail mode, size should get 0'ed on failure. + output_buffer.resize(100); + utf8result_len = static_cast<uint32_t>(output_buffer.size()); + result = char_set_trusted_interface_->UTF16ToCharSet( + &utf16[0], static_cast<uint32_t>(utf16.size()), + "latin1", PP_CHARSET_TRUSTED_CONVERSIONERROR_FAIL, + &output_buffer[0], &utf8result_len); + ASSERT_TRUE(result == PP_FALSE); + ASSERT_TRUE(utf8result_len == 0); + + // Skip mode. + output_buffer.resize(100); + utf8result_len = static_cast<uint32_t>(output_buffer.size()); + result = char_set_trusted_interface_->UTF16ToCharSet( + &utf16[0], static_cast<uint32_t>(utf16.size()), + "latin1", PP_CHARSET_TRUSTED_CONVERSIONERROR_SKIP, + &output_buffer[0], &utf8result_len); + ASSERT_TRUE(result == PP_TRUE); + ASSERT_TRUE(utf8result_len == 2); + ASSERT_TRUE(output_buffer[0] == 'h' && output_buffer[1] == 'i'); + + // Substitute mode. + output_buffer.resize(100); + utf8result_len = static_cast<uint32_t>(output_buffer.size()); + result = char_set_trusted_interface_->UTF16ToCharSet( + &utf16[0], static_cast<uint32_t>(utf16.size()), + "latin1", PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE, + &output_buffer[0], &utf8result_len); + ASSERT_TRUE(utf8result_len == 3); + output_buffer.resize(utf8result_len); + ASSERT_TRUE(output_buffer == "h?i"); + + // Try some invalid input encoding. + output_buffer.resize(100); + utf8result_len = static_cast<uint32_t>(output_buffer.size()); + utf16.clear(); + utf16.push_back(0xD800); // High surrogate. + utf16.push_back('A'); // Not a low surrogate. + result = char_set_trusted_interface_->UTF16ToCharSet( + &utf16[0], static_cast<uint32_t>(utf16.size()), + "latin1", PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE, + &output_buffer[0], &utf8result_len); + ASSERT_TRUE(utf8result_len == 2); + ASSERT_TRUE(output_buffer[0] == '?' && output_buffer[1] == 'A'); + + // Invalid encoding name. + output_buffer.resize(100); + utf8result_len = static_cast<uint32_t>(output_buffer.size()); + result = char_set_trusted_interface_->UTF16ToCharSet( + &utf16[0], static_cast<uint32_t>(utf16.size()), + "poopiepants", PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE, + &output_buffer[0], &utf8result_len); + ASSERT_TRUE(result == PP_FALSE); + ASSERT_TRUE(utf8result_len == 0); + + PASS(); +} + +// TODO(brettw) remove this when the old interface is removed. +std::string TestCharSet::TestCharSetToUTF16Deprecated() { pp::Memory_Dev memory; // Empty string. @@ -166,6 +282,74 @@ std::string TestCharSet::TestCharSetToUTF16() { PASS(); } +std::string TestCharSet::TestCharSetToUTF16() { + std::vector<uint16_t> output_buffer; + output_buffer.resize(100); + + // Empty string. + output_buffer.resize(100); + uint32_t utf16result_len = static_cast<uint32_t>(output_buffer.size()); + PP_Bool result = char_set_trusted_interface_->CharSetToUTF16( + "", 0, "latin1", PP_CHARSET_TRUSTED_CONVERSIONERROR_FAIL, + &output_buffer[0], &utf16result_len); + ASSERT_TRUE(result); + ASSERT_TRUE(utf16result_len == 0); + ASSERT_TRUE(output_buffer[0] == 0); + + // Basic Latin1. + output_buffer.resize(100); + utf16result_len = static_cast<uint32_t>(output_buffer.size()); + char latin1[] = "H\xef"; + result = char_set_trusted_interface_->CharSetToUTF16( + latin1, 2, "latin1", PP_CHARSET_TRUSTED_CONVERSIONERROR_FAIL, + &output_buffer[0], &utf16result_len); + ASSERT_TRUE(result); + ASSERT_TRUE(utf16result_len == 2); + ASSERT_TRUE(output_buffer[0] == 'H' && output_buffer[1] == 0xef); + + // Invalid input encoding with FAIL. + output_buffer.resize(100); + utf16result_len = static_cast<uint32_t>(output_buffer.size()); + char badutf8[] = "A\xe4Z"; + result = char_set_trusted_interface_->CharSetToUTF16( + badutf8, 3, "utf8", PP_CHARSET_TRUSTED_CONVERSIONERROR_FAIL, + &output_buffer[0], &utf16result_len); + ASSERT_TRUE(!result); + ASSERT_TRUE(utf16result_len == 0); + + // Invalid input with SKIP. + output_buffer.resize(100); + utf16result_len = static_cast<uint32_t>(output_buffer.size()); + result = char_set_trusted_interface_->CharSetToUTF16( + badutf8, 3, "utf8", PP_CHARSET_TRUSTED_CONVERSIONERROR_SKIP, + &output_buffer[0], &utf16result_len); + ASSERT_TRUE(result); + ASSERT_TRUE(utf16result_len == 2); + ASSERT_TRUE(output_buffer[0] == 'A' && output_buffer[1] == 'Z'); + + // Invalid input with SUBSTITUTE. + output_buffer.resize(100); + utf16result_len = static_cast<uint32_t>(output_buffer.size()); + result = char_set_trusted_interface_->CharSetToUTF16( + badutf8, 3, "utf8", PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE, + &output_buffer[0], &utf16result_len); + ASSERT_TRUE(result); + ASSERT_TRUE(utf16result_len == 3); + ASSERT_TRUE(output_buffer[0] == 'A' && output_buffer[1] == 0xFFFD && + output_buffer[2] == 'Z'); + + // Invalid encoding name. + output_buffer.resize(100); + utf16result_len = static_cast<uint32_t>(output_buffer.size()); + result = char_set_trusted_interface_->CharSetToUTF16( + badutf8, 3, "poopiepants", PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE, + &output_buffer[0], &utf16result_len); + ASSERT_TRUE(!result); + ASSERT_TRUE(utf16result_len == 0); + + PASS(); +} + std::string TestCharSet::TestGetDefaultCharSet() { // Test invalid instance. pp::Var result(pp::Var::PassRef(), char_set_interface_->GetDefaultCharSet(0)); diff --git a/ppapi/tests/test_char_set.h b/ppapi/tests/test_char_set.h index f278bef..ad2c5f1 100644 --- a/ppapi/tests/test_char_set.h +++ b/ppapi/tests/test_char_set.h @@ -9,6 +9,7 @@ #include <vector> #include "ppapi/c/dev/ppb_char_set_dev.h" +#include "ppapi/c/trusted/ppb_char_set_trusted.h" #include "ppapi/tests/test_case.h" class TestCharSet : public TestCase { @@ -21,7 +22,9 @@ class TestCharSet : public TestCase { virtual void RunTests(const std::string& filter); private: + std::string TestUTF16ToCharSetDeprecated(); std::string TestUTF16ToCharSet(); + std::string TestCharSetToUTF16Deprecated(); std::string TestCharSetToUTF16(); std::string TestGetDefaultCharSet(); @@ -30,6 +33,7 @@ class TestCharSet : public TestCase { std::vector<uint16_t> UTF8ToUTF16(const std::string& utf8); const PPB_CharSet_Dev* char_set_interface_; + const PPB_CharSet_Trusted* char_set_trusted_interface_; }; #endif // PPAPI_TESTS_TEST_CHAR_SET_H_ diff --git a/ppapi/thunk/interfaces_ppb_private.h b/ppapi/thunk/interfaces_ppb_private.h index 35a5704..db888b1 100644 --- a/ppapi/thunk/interfaces_ppb_private.h +++ b/ppapi/thunk/interfaces_ppb_private.h @@ -13,6 +13,8 @@ PROXIED_API(PPB_UDPSocket_Private) PROXIED_IFACE(PPB_Broker, PPB_BROKER_TRUSTED_INTERFACE_0_2, PPB_BrokerTrusted_0_2) +PROXIED_IFACE(PPB_Instance, PPB_CHARSET_TRUSTED_INTERFACE_1_0, + PPB_CharSet_Trusted_1_0) PROXIED_IFACE(PPB_FileRef, PPB_FILEREFPRIVATE_INTERFACE_0_1, PPB_FileRefPrivate_0_1) // This uses the FileIO API which is declared in the public stable file. diff --git a/ppapi/thunk/ppb_char_set_thunk.cc b/ppapi/thunk/ppb_char_set_thunk.cc index c5cb1de..a663c55 100644 --- a/ppapi/thunk/ppb_char_set_thunk.cc +++ b/ppapi/thunk/ppb_char_set_thunk.cc @@ -3,7 +3,7 @@ // found in the LICENSE file. #include "ppapi/c/pp_var.h" -#include "ppapi/shared_impl/ppb_char_set_shared.h" +#include "ppapi/shared_impl/private/ppb_char_set_shared.h" #include "ppapi/thunk/thunk.h" #include "ppapi/thunk/enter.h" @@ -12,11 +12,27 @@ namespace thunk { namespace { -char* UTF16ToCharSet(PP_Instance instance, - const uint16_t* utf16, uint32_t utf16_len, - const char* output_char_set, - PP_CharSet_ConversionError on_error, - uint32_t* output_length) { +char* UTF16ToCharSetDeprecated(PP_Instance instance, + const uint16_t* utf16, uint32_t utf16_len, + const char* output_char_set, + PP_CharSet_ConversionError on_error, + uint32_t* output_length) { + // We validate the instance just to make sure we can make changes in the + // future and assume people pass proper instances. + EnterInstance enter(instance); + if (enter.failed()) + return NULL; + + return PPB_CharSet_Shared::UTF16ToCharSetDeprecated( + utf16, utf16_len, output_char_set, on_error, output_length); +} + +PP_Bool UTF16ToCharSet(const uint16_t utf16[], + uint32_t utf16_len, + const char* output_char_set, + PP_CharSet_Trusted_ConversionError on_error, + char* output_buffer, + uint32_t* output_length) { // This interface is a bit odd because it contains a function // (GetDefaultCharSet) that must be called on the instance object and // proxied, but the rest of the functions are implemented in the plugin @@ -27,30 +43,35 @@ char* UTF16ToCharSet(PP_Instance instance, // shared_impl. That would be more consistent, and we may want to do that if // this file is autogenerated in the future. For now, however, it's less code // to just call the shared_impl code directly here. + return PPB_CharSet_Shared::UTF16ToCharSet( + utf16, utf16_len, output_char_set, on_error, + output_buffer, output_length); +} +uint16_t* CharSetToUTF16Deprecated(PP_Instance instance, + const char* input, uint32_t input_len, + const char* input_char_set, + PP_CharSet_ConversionError on_error, + uint32_t* output_length) { // We validate the instance just to make sure we can make changes in the // future and assume people pass proper instances. EnterInstance enter(instance); if (enter.failed()) return NULL; - return PPB_CharSet_Shared::UTF16ToCharSet(utf16, utf16_len, output_char_set, - on_error, output_length); + return PPB_CharSet_Shared::CharSetToUTF16Deprecated( + input, input_len, input_char_set, on_error, output_length); } -uint16_t* CharSetToUTF16(PP_Instance instance, - const char* input, uint32_t input_len, - const char* input_char_set, - PP_CharSet_ConversionError on_error, - uint32_t* output_length) { - // We validate the instance just to make sure we can make changes in the - // future and assume people pass proper instances. - EnterInstance enter(instance); - if (enter.failed()) - return NULL; - - return PPB_CharSet_Shared::CharSetToUTF16(input, input_len, input_char_set, - on_error, output_length); +PP_Bool CharSetToUTF16(const char* input, + uint32_t input_len, + const char* input_char_set, + PP_CharSet_Trusted_ConversionError on_error, + uint16_t* output_buffer, + uint32_t* output_utf16_length) { + return PPB_CharSet_Shared::CharSetToUTF16( + input, input_len, input_char_set, on_error, + output_buffer, output_utf16_length); } PP_Var GetDefaultCharSet(PP_Instance instance) { @@ -61,6 +82,12 @@ PP_Var GetDefaultCharSet(PP_Instance instance) { } const PPB_CharSet_Dev g_ppb_char_set_thunk = { + &UTF16ToCharSetDeprecated, + &CharSetToUTF16Deprecated, + &GetDefaultCharSet +}; + +const PPB_CharSet_Trusted_1_0 g_ppb_char_set_trusted_thunk = { &UTF16ToCharSet, &CharSetToUTF16, &GetDefaultCharSet @@ -72,5 +99,9 @@ const PPB_CharSet_Dev_0_4* GetPPB_CharSet_Dev_0_4_Thunk() { return &g_ppb_char_set_thunk; } +const PPB_CharSet_Trusted_1_0* GetPPB_CharSet_Trusted_1_0_Thunk() { + return &g_ppb_char_set_trusted_thunk; +} + } // namespace thunk } // namespace ppapi diff --git a/webkit/plugins/ppapi/plugin_module.cc b/webkit/plugins/ppapi/plugin_module.cc index 57a3645..93d8161 100644 --- a/webkit/plugins/ppapi/plugin_module.cc +++ b/webkit/plugins/ppapi/plugin_module.cc @@ -83,6 +83,7 @@ #include "ppapi/c/trusted/ppb_audio_trusted.h" #include "ppapi/c/trusted/ppb_broker_trusted.h" #include "ppapi/c/trusted/ppb_buffer_trusted.h" +#include "ppapi/c/trusted/ppb_char_set_trusted.h" #include "ppapi/c/trusted/ppb_file_chooser_trusted.h" #include "ppapi/c/trusted/ppb_file_io_trusted.h" #include "ppapi/c/trusted/ppb_graphics_3d_trusted.h" |