⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 charcnv.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    Unix SMB/CIFS implementation.   Character set conversion Extensions   Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001   Copyright (C) Andrew Tridgell 2001   Copyright (C) Simo Sorce 2001   Copyright (C) Jelmer Vernooij 2007      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 3 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, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "system/iconv.h"#include "param/param.h"/** * @file * * @brief Character-set conversion routines built on our iconv. *  * @note Samba's internal character set (at least in the 3.0 series) * is always the same as the one for the Unix filesystem.  It is * <b>not</b> necessarily UTF-8 and may be different on machines that * need i18n filenames to be compatible with Unix software.  It does * have to be a superset of ASCII.  All multibyte sequences must start * with a byte with the high bit set. * * @sa lib/iconv.c */struct smb_iconv_convenience {	const char *unix_charset;	const char *dos_charset;	bool native_iconv;	smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];};/** * Return the name of a charset to give to iconv(). **/static const char *charset_name(struct smb_iconv_convenience *ic, charset_t ch){	switch (ch) {	case CH_UTF16: return "UTF-16LE";	case CH_UNIX: return ic->unix_charset;	case CH_DOS: return ic->dos_charset;	case CH_UTF8: return "UTF8";	case CH_UTF16BE: return "UTF-16BE";	default:	return "ASCII";	}}/** re-initialize iconv conversion descriptors**/static int close_iconv(struct smb_iconv_convenience *data){	unsigned c1, c2;	for (c1=0;c1<NUM_CHARSETS;c1++) {		for (c2=0;c2<NUM_CHARSETS;c2++) {			if (data->conv_handles[c1][c2] != NULL) {				if (data->conv_handles[c1][c2] != (smb_iconv_t)-1) {					smb_iconv_close(data->conv_handles[c1][c2]);				}				data->conv_handles[c1][c2] = NULL;			}		}	}	return 0;}_PUBLIC_ struct smb_iconv_convenience *smb_iconv_convenience_init(TALLOC_CTX *mem_ctx,							 const char *dos_charset,							 const char *unix_charset,							 bool native_iconv){	struct smb_iconv_convenience *ret = talloc_zero(mem_ctx, 					struct smb_iconv_convenience);	if (ret == NULL) {		return NULL;	}	talloc_set_destructor(ret, close_iconv);	ret->dos_charset = talloc_strdup(ret, dos_charset);	ret->unix_charset = talloc_strdup(ret, unix_charset);	ret->native_iconv = native_iconv;	return ret;}/*  on-demand initialisation of conversion handles*/static smb_iconv_t get_conv_handle(struct smb_iconv_convenience *ic,				   charset_t from, charset_t to){	const char *n1, *n2;	static bool initialised;	if (initialised == false) {		initialised = true;		#ifdef LC_ALL		/* we set back the locale to C to get ASCII-compatible		   toupper/lower functions.  For now we do not need		   any other POSIX localisations anyway. When we		   should really need localized string functions one		   day we need to write our own ascii_tolower etc.		*/		setlocale(LC_ALL, "C");#endif	}	if (ic->conv_handles[from][to]) {		return ic->conv_handles[from][to];	}	n1 = charset_name(ic, from);	n2 = charset_name(ic, to);	ic->conv_handles[from][to] = smb_iconv_open_ex(ic, n2, n1, 						       ic->native_iconv);		if (ic->conv_handles[from][to] == (smb_iconv_t)-1) {		if ((from == CH_DOS || to == CH_DOS) &&		    strcasecmp(charset_name(ic, CH_DOS), "ASCII") != 0) {			DEBUG(0,("dos charset '%s' unavailable - using ASCII\n",				 charset_name(ic, CH_DOS)));			ic->dos_charset = "ASCII";			n1 = charset_name(ic, from);			n2 = charset_name(ic, to);						ic->conv_handles[from][to] = 				smb_iconv_open_ex(ic, n2, n1, ic->native_iconv);		}	}	return ic->conv_handles[from][to];}/** * Convert string from one encoding to another, making error checking etc * * @param src pointer to source string (multibyte or singlebyte) * @param srclen length of the source string in bytes * @param dest pointer to destination string (multibyte or singlebyte) * @param destlen maximal length allowed for string * @returns the number of bytes occupied in the destination **/_PUBLIC_ ssize_t convert_string(struct smb_iconv_convenience *ic,				charset_t from, charset_t to,				void const *src, size_t srclen, 				void *dest, size_t destlen){	size_t i_len, o_len;	size_t retval;	const char* inbuf = (const char*)src;	char* outbuf = (char*)dest;	smb_iconv_t descriptor;	if (srclen == (size_t)-1)		srclen = strlen(inbuf)+1;	descriptor = get_conv_handle(ic, from, to);	if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {		/* conversion not supported, use as is */		size_t len = MIN(srclen,destlen);		memcpy(dest,src,len);		return len;	}	i_len=srclen;	o_len=destlen;	retval = smb_iconv(descriptor,  &inbuf, &i_len, &outbuf, &o_len);	if(retval==(size_t)-1) {	    	const char *reason;		switch(errno) {			case EINVAL:				reason="Incomplete multibyte sequence";				return -1;			case E2BIG:				reason="No more room"; 				if (from == CH_UNIX) {					DEBUG(0,("E2BIG: convert_string(%s,%s): srclen=%d destlen=%d - '%s'\n",						 charset_name(ic, from), charset_name(ic, to),						 (int)srclen, (int)destlen, 						 (const char *)src));				} else {					DEBUG(0,("E2BIG: convert_string(%s,%s): srclen=%d destlen=%d\n",						 charset_name(ic, from), charset_name(ic, to),						 (int)srclen, (int)destlen));				}			       return -1;			case EILSEQ:			       reason="Illegal multibyte sequence";			       return -1;		}		/* smb_panic(reason); */	}	return destlen-o_len;}	_PUBLIC_ ssize_t convert_string_talloc_descriptor(TALLOC_CTX *ctx, smb_iconv_t descriptor, void const *src, size_t srclen, void **dest){	size_t i_len, o_len, destlen;	size_t retval;	const char *inbuf = (const char *)src;	char *outbuf, *ob;	*dest = NULL;	/* it is _very_ rare that a conversion increases the size by	   more than 3x */	destlen = srclen;	outbuf = NULL;convert:	destlen = 2 + (destlen*3);	ob = talloc_realloc(ctx, outbuf, char, destlen);	if (!ob) {		DEBUG(0, ("convert_string_talloc: realloc failed!\n"));		talloc_free(outbuf);		return (size_t)-1;	} else {		outbuf = ob;	}	/* we give iconv 2 less bytes to allow us to terminate at the	   end */	i_len = srclen;	o_len = destlen-2;	retval = smb_iconv(descriptor,			   &inbuf, &i_len,			   &outbuf, &o_len);	if(retval == (size_t)-1) 		{	    	const char *reason="unknown error";		switch(errno) {			case EINVAL:				reason="Incomplete multibyte sequence";				break;			case E2BIG:				goto convert;					case EILSEQ:				reason="Illegal multibyte sequence";				break;		}		DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));		talloc_free(ob);		return (size_t)-1;	}		destlen = (destlen-2) - o_len;	/* guarantee null termination in all charsets */	SSVAL(ob, destlen, 0);	*dest = ob;	return destlen;}/** * Convert between character sets, allocating a new buffer using talloc for the result. * * @param srclen length of source buffer. * @param dest always set at least to NULL * @note -1 is not accepted for srclen. * * @returns Size in bytes of the converted string; or -1 in case of error. **/_PUBLIC_ ssize_t convert_string_talloc(TALLOC_CTX *ctx, 				       struct smb_iconv_convenience *ic, 				       charset_t from, charset_t to, 				       void const *src, size_t srclen, 				       void **dest){	smb_iconv_t descriptor;	*dest = NULL;	if (src == NULL || srclen == (size_t)-1 || srclen == 0)		return (size_t)-1;	descriptor = get_conv_handle(ic, from, to);	if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {		/* conversion not supported, return -1*/		DEBUG(3, ("convert_string_talloc: conversion from %s to %s not supported!\n",			  charset_name(ic, from), 			  charset_name(ic, to)));		return -1;	}	return convert_string_talloc_descriptor(ctx, descriptor, src, srclen, dest);}/** * Copy a string from a char* unix src to a dos codepage string destination. * * @return the number of bytes occupied by the string in the destination. * * @param flags can include * <dl> * <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd> * <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd> * </dl> * * @param dest_len the maximum length in bytes allowed in the * destination.  If @p dest_len is -1 then no maximum is used. **/static ssize_t push_ascii(struct smb_iconv_convenience *ic, 			  void *dest, const char *src, size_t dest_len, int flags){	size_t src_len;	ssize_t ret;	if (flags & STR_UPPER) {		char *tmpbuf = strupper_talloc(NULL, src);		if (tmpbuf == NULL) {			return -1;		}		ret = push_ascii(ic, dest, tmpbuf, dest_len, flags & ~STR_UPPER);		talloc_free(tmpbuf);		return ret;	}	src_len = strlen(src);	if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))		src_len++;	return convert_string(ic, CH_UNIX, CH_DOS, src, src_len, dest, dest_len);}/** * Copy a string from a unix char* src to an ASCII destination, * allocating a buffer using talloc(). * * @param dest always set at least to NULL  * * @returns The number of bytes occupied by the string in the destination *         or -1 in case of error. **/_PUBLIC_ ssize_t push_ascii_talloc(TALLOC_CTX *ctx, struct smb_iconv_convenience *ic, char **dest, const char *src){	size_t src_len = strlen(src)+1;	*dest = NULL;	return convert_string_talloc(ctx, ic, CH_UNIX, CH_DOS, src, src_len, (void **)dest);}/** * Copy a string from a dos codepage source to a unix char* destination. * * The resulting string in "dest" is always null terminated. * * @param flags can have: * <dl> * <dt>STR_TERMINATE</dt> * <dd>STR_TERMINATE means the string in @p src * is null terminated, and src_len is ignored.</dd> * </dl> * * @param src_len is the length of the source area in bytes. * @returns the number of bytes occupied by the string in @p src. **/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -