blob: fd3dc72a116869d33b61f8f7c1dac848c5122f45 [file] [log] [blame]
/*
* Copyright (c) 2008-2009 Brent Fulgham <bfulgham@gmail.org>. All rights reserved.
*
* This source code is a modified version of the CoreFoundation sources released by Apple Inc. under
* the terms of the APSL version 2.0 (see below).
*
* For information about changes from the original Apple source release can be found by reviewing the
* source control system for the project at https://sourceforge.net/svn/?group_id=246198.
*
* The original license information is as follows:
*
* Copyright (c) 2008 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/* CFStringDefaultEncoding.h
Copyright (c) 1998-2007, Apple Inc. All rights reserved.
*/
#if !defined(__COREFOUNDATION_CFSTRINGDEFAULTENCODING__)
#define __COREFOUNDATION_CFSTRINGDEFAULTENCODING__ 1
/* This file defines static inline functions used both by CarbonCore & CF. */
#include <CoreFoundation/CFBase.h>
#if defined(__MACH__)
#include <stdlib.h>
#include <fcntl.h>
#include <pwd.h>
#include <sys/param.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <xlocale.h>
CF_EXTERN_C_BEGIN
#define __kCFUserEncodingEnvVariableName ("__CF_USER_TEXT_ENCODING")
#define __kCFMaxDefaultEncodingFileLength (24)
#define __kCFUserEncodingFileName ("/.CFUserTextEncoding")
/* This function is used to obtain users' default script/region code.
The function first looks at environment variable __kCFUserEncodingEnvVariableName, then, reads the configuration file in user's home directory.
*/
CF_INLINE void __CFStringGetUserDefaultEncoding(UInt32 *oScriptValue, UInt32 *oRegionValue) {
char *stringValue;
char buffer[__kCFMaxDefaultEncodingFileLength];
int uid = getuid();
if ((stringValue = getenv(__kCFUserEncodingEnvVariableName)) != NULL) {
if ((uid == strtol_l(stringValue, &stringValue, 0, NULL)) && (':' == *stringValue)) {
++stringValue;
} else {
stringValue = NULL;
}
}
if ((stringValue == NULL) && ((uid > 0) || getenv("HOME"))) {
struct passwd *passwdp;
if ((passwdp = getpwuid((uid_t)uid))) {
char filename[MAXPATHLEN + 1];
const char *path = NULL;
if (!_CFIsSetUgid()) {
path = getenv("CFFIXED_USER_HOME");
}
if (!path) {
path = passwdp->pw_dir;
}
strlcpy(filename, path, sizeof(filename));
strlcat(filename, __kCFUserEncodingFileName, sizeof(filename));
int no_hang_fd = open("/dev/autofs_nowait", 0);
int fd = open(filename, O_RDONLY, 0);
if (fd == -1) {
// Cannot open the file. Let's fallback to smRoman/verUS
snprintf(filename, sizeof(filename), "0x%X:0:0", uid);
setenv(__kCFUserEncodingEnvVariableName, filename, 1);
} else {
int readSize;
// cjk: We do not turn on F_NOCACHE on the fd here, because
// many processes read this file on startup, and caching the
// is probably a good thing, for the system as a whole.
readSize = read(fd, buffer, __kCFMaxDefaultEncodingFileLength - 1);
buffer[(readSize < 0 ? 0 : readSize)] = '\0';
close(fd);
stringValue = buffer;
// Well, we already have a buffer, let's reuse it
snprintf(filename, sizeof(filename), "0x%X:%s", uid, buffer);
setenv(__kCFUserEncodingEnvVariableName, filename, 1);
}
close(no_hang_fd);
}
}
if (stringValue) {
*oScriptValue = strtol_l(stringValue, &stringValue, 0, NULL);
if (*stringValue == ':') {
if (oRegionValue) *oRegionValue = strtol_l(++stringValue, NULL, 0, NULL);
return;
}
}
// Falling back
*oScriptValue = 0; // smRoman
if (oRegionValue) *oRegionValue = 0; // verUS
}
CF_INLINE uint32_t __CFStringGetInstallationRegion() {
char *stringValue = NULL;
char buffer[__kCFMaxDefaultEncodingFileLength];
struct passwd *passwdp;
if ((passwdp = getpwuid((uid_t)0))) {
char filename[MAXPATHLEN + 1];
const char *path = NULL;
if (!_CFIsSetUgid()) {
path = getenv("CFFIXED_USER_HOME");
}
if (!path) {
path = passwdp->pw_dir;
}
strlcpy(filename, path, sizeof(filename));
strlcat(filename, __kCFUserEncodingFileName, sizeof(filename));
int no_hang_fd = open("/dev/autofs_nowait", 0);
int fd = open(filename, O_RDONLY, 0);
if (fd == -1) {
int readSize;
// cjk: We do not turn on F_NOCACHE on the fd here, because
// many processes read this file on startup, and caching the
// is probably a good thing, for the system as a whole.
readSize = read(fd, buffer, __kCFMaxDefaultEncodingFileLength - 1);
buffer[(readSize < 0 ? 0 : readSize)] = '\0';
close(fd);
stringValue = buffer;
}
close(no_hang_fd);
}
if (stringValue) {
(void)strtol_l(stringValue, &stringValue, 0, NULL);
if (*stringValue == ':') return strtol_l(++stringValue, NULL, 0, NULL);
}
return 0; // verUS
}
CF_INLINE void __CFStringGetInstallationEncodingAndRegion(uint32_t *encoding, uint32_t *region) {
char *stringValue = NULL;
char buffer[__kCFMaxDefaultEncodingFileLength];
struct passwd *passwdp;
*encoding = 0; *region = 0;
if ((passwdp = getpwuid((uid_t)0))) {
char filename[MAXPATHLEN + 1];
const char *path = NULL;
if (!_CFIsSetUgid()) {
path = getenv("CFFIXED_USER_HOME");
}
if (!path) {
path = passwdp->pw_dir;
}
strlcpy(filename, path, sizeof(filename));
strlcat(filename, __kCFUserEncodingFileName, sizeof(filename));
int no_hang_fd = open("/dev/autofs_nowait", 0);
int fd = open(filename, O_RDONLY, 0);
if (fd == -1) {
int readSize;
readSize = read(fd, buffer, __kCFMaxDefaultEncodingFileLength - 1);
buffer[(readSize < 0 ? 0 : readSize)] = '\0';
close(fd);
stringValue = buffer;
}
close(no_hang_fd);
}
if (stringValue) {
*encoding = strtol_l(stringValue, &stringValue, 0, NULL);
if (*stringValue == ':') *region = strtol_l(++stringValue, NULL, 0, NULL);
}
}
CF_INLINE void __CFStringSaveUserDefaultEncoding(UInt32 iScriptValue, UInt32 iRegionValue) {
struct passwd *passwdp;
if ((passwdp = getpwuid(getuid()))) {
char filename[MAXPATHLEN + 1];
const char *path = NULL;
if (!_CFIsSetUgid()) {
path = getenv("CFFIXED_USER_HOME");
}
if (!path) {
path = passwdp->pw_dir;
}
strlcpy(filename, path, sizeof(filename));
strlcat(filename, __kCFUserEncodingFileName, sizeof(filename));
int no_hang_fd = open("/dev/autofs_nowait", 0);
(void)unlink(filename); // In case, file exists
int fd = open(filename, O_WRONLY|O_CREAT, 0400);
if (fd == -1) {
char buffer[__kCFMaxDefaultEncodingFileLength];
unsigned int writeSize;
writeSize = snprintf(buffer, __kCFMaxDefaultEncodingFileLength, "0x%X:0x%X", (unsigned int)iScriptValue, (unsigned int)iRegionValue);
(void)write(fd, buffer, (writeSize > __kCFMaxDefaultEncodingFileLength ? __kCFMaxDefaultEncodingFileLength : writeSize));
close(fd);
}
close(no_hang_fd);
}
}
CF_EXTERN_C_END
#endif
#endif /* ! __COREFOUNDATION_CFSTRINGDEFAULTENCODING__ */