1 /*
2 * libjingle
3 * Copyright 2007--2009, 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
36 namespace talk_base {
37
38 ///////////////////////////////////////////////////////////////////////////////
39
ToUtf8(const CFStringRef str16,std::string * str8)40 bool ToUtf8(const CFStringRef str16, std::string* str8) {
41 if ((NULL == str16) || (NULL == str8))
42 return false;
43 size_t maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str16),
44 kCFStringEncodingUTF8)
45 + 1;
46 scoped_array<char> buffer(new char[maxlen]);
47 if (!buffer.get()
48 || !CFStringGetCString(str16, buffer.get(), maxlen,
49 kCFStringEncodingUTF8))
50 return false;
51 str8->assign(buffer.get());
52 return true;
53 }
54
ToUtf16(const std::string & str8,CFStringRef * str16)55 bool ToUtf16(const std::string& str8, CFStringRef* str16) {
56 if (NULL == str16)
57 return false;
58 *str16 = CFStringCreateWithBytes(kCFAllocatorDefault,
59 reinterpret_cast<const UInt8*>(str8.data()),
60 str8.length(), kCFStringEncodingUTF8,
61 false);
62 return (NULL != *str16);
63 }
64
DecodeFourChar(UInt32 fc,std::string * out)65 void DecodeFourChar(UInt32 fc, std::string* out) {
66 std::stringstream ss;
67 ss << '\'';
68 bool printable = true;
69 for (int i = 3; i >= 0; --i) {
70 char ch = (fc >> (8 * i)) & 0xFF;
71 if (isprint(static_cast<unsigned char>(ch))) {
72 ss << ch;
73 } else {
74 printable = false;
75 break;
76 }
77 }
78 if (printable) {
79 ss << '\'';
80 } else {
81 ss.str("");
82 ss << "0x" << std::hex << fc;
83 }
84 out->append(ss.str());
85 }
86
DecodeEvent(EventRef event)87 std::string DecodeEvent(EventRef event) {
88 std::string str;
89 DecodeFourChar(::GetEventClass(event), &str);
90 str.push_back(':');
91 DecodeFourChar(::GetEventKind(event), &str);
92 return str;
93 }
94
GetGestalt(OSType ostype,int * value)95 static bool GetGestalt(OSType ostype, int* value) {
96 ASSERT(NULL != value);
97 SInt32 native_value;
98 OSStatus result = Gestalt(ostype, &native_value);
99 if (noErr == result) {
100 *value = native_value;
101 return true;
102 }
103 std::string str;
104 DecodeFourChar(ostype, &str);
105 LOG_E(LS_ERROR, OS, result) << "Gestalt(" << str << ")";
106 return false;
107 }
108
GetOSVersion(int * major,int * minor,int * bugfix)109 bool GetOSVersion(int* major, int* minor, int* bugfix) {
110 ASSERT(major && minor && bugfix);
111 if (!GetGestalt(gestaltSystemVersion, major))
112 return false;
113 if (*major < 0x1040) {
114 *bugfix = *major & 0xF;
115 *minor = (*major >> 4) & 0xF;
116 *major = (*major >> 8);
117 return true;
118 }
119 return GetGestalt(gestaltSystemVersionMajor, major)
120 && GetGestalt(gestaltSystemVersionMinor, minor)
121 && GetGestalt(gestaltSystemVersionBugFix, bugfix);
122 }
123
GetOSVersionName()124 MacOSVersionName GetOSVersionName() {
125 int major = 0, minor = 0, bugfix = 0;
126 if (!GetOSVersion(&major, &minor, &bugfix))
127 return kMacOSUnknown;
128 if (major > 10)
129 return kMacOSNewer;
130 if ((major < 10) || (minor < 3))
131 return kMacOSOlder;
132 switch (minor) {
133 case 3:
134 return kMacOSPanther;
135 case 4:
136 return kMacOSTiger;
137 case 5:
138 return kMacOSLeopard;
139 }
140 return kMacOSNewer;
141 }
142
GetQuickTimeVersion(std::string * out)143 bool GetQuickTimeVersion(std::string* out) {
144 int ver;
145 if (!GetGestalt(gestaltQuickTimeVersion, &ver))
146 return false;
147
148 std::stringstream ss;
149 ss << std::hex << ver;
150 *out = ss.str();
151 return true;
152 }
153
RunAppleScript(const std::string & script)154 bool RunAppleScript(const std::string& script) {
155 ComponentInstance component = NULL;
156 AEDesc script_desc;
157 AEDesc result_data;
158 OSStatus err;
159 OSAID script_id, result_id;
160
161 AECreateDesc(typeNull, NULL, 0, &script_desc);
162 AECreateDesc(typeNull, NULL, 0, &result_data);
163 script_id = kOSANullScript;
164 result_id = kOSANullScript;
165
166 component = OpenDefaultComponent(kOSAComponentType, typeAppleScript);
167 if (component == NULL) {
168 LOG(LS_ERROR) << "Failed opening Apple Script component";
169 return false;
170 }
171 err = AECreateDesc(typeUTF8Text, script.data(), script.size(), &script_desc);
172 if (err != noErr) {
173 CloseComponent(component);
174 LOG(LS_ERROR) << "Failed creating Apple Script description";
175 return false;
176 }
177
178 err = OSACompile(component, &script_desc, kOSAModeCanInteract, &script_id);
179 if (err != noErr) {
180 AEDisposeDesc(&script_desc);
181 if (script_id != kOSANullScript) {
182 OSADispose(component, script_id);
183 }
184 CloseComponent(component);
185 LOG(LS_ERROR) << "Error compiling Apple Script";
186 return false;
187 }
188
189 err = OSAExecute(component, script_id, kOSANullScript, kOSAModeCanInteract,
190 &result_id);
191
192 if (err == errOSAScriptError) {
193 LOG(LS_ERROR) << "Error when executing Apple Script: " << script;
194 AECreateDesc(typeNull, NULL, 0, &result_data);
195 OSAScriptError(component, kOSAErrorMessage, typeChar, &result_data);
196 int len = AEGetDescDataSize(&result_data);
197 char* data = (char*) malloc(len);
198 if (data != NULL) {
199 err = AEGetDescData(&result_data, data, len);
200 LOG(LS_ERROR) << "Script error: " << data;
201 }
202 AEDisposeDesc(&script_desc);
203 AEDisposeDesc(&result_data);
204 return false;
205 }
206 AEDisposeDesc(&script_desc);
207 if (script_id != kOSANullScript) {
208 OSADispose(component, script_id);
209 }
210 if (result_id != kOSANullScript) {
211 OSADispose(component, result_id);
212 }
213 CloseComponent(component);
214 return true;
215 }
216
217
218 ///////////////////////////////////////////////////////////////////////////////
219
220 } // namespace talk_base
221