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 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 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 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 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 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 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 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 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 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