1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef SimpleArgumentCoder_h
27#define SimpleArgumentCoder_h
28
29#include "ArgumentDecoder.h"
30#include "ArgumentEncoder.h"
31#include <utility>
32#include <wtf/HashMap.h>
33#include <wtf/TypeTraits.h>
34#include <wtf/Vector.h>
35#include <wtf/text/AtomicString.h>
36#include <wtf/text/CString.h>
37#include <wtf/text/WTFString.h>
38
39namespace CoreIPC {
40
41// An argument coder works on POD types
42template<typename T> struct SimpleArgumentCoder {
43    static void encode(ArgumentEncoder* encoder, const T& t)
44    {
45        encoder->encodeBytes(reinterpret_cast<const uint8_t*>(&t), sizeof(T));
46    }
47    static bool decode(ArgumentDecoder* decoder, T& t)
48    {
49        return decoder->decodeBytes(reinterpret_cast<uint8_t*>(&t), sizeof(T));
50    }
51};
52
53template<typename T, typename U> struct ArgumentCoder<std::pair<T, U> > {
54    static void encode(ArgumentEncoder* encoder, const std::pair<T, U>& pair)
55    {
56        encoder->encode(pair.first);
57        encoder->encode(pair.second);
58    }
59
60    static bool decode(ArgumentDecoder* decoder, std::pair<T, U>& pair)
61    {
62        T first;
63        if (!decoder->decode(first))
64            return false;
65
66        U second;
67        if (!decoder->decode(second))
68            return false;
69
70        pair.first = first;
71        pair.second = second;
72        return true;
73    }
74};
75
76template<bool fixedSizeElements, typename T> struct VectorArgumentCoder;
77
78template<typename T> struct VectorArgumentCoder<false, T> {
79    static void encode(ArgumentEncoder* encoder, const Vector<T>& vector)
80    {
81        encoder->encodeUInt64(vector.size());
82        for (size_t i = 0; i < vector.size(); ++i)
83            encoder->encode(vector[i]);
84    }
85
86    static bool decode(ArgumentDecoder* decoder, Vector<T>& vector)
87    {
88        uint64_t size;
89        if (!decoder->decodeUInt64(size))
90            return false;
91
92        Vector<T> tmp;
93        for (size_t i = 0; i < size; ++i) {
94            T element;
95            if (!decoder->decode(element))
96                return false;
97
98            tmp.append(element);
99        }
100
101        tmp.shrinkToFit();
102        vector.swap(tmp);
103        return true;
104    }
105};
106
107template<typename T> struct VectorArgumentCoder<true, T> {
108    static void encode(ArgumentEncoder* encoder, const Vector<T>& vector)
109    {
110        encoder->encodeUInt64(vector.size());
111        // FIXME: If we could tell the encoder to align the buffer, we could just do an encodeBytes here.
112        for (size_t i = 0; i < vector.size(); ++i)
113            encoder->encode(vector[i]);
114    }
115
116    static bool decode(ArgumentDecoder* decoder, Vector<T>& vector)
117    {
118        uint64_t size;
119        if (!decoder->decodeUInt64(size))
120            return false;
121
122        // Since we know the total size of the elements, we can allocate the vector in
123        // one fell swoop. Before allocating we must however make sure that the decoder buffer
124        // is big enough.
125        if (!decoder->bufferIsLargeEnoughToContain<T>(size)) {
126            decoder->markInvalid();
127            return false;
128        }
129
130        Vector<T> tmp;
131        tmp.reserveCapacity(size);
132
133        for (size_t i = 0; i < size; ++i) {
134            T element;
135            if (!decoder->decode(element))
136                return false;
137
138            tmp.uncheckedAppend(element);
139        }
140
141        vector.swap(tmp);
142        return true;
143    }
144};
145
146template<typename T> struct ArgumentCoder<Vector<T> > : VectorArgumentCoder<WTF::IsArithmetic<T>::value, T> { };
147
148// Specialization for Vector<uint8_t>
149template<> struct ArgumentCoder<Vector<uint8_t> > {
150    static void encode(ArgumentEncoder* encoder, const Vector<uint8_t>& vector)
151    {
152        encoder->encodeBytes(vector.data(), vector.size());
153    }
154
155    static bool decode(ArgumentDecoder* decoder, Vector<uint8_t>& vector)
156    {
157        return decoder->decodeBytes(vector);
158    }
159};
160
161template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg> struct ArgumentCoder<HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> > {
162    typedef HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> HashMapType;
163
164    static void encode(ArgumentEncoder* encoder, const HashMapType& hashMap)
165    {
166        encoder->encodeUInt64(hashMap.size());
167        for (typename HashMapType::const_iterator it = hashMap.begin(), end = hashMap.end(); it != end; ++it)
168            encoder->encode(*it);
169    }
170
171    static bool decode(ArgumentDecoder* decoder, HashMapType& hashMap)
172    {
173        uint64_t hashMapSize;
174        if (!decoder->decode(hashMapSize))
175            return false;
176
177        HashMapType tempHashMap;
178        for (uint64_t i = 0; i < hashMapSize; ++i) {
179            KeyArg key;
180            MappedArg value;
181            if (!decoder->decode(key))
182                return false;
183            if (!decoder->decode(value))
184                return false;
185
186            if (!tempHashMap.add(key, value).second) {
187                // The hash map already has the specified key, bail.
188                decoder->markInvalid();
189                return false;
190            }
191        }
192
193        hashMap.swap(tempHashMap);
194        return true;
195    }
196};
197
198template<> struct ArgumentCoder<CString> {
199    static void encode(ArgumentEncoder* encoder, const CString& string)
200    {
201        // Special case the null string.
202        if (string.isNull()) {
203            encoder->encodeUInt32(std::numeric_limits<uint32_t>::max());
204            return;
205        }
206
207        uint32_t length = string.length();
208        encoder->encode(length);
209        encoder->encodeBytes(reinterpret_cast<const uint8_t*>(string.data()), length);
210    }
211
212    static bool decode(ArgumentDecoder* decoder, CString& result)
213    {
214        uint32_t length;
215        if (!decoder->decode(length))
216            return false;
217
218        if (length == std::numeric_limits<uint32_t>::max()) {
219            // This is the null string.
220            result = CString();
221            return true;
222        }
223
224        // Before allocating the string, make sure that the decoder buffer is big enough.
225        if (!decoder->bufferIsLargeEnoughToContain<char>(length)) {
226            decoder->markInvalid();
227            return false;
228        }
229
230        char* buffer;
231        CString string = CString::newUninitialized(length, buffer);
232        if (!decoder->decodeBytes(reinterpret_cast<uint8_t*>(buffer), length))
233            return false;
234
235        result = string;
236        return true;
237    }
238};
239
240template<> struct ArgumentCoder<String> {
241    static void encode(ArgumentEncoder* encoder, const String& string)
242    {
243        // Special case the null string.
244        if (string.isNull()) {
245            encoder->encodeUInt32(std::numeric_limits<uint32_t>::max());
246            return;
247        }
248
249        uint32_t length = string.length();
250        encoder->encode(length);
251        encoder->encodeBytes(reinterpret_cast<const uint8_t*>(string.characters()), length * sizeof(UChar));
252    }
253
254    static bool decode(ArgumentDecoder* decoder, String& result)
255    {
256        uint32_t length;
257        if (!decoder->decode(length))
258            return false;
259
260        if (length == std::numeric_limits<uint32_t>::max()) {
261            // This is the null string.
262            result = String();
263            return true;
264        }
265
266        // Before allocating the string, make sure that the decoder buffer is big enough.
267        if (!decoder->bufferIsLargeEnoughToContain<UChar>(length)) {
268            decoder->markInvalid();
269            return false;
270        }
271
272        UChar* buffer;
273        String string = String::createUninitialized(length, buffer);
274        if (!decoder->decodeBytes(reinterpret_cast<uint8_t*>(buffer), length * sizeof(UChar)))
275            return false;
276
277        result = string;
278        return true;
279    }
280};
281
282template<> struct ArgumentCoder<AtomicString> {
283    static void encode(ArgumentEncoder* encoder, const AtomicString& atomicString)
284    {
285        encoder->encode(atomicString.string());
286    }
287
288    static bool decode(ArgumentDecoder* decoder, AtomicString& atomicString)
289    {
290        String string;
291        if (!decoder->decode(string))
292            return false;
293
294        atomicString = string;
295        return true;
296    }
297};
298
299} // namespace CoreIPC
300
301#endif // SimpleArgumentCoder_h
302