diff options
author | dcheng@chromium.org <dcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-05 20:32:24 +0000 |
---|---|---|
committer | dcheng@chromium.org <dcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-05 20:32:24 +0000 |
commit | 9d77eaa5fc16e172f4c9deee4dc484016702f8e7 (patch) | |
tree | 0823a9e4ffef80edae7fa8f704c6b4c3166af60d /ui | |
parent | 0905b01662953ed9475e699ca4fe9ca3299df1ee (diff) | |
download | chromium_src-9d77eaa5fc16e172f4c9deee4dc484016702f8e7.zip chromium_src-9d77eaa5fc16e172f4c9deee4dc484016702f8e7.tar.gz chromium_src-9d77eaa5fc16e172f4c9deee4dc484016702f8e7.tar.bz2 |
Helpers to pickle custom data for web copy/paste and drag/drop.
BUG=31037
TEST=ui_unittests --gtest_filter=CustomDataHelperTest.*
Review URL: http://codereview.chromium.org/8803005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113012 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/base/clipboard/custom_data_helper.cc | 131 | ||||
-rw-r--r-- | ui/base/clipboard/custom_data_helper.h | 40 | ||||
-rw-r--r-- | ui/base/clipboard/custom_data_helper_unittest.cc | 168 | ||||
-rw-r--r-- | ui/ui.gyp | 2 | ||||
-rw-r--r-- | ui/ui_unittests.gypi | 1 |
5 files changed, 342 insertions, 0 deletions
diff --git a/ui/base/clipboard/custom_data_helper.cc b/ui/base/clipboard/custom_data_helper.cc new file mode 100644 index 0000000..88abf0f --- /dev/null +++ b/ui/base/clipboard/custom_data_helper.cc @@ -0,0 +1,131 @@ +// 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. +// +// TODO(dcheng): For efficiency reasons, consider passing custom data around +// as a vector instead. It allows us to append a +// std::pair<string16, string16> and swap the deserialized values in. + +#include "ui/base/clipboard/custom_data_helper.h" + +#include <utility> + +#include "base/pickle.h" + +namespace ui { + +namespace { + +class SkippablePickle : public Pickle { + public: + SkippablePickle(const void* data, size_t data_len); + bool SkipString16(void** iter); +}; + +SkippablePickle::SkippablePickle(const void* data, size_t data_len) + : Pickle(reinterpret_cast<const char*>(data), data_len) { +} + +bool SkippablePickle::SkipString16(void** iter) { + DCHECK(iter); + + int len; + if (!ReadLength(iter, &len)) + return false; + if (!IteratorHasRoomFor(*iter, len * sizeof(char16))) + return false; + + UpdateIter(iter, len * sizeof(char16)); + return true; +} + +} // namespace + +void ReadCustomDataTypes(const void* data, + size_t data_length, + std::vector<string16>* types) { + SkippablePickle pickle(data, data_length); + void* iter = NULL; + + size_t size = 0; + if (!pickle.ReadSize(&iter, &size)) + return; + + // Keep track of the original elements in the types vector. On failure, we + // truncate the vector to the original size since we want to ignore corrupt + // custom data pickles. + size_t original_size = types->size(); + + for (size_t i = 0; i < size; ++i) { + types->push_back(string16()); + if (!pickle.ReadString16(&iter, &types->back()) || + !pickle.SkipString16(&iter)) { + types->resize(original_size); + return; + } + } +} + +void ReadCustomDataForType(const void* data, + size_t data_length, + const string16& type, + string16* result) { + SkippablePickle pickle(data, data_length); + void* iter = NULL; + + size_t size = 0; + if (!pickle.ReadSize(&iter, &size)) + return; + + for (size_t i = 0; i < size; ++i) { + string16 deserialized_type; + if (!pickle.ReadString16(&iter, &deserialized_type)) + return; + if (deserialized_type == type) { + pickle.ReadString16(&iter, result); + return; + } + if (!pickle.SkipString16(&iter)) + return; + } +} + +void ReadCustomDataIntoMap(const void* data, + size_t data_length, + std::map<string16, string16>* result) { + Pickle pickle(reinterpret_cast<const char*>(data), data_length); + void* iter = NULL; + + size_t size = 0; + if (!pickle.ReadSize(&iter, &size)) + return; + + for (size_t i = 0; i < size; ++i) { + string16 type; + if (!pickle.ReadString16(&iter, &type)) { + // Data is corrupt, return an empty map. + result->clear(); + return; + } + std::pair<std::map<string16, string16>::iterator, bool> insert_result = + result->insert(std::make_pair(type, string16())); + if (!pickle.ReadString16(&iter, &insert_result.first->second)) { + // Data is corrupt, return an empty map. + result->clear(); + return; + } + } +} + +void WriteCustomDataToPickle(const std::map<string16, string16>& data, + Pickle* pickle) { + pickle->WriteSize(data.size()); + for (std::map<string16, string16>::const_iterator it = data.begin(); + it != data.end(); + ++it) { + pickle->WriteString16(it->first); + pickle->WriteString16(it->second); + } +} + +} // namespace ui diff --git a/ui/base/clipboard/custom_data_helper.h b/ui/base/clipboard/custom_data_helper.h new file mode 100644 index 0000000..3294f51 --- /dev/null +++ b/ui/base/clipboard/custom_data_helper.h @@ -0,0 +1,40 @@ +// 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. +// +// Due to restrictions of most operating systems, we don't directly map each +// type of custom data to a native data transfer type. Instead, we serialize +// each key-value pair into the pickle as a pair of string objects, and then +// write the binary data in the pickle to the native data transfer object. + +#ifndef UI_BASE_CLIPBOARD_CUSTOM_DATA_HELPER_H_ +#define UI_BASE_CLIPBOARD_CUSTOM_DATA_HELPER_H_ +#pragma once + +#include <map> +#include <vector> + +#include "base/string16.h" +#include "ui/base/ui_export.h" + +class Pickle; + +namespace ui { + +UI_EXPORT void ReadCustomDataTypes(const void* data, + size_t data_length, + std::vector<string16>* types); +UI_EXPORT void ReadCustomDataForType(const void* data, + size_t data_length, + const string16& type, + string16* result); +UI_EXPORT void ReadCustomDataIntoMap(const void* data, + size_t data_length, + std::map<string16, string16>* result); + +UI_EXPORT void WriteCustomDataToPickle(const std::map<string16, string16>& data, + Pickle* pickle); + +} // namespace ui + +#endif // UI_BASE_CLIPBOARD_CLIPBOARD_H_ diff --git a/ui/base/clipboard/custom_data_helper_unittest.cc b/ui/base/clipboard/custom_data_helper_unittest.cc new file mode 100644 index 0000000..05df47e --- /dev/null +++ b/ui/base/clipboard/custom_data_helper_unittest.cc @@ -0,0 +1,168 @@ +// 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. + +#include "ui/base/clipboard/custom_data_helper.h" + +#include <utility> + +#include "base/pickle.h" +#include "base/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ui { + +namespace { + +void PrepareEmptyTestData(Pickle* pickle) { + std::map<string16, string16> data; + WriteCustomDataToPickle(data, pickle); +} + +void PrepareTestData(Pickle* pickle) { + std::map<string16, string16> data; + data.insert(std::make_pair(ASCIIToUTF16("abc"), ASCIIToUTF16(""))); + data.insert(std::make_pair(ASCIIToUTF16("de"), ASCIIToUTF16("1"))); + data.insert(std::make_pair(ASCIIToUTF16("f"), ASCIIToUTF16("23"))); + WriteCustomDataToPickle(data, pickle); +} + +TEST(CustomDataHelperTest, EmptyReadTypes) { + Pickle pickle; + PrepareEmptyTestData(&pickle); + + std::vector<string16> types; + ReadCustomDataTypes(pickle.data(), pickle.size(), &types); + EXPECT_EQ(0u, types.size()); +} + +TEST(CustomDataHelperTest, EmptyReadSingleType) { + Pickle pickle; + PrepareEmptyTestData(&pickle); + + string16 result; + ReadCustomDataForType(pickle.data(), + pickle.size(), + ASCIIToUTF16("f"), + &result); + EXPECT_EQ(ASCIIToUTF16(""), result); +} + +TEST(CustomDataHelperTest, EmptyReadMap) { + Pickle pickle; + PrepareEmptyTestData(&pickle); + + std::map<string16, string16> result; + ReadCustomDataIntoMap(pickle.data(), pickle.size(), &result); + EXPECT_EQ(0u, result.size()); +} + +TEST(CustomDataHelperTest, ReadTypes) { + Pickle pickle; + PrepareTestData(&pickle); + + std::vector<string16> types; + ReadCustomDataTypes(pickle.data(), pickle.size(), &types); + + std::vector<string16> expected; + expected.push_back(ASCIIToUTF16("abc")); + expected.push_back(ASCIIToUTF16("de")); + expected.push_back(ASCIIToUTF16("f")); + EXPECT_EQ(expected, types); +} + +TEST(CustomDataHelperTest, ReadSingleType) { + Pickle pickle; + PrepareTestData(&pickle); + + string16 result; + ReadCustomDataForType(pickle.data(), + pickle.size(), + ASCIIToUTF16("abc"), + &result); + EXPECT_EQ(ASCIIToUTF16(""), result); + + ReadCustomDataForType(pickle.data(), + pickle.size(), + ASCIIToUTF16("de"), + &result); + EXPECT_EQ(ASCIIToUTF16("1"), result); + + ReadCustomDataForType(pickle.data(), + pickle.size(), + ASCIIToUTF16("f"), + &result); + EXPECT_EQ(ASCIIToUTF16("23"), result); +} + +TEST(CustomDataHelperTest, ReadMap) { + Pickle pickle; + PrepareTestData(&pickle); + + std::map<string16, string16> result; + ReadCustomDataIntoMap(pickle.data(), pickle.size(), &result); + + std::map<string16, string16> expected; + expected.insert(std::make_pair(ASCIIToUTF16("abc"), ASCIIToUTF16(""))); + expected.insert(std::make_pair(ASCIIToUTF16("de"), ASCIIToUTF16("1"))); + expected.insert(std::make_pair(ASCIIToUTF16("f"), ASCIIToUTF16("23"))); + EXPECT_EQ(expected, result); +} + +TEST(CustomDataHelperTest, BadReadTypes) { + // ReadCustomDataTypes makes the additional guarantee that the contents of the + // result vector will not change if the input is malformed. + std::vector<string16> expected; + expected.push_back(ASCIIToUTF16("abc")); + expected.push_back(ASCIIToUTF16("de")); + expected.push_back(ASCIIToUTF16("f")); + + Pickle malformed; + malformed.WriteSize(1000); + malformed.WriteString16(ASCIIToUTF16("hello")); + malformed.WriteString16(ASCIIToUTF16("world")); + std::vector<string16> actual(expected); + ReadCustomDataTypes(malformed.data(), malformed.size(), &actual); + EXPECT_EQ(expected, actual); + + Pickle malformed2; + malformed2.WriteSize(1); + malformed2.WriteString16(ASCIIToUTF16("hello")); + std::vector<string16> actual2(expected); + ReadCustomDataTypes(malformed2.data(), malformed2.size(), &actual2); + EXPECT_EQ(expected, actual2); +} + +TEST(CustomDataHelperTest, BadPickle) { + string16 result_data; + std::map<string16, string16> result_map; + + Pickle malformed; + malformed.WriteSize(1000); + malformed.WriteString16(ASCIIToUTF16("hello")); + malformed.WriteString16(ASCIIToUTF16("world")); + + ReadCustomDataForType(malformed.data(), + malformed.size(), + ASCIIToUTF16("f"), + &result_data); + ReadCustomDataIntoMap(malformed.data(), malformed.size(), &result_map); + EXPECT_EQ(0u, result_data.size()); + EXPECT_EQ(0u, result_map.size()); + + Pickle malformed2; + malformed2.WriteSize(1); + malformed2.WriteString16(ASCIIToUTF16("hello")); + + ReadCustomDataForType(malformed2.data(), + malformed2.size(), + ASCIIToUTF16("f"), + &result_data); + ReadCustomDataIntoMap(malformed2.data(), malformed2.size(), &result_map); + EXPECT_EQ(0u, result_data.size()); + EXPECT_EQ(0u, result_map.size()); +} + +} // namespace + +} // namespace ui @@ -77,6 +77,8 @@ 'base/clipboard/clipboard_util_win.cc', 'base/clipboard/clipboard_util_win.h', 'base/clipboard/clipboard_win.cc', + 'base/clipboard/custom_data_helper.cc', + 'base/clipboard/custom_data_helper.h', 'base/clipboard/scoped_clipboard_writer.cc', 'base/clipboard/scoped_clipboard_writer.h', 'base/cocoa/base_view.h', diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi index cab407c..7b1ec9f 100644 --- a/ui/ui_unittests.gypi +++ b/ui/ui_unittests.gypi @@ -49,6 +49,7 @@ 'base/animation/multi_animation_unittest.cc', 'base/animation/slide_animation_unittest.cc', 'base/clipboard/clipboard_unittest.cc', + 'base/clipboard/custom_data_helper_unittest.cc', 'base/cocoa/base_view_unittest.mm', 'base/gtk/gtk_expanded_container_unittest.cc', 'base/gtk/gtk_im_context_util_unittest.cc', |