blob: a1dcc04d424105d521ae97c9e5c6387a0327352c [file] [log] [blame]
henrike@webrtc.org0e118e72013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2007 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sstream>
29
30#include "talk/base/common.h"
31#include "talk/base/logging.h"
32#include "talk/base/macutils.h"
33#include "talk/base/scoped_ptr.h"
34#include "talk/base/stringutils.h"
35
36namespace talk_base {
37
38///////////////////////////////////////////////////////////////////////////////
39
40bool ToUtf8(const CFStringRef str16, std::string* str8) {
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +000041 if ((NULL == str16) || (NULL == str8)) {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000042 return false;
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +000043 }
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000044 size_t maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str16),
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +000045 kCFStringEncodingUTF8) + 1;
wu@webrtc.org5c9dd592013-10-25 21:18:33 +000046 scoped_ptr<char[]> buffer(new char[maxlen]);
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000047 if (!buffer || !CFStringGetCString(str16, buffer.get(), maxlen,
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +000048 kCFStringEncodingUTF8)) {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000049 return false;
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +000050 }
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000051 str8->assign(buffer.get());
52 return true;
53}
54
55bool ToUtf16(const std::string& str8, CFStringRef* str16) {
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +000056 if (NULL == str16) {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000057 return false;
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +000058 }
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000059 *str16 = CFStringCreateWithBytes(kCFAllocatorDefault,
60 reinterpret_cast<const UInt8*>(str8.data()),
61 str8.length(), kCFStringEncodingUTF8,
62 false);
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +000063 return NULL != *str16;
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000064}
65
66#ifdef OSX
67void DecodeFourChar(UInt32 fc, std::string* out) {
68 std::stringstream ss;
69 ss << '\'';
70 bool printable = true;
71 for (int i = 3; i >= 0; --i) {
72 char ch = (fc >> (8 * i)) & 0xFF;
73 if (isprint(static_cast<unsigned char>(ch))) {
74 ss << ch;
75 } else {
76 printable = false;
77 break;
78 }
79 }
80 if (printable) {
81 ss << '\'';
82 } else {
83 ss.str("");
84 ss << "0x" << std::hex << fc;
85 }
86 out->append(ss.str());
87}
88
89static bool GetGestalt(OSType ostype, int* value) {
90 ASSERT(NULL != value);
91 SInt32 native_value;
92 OSStatus result = Gestalt(ostype, &native_value);
93 if (noErr == result) {
94 *value = native_value;
95 return true;
96 }
97 std::string str;
98 DecodeFourChar(ostype, &str);
99 LOG_E(LS_ERROR, OS, result) << "Gestalt(" << str << ")";
100 return false;
101}
102
103bool GetOSVersion(int* major, int* minor, int* bugfix) {
104 ASSERT(major && minor && bugfix);
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +0000105 if (!GetGestalt(gestaltSystemVersion, major)) {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000106 return false;
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +0000107 }
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000108 if (*major < 0x1040) {
109 *bugfix = *major & 0xF;
110 *minor = (*major >> 4) & 0xF;
111 *major = (*major >> 8);
112 return true;
113 }
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +0000114 return GetGestalt(gestaltSystemVersionMajor, major) &&
115 GetGestalt(gestaltSystemVersionMinor, minor) &&
116 GetGestalt(gestaltSystemVersionBugFix, bugfix);
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000117}
118
119MacOSVersionName GetOSVersionName() {
120 int major = 0, minor = 0, bugfix = 0;
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +0000121 if (!GetOSVersion(&major, &minor, &bugfix)) {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000122 return kMacOSUnknown;
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +0000123 }
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000124 if (major > 10) {
125 return kMacOSNewer;
126 }
127 if ((major < 10) || (minor < 3)) {
128 return kMacOSOlder;
129 }
130 switch (minor) {
131 case 3:
132 return kMacOSPanther;
133 case 4:
134 return kMacOSTiger;
135 case 5:
136 return kMacOSLeopard;
137 case 6:
138 return kMacOSSnowLeopard;
139 case 7:
140 return kMacOSLion;
141 case 8:
142 return kMacOSMountainLion;
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +0000143 case 9:
144 return kMacOSMavericks;
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000145 }
146 return kMacOSNewer;
147}
148
149bool GetQuickTimeVersion(std::string* out) {
150 int ver;
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +0000151 if (!GetGestalt(gestaltQuickTimeVersion, &ver)) {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000152 return false;
sergeyu@chromium.org97fbd302013-12-05 00:24:06 +0000153 }
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000154
155 std::stringstream ss;
156 ss << std::hex << ver;
157 *out = ss.str();
158 return true;
159}
160
161bool RunAppleScript(const std::string& script) {
162 // TODO(thaloun): Add a .mm file that contains something like this:
163 // NSString source from script
164 // NSAppleScript* appleScript = [[NSAppleScript alloc] initWithSource:&source]
165 // if (appleScript != nil) {
166 // [appleScript executeAndReturnError:nil]
167 // [appleScript release]
168#ifndef CARBON_DEPRECATED
169 ComponentInstance component = NULL;
170 AEDesc script_desc;
171 AEDesc result_data;
172 OSStatus err;
173 OSAID script_id, result_id;
174
175 AECreateDesc(typeNull, NULL, 0, &script_desc);
176 AECreateDesc(typeNull, NULL, 0, &result_data);
177 script_id = kOSANullScript;
178 result_id = kOSANullScript;
179
180 component = OpenDefaultComponent(kOSAComponentType, typeAppleScript);
181 if (component == NULL) {
182 LOG(LS_ERROR) << "Failed opening Apple Script component";
183 return false;
184 }
185 err = AECreateDesc(typeUTF8Text, script.data(), script.size(), &script_desc);
186 if (err != noErr) {
187 CloseComponent(component);
188 LOG(LS_ERROR) << "Failed creating Apple Script description";
189 return false;
190 }
191
192 err = OSACompile(component, &script_desc, kOSAModeCanInteract, &script_id);
193 if (err != noErr) {
194 AEDisposeDesc(&script_desc);
195 if (script_id != kOSANullScript) {
196 OSADispose(component, script_id);
197 }
198 CloseComponent(component);
199 LOG(LS_ERROR) << "Error compiling Apple Script";
200 return false;
201 }
202
203 err = OSAExecute(component, script_id, kOSANullScript, kOSAModeCanInteract,
204 &result_id);
205
206 if (err == errOSAScriptError) {
207 LOG(LS_ERROR) << "Error when executing Apple Script: " << script;
208 AECreateDesc(typeNull, NULL, 0, &result_data);
209 OSAScriptError(component, kOSAErrorMessage, typeChar, &result_data);
210 int len = AEGetDescDataSize(&result_data);
211 char* data = (char*) malloc(len);
212 if (data != NULL) {
213 err = AEGetDescData(&result_data, data, len);
214 LOG(LS_ERROR) << "Script error: " << data;
215 }
216 AEDisposeDesc(&script_desc);
217 AEDisposeDesc(&result_data);
218 return false;
219 }
220 AEDisposeDesc(&script_desc);
221 if (script_id != kOSANullScript) {
222 OSADispose(component, script_id);
223 }
224 if (result_id != kOSANullScript) {
225 OSADispose(component, result_id);
226 }
227 CloseComponent(component);
228 return true;
229#else
230 // TODO(thaloun): Support applescripts with the NSAppleScript API.
231 return false;
232#endif // CARBON_DEPRECATED
233}
234#endif // OSX
235
236///////////////////////////////////////////////////////////////////////////////
237
238} // namespace talk_base