summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authordcheng@chromium.org <dcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-05 20:32:24 +0000
committerdcheng@chromium.org <dcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-05 20:32:24 +0000
commit9d77eaa5fc16e172f4c9deee4dc484016702f8e7 (patch)
tree0823a9e4ffef80edae7fa8f704c6b4c3166af60d /ui
parent0905b01662953ed9475e699ca4fe9ca3299df1ee (diff)
downloadchromium_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.cc131
-rw-r--r--ui/base/clipboard/custom_data_helper.h40
-rw-r--r--ui/base/clipboard/custom_data_helper_unittest.cc168
-rw-r--r--ui/ui.gyp2
-rw-r--r--ui/ui_unittests.gypi1
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
diff --git a/ui/ui.gyp b/ui/ui.gyp
index 81cfb16..d165e9b 100644
--- a/ui/ui.gyp
+++ b/ui/ui.gyp
@@ -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',