| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "chrome/browser/ui/cocoa/applescript/apple_event_util.h" |
| |
| #import <Carbon/Carbon.h> |
| #include <stddef.h> |
| |
| #include "base/check.h" |
| #include "base/notreached.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "base/values.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/pref_names.h" |
| #include "components/prefs/pref_service.h" |
| |
| namespace chrome::mac { |
| |
| namespace { |
| |
| void AppendValueToListDescriptor(NSAppleEventDescriptor* list, |
| const base::Value& value) { |
| // Note that index 0 means "append to end of list"; see the docs for |
| // -[NSAppleEventDescriptor insertDescriptor:atIndex:] and ultimately for |
| // AEPutDesc(). |
| [list insertDescriptor:ValueToAppleEventDescriptor(value) atIndex:0]; |
| } |
| |
| NSAppleEventDescriptor* RecordDescriptorForKeyValuePairs( |
| NSAppleEventDescriptor* list) { |
| // /!\ Extreme undocumented subtlety ahead /!\ |
| // |
| // AERecords have the restriction that their keys are `FourChar` codes |
| // (e.g. keyAS* values from ASRegistry.h). This does not mesh well with |
| // Cocoa, where keys in `NSDictionary` objects are full objects (though |
| // usually strings). |
| // |
| // Therefore, the AppleScript team developed a special way to wrap an |
| // NSDictionary in an AERecord. NSDictionary objects are wrapped by |
| // creating an an AERecord has a single key of keyASUserRecordFields |
| // that has a value of an AEList. That list must have alternating |
| // keys (required to be string type) and values. |
| // |
| // As Value dictionaries have string-typed keys, they are perfect for |
| // this wrapping, so wrap them in this manner too. See |
| // https://lists.apple.com/archives/cocoa-dev/2009/Jul/msg01216.html |
| // for more details. |
| NSAppleEventDescriptor* descriptor = |
| [NSAppleEventDescriptor recordDescriptor]; |
| [descriptor setDescriptor:list forKeyword:keyASUserRecordFields]; |
| return descriptor; |
| } |
| |
| } // namespace |
| |
| NSAppleEventDescriptor* ValueToAppleEventDescriptor(const base::Value& value) { |
| NSAppleEventDescriptor* descriptor = nil; |
| |
| switch (value.type()) { |
| case base::Value::Type::NONE: |
| descriptor = |
| [NSAppleEventDescriptor descriptorWithTypeCode:cMissingValue]; |
| break; |
| |
| case base::Value::Type::BOOLEAN: { |
| descriptor = |
| [NSAppleEventDescriptor descriptorWithBoolean:value.GetBool()]; |
| break; |
| } |
| |
| case base::Value::Type::INTEGER: { |
| descriptor = [NSAppleEventDescriptor descriptorWithInt32:value.GetInt()]; |
| break; |
| } |
| |
| case base::Value::Type::DOUBLE: { |
| double double_value = value.GetDouble(); |
| descriptor = [NSAppleEventDescriptor |
| descriptorWithDescriptorType:typeIEEE64BitFloatingPoint |
| bytes:&double_value |
| length:sizeof(double_value)]; |
| break; |
| } |
| |
| case base::Value::Type::STRING: { |
| descriptor = [NSAppleEventDescriptor |
| descriptorWithString:base::SysUTF8ToNSString(value.GetString())]; |
| break; |
| } |
| |
| case base::Value::Type::BINARY: |
| NOTREACHED(); |
| |
| case base::Value::Type::DICT: { |
| NSAppleEventDescriptor* keyValuePairs = |
| [NSAppleEventDescriptor listDescriptor]; |
| for (auto iter : value.GetDict()) { |
| AppendValueToListDescriptor(keyValuePairs, base::Value(iter.first)); |
| AppendValueToListDescriptor(keyValuePairs, iter.second); |
| } |
| descriptor = RecordDescriptorForKeyValuePairs(keyValuePairs); |
| break; |
| } |
| |
| case base::Value::Type::LIST: { |
| descriptor = [NSAppleEventDescriptor listDescriptor]; |
| for (const auto& item : value.GetList()) { |
| AppendValueToListDescriptor(descriptor, item); |
| } |
| break; |
| } |
| } |
| |
| return descriptor; |
| } |
| |
| bool IsJavaScriptEnabledForProfile(Profile* profile) { |
| DCHECK(profile); |
| PrefService* prefs = profile->GetPrefs(); |
| return prefs->GetBoolean(prefs::kAllowJavascriptAppleEvents); |
| } |
| |
| } // namespace chrome::mac |