1/*
2 * Copyright (C) 2014 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#include "config.h"
27#include "KeyedDecoder.h"
28
29#include <wtf/cf/TypeCasts.h>
30#include <wtf/text/WTFString.h>
31
32namespace WebKit {
33
34KeyedDecoder::KeyedDecoder(const uint8_t* data, size_t size)
35{
36    auto cfData = adoptCF(CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, data, size, kCFAllocatorNull));
37
38    if (auto rootDictionary = adoptCF(dynamic_cf_cast<CFDictionaryRef>(CFPropertyListCreateWithData(kCFAllocatorDefault, cfData.get(), kCFPropertyListImmutable, nullptr, nullptr))))
39        m_rootDictionary = WTF::move(rootDictionary);
40    else
41        m_rootDictionary = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, nullptr, nullptr, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
42    m_dictionaryStack.append(m_rootDictionary.get());
43}
44
45KeyedDecoder::~KeyedDecoder()
46{
47    ASSERT(m_dictionaryStack.size() == 1);
48    ASSERT(m_dictionaryStack.last() == m_rootDictionary);
49    ASSERT(m_arrayStack.isEmpty());
50    ASSERT(m_arrayIndexStack.isEmpty());
51}
52
53bool KeyedDecoder::decodeBytes(const String& key, const uint8_t*& bytes, size_t& size)
54{
55    auto data = dynamic_cf_cast<CFDataRef>(CFDictionaryGetValue(m_dictionaryStack.last(), key.createCFString().get()));
56    if (!data)
57        return false;
58
59    bytes = CFDataGetBytePtr(data);
60    size = CFDataGetLength(data);
61    return true;
62}
63
64bool KeyedDecoder::decodeBool(const String& key, bool& result)
65{
66    auto boolean = dynamic_cf_cast<CFBooleanRef>(CFDictionaryGetValue(m_dictionaryStack.last(), key.createCFString().get()));
67    if (!boolean)
68        return false;
69
70    result = CFBooleanGetValue(boolean);
71    return true;
72}
73
74bool KeyedDecoder::decodeUInt32(const String& key, uint32_t& result)
75{
76    return decodeInt32(key, reinterpret_cast<int32_t&>(result));
77}
78
79bool KeyedDecoder::decodeInt32(const String& key, int32_t& result)
80{
81    auto number = dynamic_cf_cast<CFNumberRef>(CFDictionaryGetValue(m_dictionaryStack.last(), key.createCFString().get()));
82    if (!number)
83        return false;
84
85    return CFNumberGetValue(number, kCFNumberSInt32Type, &result);
86}
87
88bool KeyedDecoder::decodeInt64(const String& key, int64_t& result)
89{
90    auto number = dynamic_cf_cast<CFNumberRef>(CFDictionaryGetValue(m_dictionaryStack.last(), key.createCFString().get()));
91    if (!number)
92        return false;
93
94    return CFNumberGetValue(number, kCFNumberSInt64Type, &result);
95}
96
97bool KeyedDecoder::decodeFloat(const String& key, float& result)
98{
99    auto number = dynamic_cf_cast<CFNumberRef>(CFDictionaryGetValue(m_dictionaryStack.last(), key.createCFString().get()));
100    if (!number)
101        return false;
102
103    return CFNumberGetValue(number, kCFNumberFloatType, &result);
104}
105
106bool KeyedDecoder::decodeDouble(const String& key, double& result)
107{
108    auto number = dynamic_cf_cast<CFNumberRef>(CFDictionaryGetValue(m_dictionaryStack.last(), key.createCFString().get()));
109    if (!number)
110        return false;
111
112    return CFNumberGetValue(number, kCFNumberDoubleType, &result);
113}
114
115bool KeyedDecoder::decodeString(const String& key, String& result)
116{
117    auto string = dynamic_cf_cast<CFStringRef>(CFDictionaryGetValue(m_dictionaryStack.last(), key.createCFString().get()));
118    if (!string)
119        return false;
120
121    result = string;
122    return true;
123}
124
125bool KeyedDecoder::beginObject(const String& key)
126{
127    auto dictionary = dynamic_cf_cast<CFDictionaryRef>(CFDictionaryGetValue(m_dictionaryStack.last(), key.createCFString().get()));
128    if (!dictionary)
129        return false;
130
131    m_dictionaryStack.append(dictionary);
132    return true;
133}
134
135void KeyedDecoder::endObject()
136{
137    m_dictionaryStack.removeLast();
138}
139
140bool KeyedDecoder::beginArray(const String& key)
141{
142    auto array = dynamic_cf_cast<CFArrayRef>(CFDictionaryGetValue(m_dictionaryStack.last(), key.createCFString().get()));
143    if (!array)
144        return false;
145
146    for (CFIndex i = 0; i < CFArrayGetCount(array); ++i) {
147        CFTypeRef object = CFArrayGetValueAtIndex(array, i);
148        if (CFGetTypeID(object) != CFDictionaryGetTypeID())
149            return false;
150    }
151
152    m_arrayStack.append(array);
153    m_arrayIndexStack.append(0);
154    return true;
155}
156
157bool KeyedDecoder::beginArrayElement()
158{
159    if (m_arrayIndexStack.last() >= CFArrayGetCount(m_arrayStack.last()))
160        return false;
161
162    auto dictionary = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(m_arrayStack.last(), m_arrayIndexStack.last()++));
163    m_dictionaryStack.append(dictionary);
164    return true;
165}
166
167void KeyedDecoder::endArrayElement()
168{
169    m_dictionaryStack.removeLast();
170}
171
172void KeyedDecoder::endArray()
173{
174    m_arrayStack.removeLast();
175    m_arrayIndexStack.removeLast();
176}
177
178} // namespace WebKit
179