1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-28 07:21:54 +03:00
samba-mirror/source3/lib/charcnv.c
Andrew Tridgell 87fbb7092b The big character set handling changeover!
This commit gets rid of all our old codepage handling and replaces it with
iconv. All internal strings in Samba are now in "unix" charset, which may
be multi-byte. See internals.doc and my posting to samba-technical for
a more complete explanation.
(This used to be commit debb471267)
2001-07-04 07:15:53 +00:00

357 lines
11 KiB
C

/*
Unix SMB/Netbios implementation.
Version 3.0
Character set conversion Extensions
Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
Copyright (C) Andrew Tridgell 2001
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.
*/
#include "includes.h"
extern int DEBUGLEVEL;
static pstring cvtbuf;
static smb_iconv_t
ucs2_to_unix=(smb_iconv_t)-1, /*ucs2 (MS) <-> unix format */
unix_to_ucs2=(smb_iconv_t)-1,
dos_to_unix=(smb_iconv_t)-1, /*unix format <-> dos codepage*/
unix_to_dos=(smb_iconv_t)-1; /*for those clients who does not support unicode*/
/****************************************************************************
Initialize iconv conversion descriptors
****************************************************************************/
void init_iconv(char *unix_charset, char *dos_charset)
{
#define ICONV(descr, from_name, to_name)\
if(descr!=(smb_iconv_t)-1) smb_iconv_close(descr);\
descr = smb_iconv_open(to_name, from_name);\
if(descr==(smb_iconv_t)-1)\
DEBUG(0,("Conversion from %s to %s is not supported\n",from_name,to_name));
if (!unix_charset || !*unix_charset) unix_charset = "ASCII";
if (!dos_charset || !*dos_charset) dos_charset = "ASCII";
ICONV(ucs2_to_unix, "UCS2", unix_charset)
ICONV(unix_to_ucs2, unix_charset, "UCS2")
ICONV(dos_to_unix, dos_charset, unix_charset)
ICONV(unix_to_dos, unix_charset, dos_charset)
#undef ICONV
}
/****************************************************************************
Convert string from one encoding to another, makeing error checking etc
Parameters:
descriptor - conversion descriptor, created in init_iconv
src - pointer to source string (multibute or singlebyte)
srclen - length of the source string in bytes
dest - pointer to destination string (multibyte or singlebyte)
destlen - maximal length allowed for string
return the number of bytes occupied in the destination
****************************************************************************/
static size_t convert_string(smb_iconv_t descriptor,
void const *src, size_t srclen,
void *dest, size_t destlen)
{
size_t i_len, o_len;
size_t retval;
char* inbuf = (char*)src;
char* outbuf = (char*)dest;
if (descriptor == (smb_iconv_t)-1) {
/* conversion not supported, use as is */
int 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==-1)
{ char *reason;
switch(errno)
{ case EINVAL: reason="Incomplete multybyte sequence"; break;
case E2BIG: reason="No more room";
DEBUG(0, ("Required %d, available %d\n",
srclen, destlen));
break;
case EILSEQ: reason="Illegal myltybyte sequence"; break;
}
DEBUG(0,("Conversion error:%s(%s)\n",reason,inbuf));
/* smb_panic(reason); */
}
return destlen-o_len;
}
int unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
{
int size,len;
smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
size=convert_string(unix_to_ucs2, src, srclen, buffer, sizeof(cvtbuf));
len=size/2;
strupper_w(buffer);
return convert_string(ucs2_to_unix, buffer, size, dest, destlen);
}
int unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
{
int size,len;
smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
size=convert_string(unix_to_ucs2, src, srclen, buffer, sizeof(cvtbuf));
len=size/2;
strlower_w(buffer);
return convert_string(ucs2_to_unix, buffer, size, dest, destlen);
}
int ucs2_align(const void *base_ptr, const void *p, int flags)
{
if (flags & (STR_NOALIGN|STR_ASCII)) return 0;
return PTR_DIFF(p, base_ptr) & 1;
}
/****************************************************************************
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
flags can have:
STR_TERMINATE means include the null termination
STR_UPPER means uppercase in the destination
dest_len is the maximum length allowed in the destination. If dest_len
is -1 then no maxiumum is used
****************************************************************************/
int push_ascii(void *dest, const char *src, int dest_len, int flags)
{
int src_len = strlen(src);
pstring tmpbuf;
/* treat a pstring as "unlimited" length */
if (dest_len == -1) {
dest_len = sizeof(pstring);
}
if (flags & STR_UPPER) {
pstrcpy(tmpbuf, src);
strupper(tmpbuf);
src = tmpbuf;
}
if (flags & STR_TERMINATE) {
src_len++;
}
return convert_string(unix_to_dos, src, src_len, dest, dest_len);
}
int push_ascii_fstring(void *dest, const char *src)
{
return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
}
int push_ascii_pstring(void *dest, const char *src)
{
return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
}
int push_pstring(void *dest, const char *src)
{
return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
}
/****************************************************************************
copy a string from a dos codepage source to a unix char* destination
flags can have:
STR_TERMINATE means the string in src is null terminated
if STR_TERMINATE is set then src_len is ignored
src_len is the length of the source area in bytes
return the number of bytes occupied by the string in src
the resulting string in "dest" is always null terminated
****************************************************************************/
int pull_ascii(char *dest, const void *src, int dest_len, int src_len, int flags)
{
int ret;
if (dest_len == -1) {
dest_len = sizeof(pstring);
}
if (flags & STR_TERMINATE) src_len = strlen(src)+1;
ret = convert_string(dos_to_unix, src, src_len, dest, dest_len);
if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
return src_len;
}
int pull_ascii_pstring(char *dest, const void *src)
{
return pull_ascii(dest, src, sizeof(pstring), -1, STR_TERMINATE);
}
int pull_ascii_fstring(char *dest, const void *src)
{
return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
}
/****************************************************************************
copy a string from a char* src to a unicode destination
return the number of bytes occupied by the string in the destination
flags can have:
STR_TERMINATE means include the null termination
STR_UPPER means uppercase in the destination
STR_NOALIGN means don't do alignment
dest_len is the maximum length allowed in the destination. If dest_len
is -1 then no maxiumum is used
****************************************************************************/
int push_ucs2(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
{
int len=0;
int src_len = strlen(src);
pstring tmpbuf;
/* treat a pstring as "unlimited" length */
if (dest_len == -1) {
dest_len = sizeof(pstring);
}
if (flags & STR_UPPER) {
pstrcpy(tmpbuf, src);
strupper(tmpbuf);
src = tmpbuf;
}
if (flags & STR_TERMINATE) {
src_len++;
}
if (ucs2_align(base_ptr, dest, flags)) {
*(char *)dest = 0;
dest = (void *)((char *)dest + 1);
if (dest_len) dest_len--;
len++;
}
len += convert_string(unix_to_ucs2, src, src_len, dest, dest_len);
return len;
}
/****************************************************************************
copy a string from a ucs2 source to a unix char* destination
flags can have:
STR_TERMINATE means the string in src is null terminated
STR_NOALIGN means don't try to align
if STR_TERMINATE is set then src_len is ignored
src_len is the length of the source area in bytes
return the number of bytes occupied by the string in src
the resulting string in "dest" is always null terminated
****************************************************************************/
int pull_ucs2(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len, int flags)
{
int ret;
if (dest_len == -1) {
dest_len = sizeof(pstring);
}
if (ucs2_align(base_ptr, src, flags)) {
src = (const void *)((const char *)src + 1);
if (src_len > 0) src_len--;
}
if (flags & STR_TERMINATE) src_len = strlen_w(src)*2+2;
ret = convert_string(ucs2_to_unix, src, src_len, dest, dest_len);
if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
return src_len;
}
int pull_ucs2_pstring(char *dest, const void *src)
{
return pull_ucs2(NULL, dest, src, sizeof(pstring), -1, STR_TERMINATE);
}
int pull_ucs2_fstring(char *dest, const void *src)
{
return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
}
/****************************************************************************
copy a string from a char* src to a unicode or ascii
dos code page destination choosing unicode or ascii based on the
flags in the SMB buffer starting at base_ptr
return the number of bytes occupied by the string in the destination
flags can have:
STR_TERMINATE means include the null termination
STR_UPPER means uppercase in the destination
STR_ASCII use ascii even with unicode packet
STR_NOALIGN means don't do alignment
dest_len is the maximum length allowed in the destination. If dest_len
is -1 then no maxiumum is used
****************************************************************************/
int push_string(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
{
if (!(flags & STR_ASCII) && \
((flags & STR_UNICODE || \
(SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
return push_ucs2(base_ptr, dest, src, dest_len, flags);
}
return push_ascii(dest, src, dest_len, flags);
}
/****************************************************************************
copy a string from a unicode or ascii source (depending on
the packet flags) to a char* destination
flags can have:
STR_TERMINATE means the string in src is null terminated
STR_UNICODE means to force as unicode
STR_ASCII use ascii even with unicode packet
STR_NOALIGN means don't do alignment
if STR_TERMINATE is set then src_len is ignored
src_len is the length of the source area in bytes
return the number of bytes occupied by the string in src
the resulting string in "dest" is always null terminated
****************************************************************************/
int pull_string(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len,
int flags)
{
if (!(flags & STR_ASCII) && \
((flags & STR_UNICODE || \
(SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
return pull_ucs2(base_ptr, dest, src, dest_len, src_len, flags);
}
return pull_ascii(dest, src, dest_len, src_len, flags);
}
int align_string(const void *base_ptr, const char *p, int flags)
{
if (!(flags & STR_ASCII) && \
((flags & STR_UNICODE || \
(SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
return ucs2_align(base_ptr, p, flags);
}
return 0;
}