1// Copyright 2014 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#include "components/policy/core/common/mac_util.h"
6
7#include <string>
8
9#include "base/mac/foundation_util.h"
10#include "base/strings/sys_string_conversions.h"
11#include "base/values.h"
12
13using base::mac::CFCast;
14
15namespace policy {
16
17namespace {
18
19// Callback function for CFDictionaryApplyFunction. |key| and |value| are an
20// entry of the CFDictionary that should be converted into an equivalent entry
21// in the DictionaryValue in |context|.
22void DictionaryEntryToValue(const void* key, const void* value, void* context) {
23  if (CFStringRef cf_key = CFCast<CFStringRef>(key)) {
24    scoped_ptr<base::Value> converted =
25        PropertyToValue(static_cast<CFPropertyListRef>(value));
26    if (converted) {
27      const std::string string = base::SysCFStringRefToUTF8(cf_key);
28      static_cast<base::DictionaryValue*>(context)->Set(
29          string, converted.release());
30    }
31  }
32}
33
34// Callback function for CFArrayApplyFunction. |value| is an entry of the
35// CFArray that should be converted into an equivalent entry in the ListValue
36// in |context|.
37void ArrayEntryToValue(const void* value, void* context) {
38  scoped_ptr<base::Value> converted =
39      PropertyToValue(static_cast<CFPropertyListRef>(value));
40  if (converted)
41    static_cast<base::ListValue *>(context)->Append(converted.release());
42}
43
44}  // namespace
45
46scoped_ptr<base::Value> PropertyToValue(CFPropertyListRef property) {
47  if (CFCast<CFNullRef>(property))
48    return scoped_ptr<base::Value>(base::Value::CreateNullValue());
49
50  if (CFBooleanRef boolean = CFCast<CFBooleanRef>(property)) {
51    return scoped_ptr<base::Value>(new base::FundamentalValue(
52        static_cast<bool>(CFBooleanGetValue(boolean))));
53  }
54
55  if (CFNumberRef number = CFCast<CFNumberRef>(property)) {
56    // CFNumberGetValue() converts values implicitly when the conversion is not
57    // lossy. Check the type before trying to convert.
58    if (CFNumberIsFloatType(number)) {
59      double double_value = 0.0;
60      if (CFNumberGetValue(number, kCFNumberDoubleType, &double_value)) {
61        return scoped_ptr<base::Value>(
62            new base::FundamentalValue(double_value));
63      }
64    } else {
65      int int_value = 0;
66      if (CFNumberGetValue(number, kCFNumberIntType, &int_value)) {
67        return scoped_ptr<base::Value>(new base::FundamentalValue(int_value));
68      }
69    }
70  }
71
72  if (CFStringRef string = CFCast<CFStringRef>(property)) {
73    return scoped_ptr<base::Value>(
74        new base::StringValue(base::SysCFStringRefToUTF8(string)));
75  }
76
77  if (CFDictionaryRef dict = CFCast<CFDictionaryRef>(property)) {
78    scoped_ptr<base::DictionaryValue> dict_value(new base::DictionaryValue());
79    CFDictionaryApplyFunction(dict, DictionaryEntryToValue, dict_value.get());
80    return dict_value.PassAs<base::Value>();
81  }
82
83  if (CFArrayRef array = CFCast<CFArrayRef>(property)) {
84    scoped_ptr<base::ListValue> list_value(new base::ListValue());
85    CFArrayApplyFunction(array,
86                         CFRangeMake(0, CFArrayGetCount(array)),
87                         ArrayEntryToValue,
88                         list_value.get());
89    return list_value.PassAs<base::Value>();
90  }
91
92  return scoped_ptr<base::Value>();
93}
94
95}  // namespace policy
96