1 /* 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 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 } 44 size_t maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str16), 45 kCFStringEncodingUTF8) + 1; 46 scoped_ptr<char[]> buffer(new char[maxlen]); 47 if (!buffer || !CFStringGetCString(str16, buffer.get(), maxlen, 48 kCFStringEncodingUTF8)) { 49 return false; 50 } 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 } 59 *str16 = CFStringCreateWithBytes(kCFAllocatorDefault, 60 reinterpret_cast<const UInt8*>(str8.data()), 61 str8.length(), kCFStringEncodingUTF8, 62 false); 63 return NULL != *str16; 64 } 65 66 #ifdef OSX 67 void 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 89 static 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 103 bool GetOSVersion(int* major, int* minor, int* bugfix) { 104 ASSERT(major && minor && bugfix); 105 if (!GetGestalt(gestaltSystemVersion, major)) { 106 return false; 107 } 108 if (*major < 0x1040) { 109 *bugfix = *major & 0xF; 110 *minor = (*major >> 4) & 0xF; 111 *major = (*major >> 8); 112 return true; 113 } 114 return GetGestalt(gestaltSystemVersionMajor, major) && 115 GetGestalt(gestaltSystemVersionMinor, minor) && 116 GetGestalt(gestaltSystemVersionBugFix, bugfix); 117 } 118 119 MacOSVersionName GetOSVersionName() { 120 int major = 0, minor = 0, bugfix = 0; 121 if (!GetOSVersion(&major, &minor, &bugfix)) { 122 return kMacOSUnknown; 123 } 124 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; 143 case 9: 144 return kMacOSMavericks; 145 } 146 return kMacOSNewer; 147 } 148 149 bool GetQuickTimeVersion(std::string* out) { 150 int ver; 151 if (!GetGestalt(gestaltQuickTimeVersion, &ver)) { 152 return false; 153 } 154 155 std::stringstream ss; 156 ss << std::hex << ver; 157 *out = ss.str(); 158 return true; 159 } 160 161 bool 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 239