/* Unix SMB/Netbios implementation. Version 3.0 Character set conversion Extensions Copyright (C) Igor Vergeichik 2001 Copyright (C) Andrew Tridgell 2001 Copyright (C) Simo Sorce 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" static pstring cvtbuf; static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS]; static int initialized; /**************************************************************************** return the name of a charset to give to iconv() ****************************************************************************/ static char *charset_name(charset_t ch) { char *ret = NULL; if (ch == CH_UCS2) ret = "UCS-2LE"; else if (ch == CH_UNIX) ret = lp_unix_charset(); else if (ch == CH_DOS) ret = lp_dos_charset(); else if (ch == CH_DISPLAY) ret = lp_display_charset(); if (!ret || !*ret) ret = "ASCII"; return ret; } /**************************************************************************** Initialize iconv conversion descriptors ****************************************************************************/ void init_iconv(void) { int c1, c2; /* so that charset_name() works we need to get the UNIX<->UCS2 going first */ if (!conv_handles[CH_UNIX][CH_UCS2]) { conv_handles[CH_UNIX][CH_UCS2] = smb_iconv_open("UCS-2LE", "ASCII"); } if (!conv_handles[CH_UCS2][CH_UNIX]) { conv_handles[CH_UCS2][CH_UNIX] = smb_iconv_open("ASCII", "UCS-2LE"); } for (c1=0;c1 0) src_len--; } if (flags & STR_TERMINATE) src_len = strlen_w(src)*2+2; /* ucs2 is always a multiple of 2 bytes */ src_len &= ~1; ret = convert_string(CH_UCS2, CH_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 codepage 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; } /**************************************************************************** convert from ucs2 to unix charset and return the allocated and converted string or NULL if an error occurred. you must provide a zero terminated string. the returning string will be zero terminated. ****************************************************************************/ char *acnv_u2ux(const smb_ucs2_t *src) { size_t slen; size_t dlen; void *dest; slen = (strlen_w(src) + 1) * sizeof(smb_ucs2_t); dlen = convert_string_allocate(CH_UCS2, CH_UNIX, src, slen, &dest); if (dlen == -1) return NULL; else return dest; } /**************************************************************************** convert from unix to ucs2 charset and return the allocated and converted string or NULL if an error occurred. you must provide a zero terminated string. the returning string will be zero terminated. ****************************************************************************/ smb_ucs2_t *acnv_uxu2(const char *src) { size_t slen; size_t dlen; void *dest; slen = strlen(src) + 1; dlen = convert_string_allocate(CH_UNIX, CH_UCS2, src, slen, &dest); if (dlen == -1) return NULL; else return dest; } /**************************************************************************** convert from ucs2 to dos charset and return the allocated and converted string or NULL if an error occurred. you must provide a zero terminated string. the returning string will be zero terminated. ****************************************************************************/ char *acnv_u2dos(const smb_ucs2_t *src) { size_t slen; size_t dlen; void *dest; slen = (strlen_w(src) + 1) * sizeof(smb_ucs2_t); dlen = convert_string_allocate(CH_UCS2, CH_DOS, src, slen, &dest); if (dlen == -1) return NULL; else return dest; } /**************************************************************************** convert from dos to ucs2 charset and return the allocated and converted string or NULL if an error occurred. you must provide a zero terminated string. the returning string will be zero terminated. ****************************************************************************/ smb_ucs2_t *acnv_dosu2(const char *src) { size_t slen; size_t dlen; void *dest; slen = strlen(src) + 1; dlen = convert_string_allocate(CH_DOS, CH_UCS2, src, slen, &dest); if (dlen == -1) return NULL; else return dest; }