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