blob: c73b0fa6f9d86ac904a6adc3143566e66d42f763 [file] [log] [blame]
/*
* libjingle
* Copyright 2007 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sstream>
#include "talk/base/common.h"
#include "talk/base/logging.h"
#include "talk/base/macutils.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/stringutils.h"
namespace talk_base {
///////////////////////////////////////////////////////////////////////////////
bool ToUtf8(const CFStringRef str16, std::string* str8) {
if ((NULL == str16) || (NULL == str8))
return false;
size_t maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str16),
kCFStringEncodingUTF8)
+ 1;
scoped_array<char> buffer(new char[maxlen]);
if (!buffer || !CFStringGetCString(str16, buffer.get(), maxlen,
kCFStringEncodingUTF8))
return false;
str8->assign(buffer.get());
return true;
}
bool ToUtf16(const std::string& str8, CFStringRef* str16) {
if (NULL == str16)
return false;
*str16 = CFStringCreateWithBytes(kCFAllocatorDefault,
reinterpret_cast<const UInt8*>(str8.data()),
str8.length(), kCFStringEncodingUTF8,
false);
return (NULL != *str16);
}
#ifdef OSX
void DecodeFourChar(UInt32 fc, std::string* out) {
std::stringstream ss;
ss << '\'';
bool printable = true;
for (int i = 3; i >= 0; --i) {
char ch = (fc >> (8 * i)) & 0xFF;
if (isprint(static_cast<unsigned char>(ch))) {
ss << ch;
} else {
printable = false;
break;
}
}
if (printable) {
ss << '\'';
} else {
ss.str("");
ss << "0x" << std::hex << fc;
}
out->append(ss.str());
}
static bool GetGestalt(OSType ostype, int* value) {
ASSERT(NULL != value);
SInt32 native_value;
OSStatus result = Gestalt(ostype, &native_value);
if (noErr == result) {
*value = native_value;
return true;
}
std::string str;
DecodeFourChar(ostype, &str);
LOG_E(LS_ERROR, OS, result) << "Gestalt(" << str << ")";
return false;
}
bool GetOSVersion(int* major, int* minor, int* bugfix) {
ASSERT(major && minor && bugfix);
if (!GetGestalt(gestaltSystemVersion, major))
return false;
if (*major < 0x1040) {
*bugfix = *major & 0xF;
*minor = (*major >> 4) & 0xF;
*major = (*major >> 8);
return true;
}
return GetGestalt(gestaltSystemVersionMajor, major)
&& GetGestalt(gestaltSystemVersionMinor, minor)
&& GetGestalt(gestaltSystemVersionBugFix, bugfix);
}
MacOSVersionName GetOSVersionName() {
int major = 0, minor = 0, bugfix = 0;
if (!GetOSVersion(&major, &minor, &bugfix))
return kMacOSUnknown;
if (major > 10) {
return kMacOSNewer;
}
if ((major < 10) || (minor < 3)) {
return kMacOSOlder;
}
switch (minor) {
case 3:
return kMacOSPanther;
case 4:
return kMacOSTiger;
case 5:
return kMacOSLeopard;
case 6:
return kMacOSSnowLeopard;
case 7:
return kMacOSLion;
case 8:
return kMacOSMountainLion;
}
return kMacOSNewer;
}
bool GetQuickTimeVersion(std::string* out) {
int ver;
if (!GetGestalt(gestaltQuickTimeVersion, &ver))
return false;
std::stringstream ss;
ss << std::hex << ver;
*out = ss.str();
return true;
}
bool RunAppleScript(const std::string& script) {
// TODO(thaloun): Add a .mm file that contains something like this:
// NSString source from script
// NSAppleScript* appleScript = [[NSAppleScript alloc] initWithSource:&source]
// if (appleScript != nil) {
// [appleScript executeAndReturnError:nil]
// [appleScript release]
#ifndef CARBON_DEPRECATED
ComponentInstance component = NULL;
AEDesc script_desc;
AEDesc result_data;
OSStatus err;
OSAID script_id, result_id;
AECreateDesc(typeNull, NULL, 0, &script_desc);
AECreateDesc(typeNull, NULL, 0, &result_data);
script_id = kOSANullScript;
result_id = kOSANullScript;
component = OpenDefaultComponent(kOSAComponentType, typeAppleScript);
if (component == NULL) {
LOG(LS_ERROR) << "Failed opening Apple Script component";
return false;
}
err = AECreateDesc(typeUTF8Text, script.data(), script.size(), &script_desc);
if (err != noErr) {
CloseComponent(component);
LOG(LS_ERROR) << "Failed creating Apple Script description";
return false;
}
err = OSACompile(component, &script_desc, kOSAModeCanInteract, &script_id);
if (err != noErr) {
AEDisposeDesc(&script_desc);
if (script_id != kOSANullScript) {
OSADispose(component, script_id);
}
CloseComponent(component);
LOG(LS_ERROR) << "Error compiling Apple Script";
return false;
}
err = OSAExecute(component, script_id, kOSANullScript, kOSAModeCanInteract,
&result_id);
if (err == errOSAScriptError) {
LOG(LS_ERROR) << "Error when executing Apple Script: " << script;
AECreateDesc(typeNull, NULL, 0, &result_data);
OSAScriptError(component, kOSAErrorMessage, typeChar, &result_data);
int len = AEGetDescDataSize(&result_data);
char* data = (char*) malloc(len);
if (data != NULL) {
err = AEGetDescData(&result_data, data, len);
LOG(LS_ERROR) << "Script error: " << data;
}
AEDisposeDesc(&script_desc);
AEDisposeDesc(&result_data);
return false;
}
AEDisposeDesc(&script_desc);
if (script_id != kOSANullScript) {
OSADispose(component, script_id);
}
if (result_id != kOSANullScript) {
OSADispose(component, result_id);
}
CloseComponent(component);
return true;
#else
// TODO(thaloun): Support applescripts with the NSAppleScript API.
return false;
#endif // CARBON_DEPRECATED
}
#endif // OSX
///////////////////////////////////////////////////////////////////////////////
} // namespace talk_base