1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//
5// TODO(dcheng): For efficiency reasons, consider passing custom data around
6// as a vector instead. It allows us to append a
7// std::pair<base::string16, base::string16> and swap the deserialized values.
8
9#include "ui/base/clipboard/custom_data_helper.h"
10
11#include <utility>
12
13#include "base/pickle.h"
14
15namespace ui {
16
17namespace {
18
19class SkippablePickle : public Pickle {
20 public:
21  SkippablePickle(const void* data, size_t data_len);
22  bool SkipString16(PickleIterator* iter);
23};
24
25SkippablePickle::SkippablePickle(const void* data, size_t data_len)
26    : Pickle(reinterpret_cast<const char*>(data), data_len) {
27}
28
29bool SkippablePickle::SkipString16(PickleIterator* iter) {
30  DCHECK(iter);
31
32  int len;
33  if (!ReadLength(iter, &len))
34    return false;
35  return iter->SkipBytes(len * sizeof(base::char16));
36}
37
38}  // namespace
39
40void ReadCustomDataTypes(const void* data,
41                         size_t data_length,
42                         std::vector<base::string16>* types) {
43  SkippablePickle pickle(data, data_length);
44  PickleIterator iter(pickle);
45
46  uint64 size = 0;
47  if (!pickle.ReadUInt64(&iter, &size))
48    return;
49
50  // Keep track of the original elements in the types vector. On failure, we
51  // truncate the vector to the original size since we want to ignore corrupt
52  // custom data pickles.
53  uint64 original_size = types->size();
54
55  for (uint64 i = 0; i < size; ++i) {
56    types->push_back(base::string16());
57    if (!pickle.ReadString16(&iter, &types->back()) ||
58        !pickle.SkipString16(&iter)) {
59      types->resize(original_size);
60      return;
61    }
62  }
63}
64
65void ReadCustomDataForType(const void* data,
66                           size_t data_length,
67                           const base::string16& type,
68                           base::string16* result) {
69  SkippablePickle pickle(data, data_length);
70  PickleIterator iter(pickle);
71
72  uint64 size = 0;
73  if (!pickle.ReadUInt64(&iter, &size))
74    return;
75
76  for (uint64 i = 0; i < size; ++i) {
77    base::string16 deserialized_type;
78    if (!pickle.ReadString16(&iter, &deserialized_type))
79      return;
80    if (deserialized_type == type) {
81      ignore_result(pickle.ReadString16(&iter, result));
82      return;
83    }
84    if (!pickle.SkipString16(&iter))
85      return;
86  }
87}
88
89void ReadCustomDataIntoMap(const void* data,
90                           size_t data_length,
91                           std::map<base::string16, base::string16>* result) {
92  Pickle pickle(reinterpret_cast<const char*>(data), data_length);
93  PickleIterator iter(pickle);
94
95  uint64 size = 0;
96  if (!pickle.ReadUInt64(&iter, &size))
97    return;
98
99  for (uint64 i = 0; i < size; ++i) {
100    base::string16 type;
101    if (!pickle.ReadString16(&iter, &type)) {
102      // Data is corrupt, return an empty map.
103      result->clear();
104      return;
105    }
106    std::pair<std::map<base::string16, base::string16>::iterator, bool>
107        insert_result = result->insert(std::make_pair(type, base::string16()));
108    if (!pickle.ReadString16(&iter, &insert_result.first->second)) {
109      // Data is corrupt, return an empty map.
110      result->clear();
111      return;
112    }
113  }
114}
115
116void WriteCustomDataToPickle(
117    const std::map<base::string16, base::string16>& data,
118    Pickle* pickle) {
119  pickle->WriteUInt64(data.size());
120  for (std::map<base::string16, base::string16>::const_iterator it =
121           data.begin();
122       it != data.end();
123       ++it) {
124    pickle->WriteString16(it->first);
125    pickle->WriteString16(it->second);
126  }
127}
128
129}  // namespace ui
130