📄 charset_macosxfs.c
字号:
/* Unix SMB/CIFS implementation. Samba charset module for Mac OS X/Darwin Copyright (C) Benjamin Riefenstahl 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*//* * modules/charset_macosxfs.c * * A Samba charset module to use on Mac OS X/Darwin as the filesystem * and display encoding. * * Actually two implementations are provided here. The default * implementation is based on the official CFString API. The other is * based on internal CFString APIs as defined in the OpenDarwin * source. */#include "includes.h"/* * Include OS frameworks. These are only needed in this module. */#include <CoreFoundation/CFString.h>/* * See if autoconf has found us the internal headers in some form. */#if HAVE_COREFOUNDATION_CFSTRINGENCODINGCONVERTER_H# include <Corefoundation/CFStringEncodingConverter.h># include <Corefoundation/CFUnicodePrecomposition.h># define USE_INTERNAL_API 1#elif HAVE_CFSTRINGENCODINGCONVERTER_H# include <CFStringEncodingConverter.h># include <CFUnicodePrecomposition.h># define USE_INTERNAL_API 1#endif/* * Compile time configuration: Do we want debug output? *//* #define DEBUG_STRINGS 1 *//* * A simple, but efficient memory provider for our buffers. */static inline void *resize_buffer (void *buffer, size_t *size, size_t newsize){ if (newsize > *size) { *size = newsize + 128; buffer = realloc(buffer, *size); } return buffer;}/* * While there is a version of OpenDarwin for intel, the usual case is * big-endian PPC. So we need byte swapping to handle the * little-endian byte order of the network protocol. We also need an * additional dynamic buffer to do this work for incoming data blocks, * because we have to consider the original data as constant. * * We abstract the differences away by providing a simple facade with * these functions/macros: * * le_to_native(dst,src,len) * native_to_le(cp,len) * set_ucbuffer_with_le(buffer,bufsize,data,size) * set_ucbuffer_with_le_copy(buffer,bufsize,data,size,reserve) */#ifdef WORDS_BIGENDIANstatic inline void swap_bytes (char * dst, const char * src, size_t len){ const char *srcend = src + len; while (src < srcend) { dst[0] = src[1]; dst[1] = src[0]; dst += 2; src += 2; }}static inline void swap_bytes_inplace (char * cp, size_t len){ char temp; char *end = cp + len; while (cp < end) { temp = cp[1]; cp[1] = cp[0]; cp[0] = temp; cp += 2; }}#define le_to_native(dst,src,len) swap_bytes(dst,src,len)#define native_to_le(cp,len) swap_bytes_inplace(cp,len)#define set_ucbuffer_with_le(buffer,bufsize,data,size) \ set_ucbuffer_with_le_copy(buffer,bufsize,data,size,0)#else /* ! WORDS_BIGENDIAN */#define le_to_native(dst,src,len) memcpy(dst,src,len)#define native_to_le(cp,len) /* nothing */#define set_ucbuffer_with_le(buffer,bufsize,data,size) \ (((void)(bufsize)),(UniChar*)(data))#endifstatic inline UniChar *set_ucbuffer_with_le_copy ( UniChar *buffer, size_t *bufsize, const void *data, size_t size, size_t reserve){ buffer = resize_buffer(buffer, bufsize, size+reserve); le_to_native((char*)buffer,data,size); return buffer;}/* * A simple hexdump function for debugging error conditions. */#define debug_out(s) DEBUG(0,(s))#ifdef DEBUG_STRINGSstatic void hexdump( const char * label, const char * s, size_t len ){ size_t restlen = len; debug_out("<<<<<<<\n"); debug_out(label); debug_out("\n"); while (restlen > 0) { char line[100]; size_t i, j; char * d = line;#undef sprintf d += sprintf(d, "%04X ", (unsigned)(len-restlen)); *d++ = ' '; for( i = 0; i<restlen && i<8; ++i ) { d += sprintf(d, "%02X ", ((unsigned)s[i]) & 0xFF); } for( j = i; j<8; ++j ) { d += sprintf(d, " "); } *d++ = ' '; for( i = 8; i<restlen && i<16; ++i ) { d += sprintf(d, "%02X ", ((unsigned)s[i]) & 0xFF); } for( j = i; j<16; ++j ) { d += sprintf(d, " "); } *d++ = ' '; for( i = 0; i<restlen && i<16; ++i ) { if(s[i] < ' ' || s[i] >= 0x7F || !isprint(s[i])) *d++ = '.'; else *d++ = s[i]; } *d++ = '\n'; *d = 0; restlen -= i; s += i; debug_out(line); } debug_out(">>>>>>>\n");}#else /* !DEBUG_STRINGS */#define hexdump(label,s,len) /* nothing */#endif#if !USE_INTERNAL_API/* * An implementation based on documented Mac OS X APIs. * * This does a certain amount of memory management, creating and * manipulating CFString objects. We try to minimize the impact by * keeping those objects around and re-using them. We also use * external backing store for the CFStrings where this is possible and * benficial. * * The Unicode normalizations forms available at this level are * generic, not specifically for the file system. So they may not be * perfect fits. */static size_t macosxfs_encoding_pull( void *cd, /* Encoder handle */ char **inbuf, size_t *inbytesleft, /* Script string */ char **outbuf, size_t *outbytesleft) /* UTF-16-LE string */{ static const int script_code = kCFStringEncodingUTF8; static CFMutableStringRef cfstring = NULL; size_t outsize; CFRange range; (void) cd; /* UNUSED */ if (0 == *inbytesleft) { return 0; } if (NULL == cfstring) { /* * A version with an external backing store as in the * push function should have been more efficient, but * testing shows, that it is actually slower (!). * Maybe kCFAllocatorDefault gets shortcut evaluation * internally, while kCFAllocatorNull doesn't. */ cfstring = CFStringCreateMutable(kCFAllocatorDefault,0); } /* * Three methods of appending to a CFString, choose the most * efficient. */ if (0 == (*inbuf)[*inbytesleft-1]) { CFStringAppendCString(cfstring, *inbuf, script_code); } else if (*inbytesleft <= 255) { Str255 buffer; buffer[0] = *inbytesleft; memcpy(buffer+1, *inbuf, buffer[0]); CFStringAppendPascalString(cfstring, buffer, script_code); } else { /* * We would like to use a fixed buffer and a loop * here, but than we can't garantee that the input is * well-formed UTF-8, as we are supposed to do. */ static char *buffer = NULL; static size_t buflen = 0; buffer = resize_buffer(buffer, &buflen, *inbytesleft+1); memcpy(buffer, *inbuf, *inbytesleft); buffer[*inbytesleft] = 0; CFStringAppendCString(cfstring, *inbuf, script_code); } /* * Compose characters, using the non-canonical composition * form. */ CFStringNormalize(cfstring, kCFStringNormalizationFormC); outsize = CFStringGetLength(cfstring); range = CFRangeMake(0,outsize); if (outsize == 0) { /* * HACK: smbd/mangle_hash2.c:is_legal_name() expects * errors here. That function will always pass 2 * characters. smbd/open.c:check_for_pipe() cuts a * patchname to 10 characters blindly. Suppress the * debug output in those cases. */ if(2 != *inbytesleft && 10 != *inbytesleft) { debug_out("String conversion: " "An unknown error occurred\n"); hexdump("UTF8->UTF16LE (old) input", *inbuf, *inbytesleft); } errno = EILSEQ; /* Not sure, but this is what we have * actually seen. */ return -1; } if (outsize*2 > *outbytesleft) { CFStringDelete(cfstring, range); debug_out("String conversion: " "Output buffer too small\n"); hexdump("UTF8->UTF16LE (old) input", *inbuf, *inbytesleft); errno = E2BIG; return -1; } CFStringGetCharacters(cfstring, range, (UniChar*)*outbuf); CFStringDelete(cfstring, range); native_to_le(*outbuf, outsize*2); /* * Add a converted null byte, if the CFString conversions * prevented that until now. */ if (0 == (*inbuf)[*inbytesleft-1] &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -