wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
+720
View File
@@ -0,0 +1,720 @@
/*
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
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"
#include "system/iconv.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
*/
/**
* Return the name of a charset to give to iconv().
**/
static const char *charset_name(charset_t ch)
{
switch (ch) {
case CH_UTF16: return "UTF-16LE";
case CH_UNIX: return lp_unix_charset();
case CH_DOS: return lp_dos_charset();
case CH_DISPLAY: return lp_display_charset();
case CH_UTF8: return "UTF8";
case CH_UTF16BE: return "UTF-16BE";
default:
return "ASCII";
}
}
static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
/**
re-initialize iconv conversion descriptors
**/
_PUBLIC_ void init_iconv(void)
{
unsigned c1, c2;
for (c1=0;c1<NUM_CHARSETS;c1++) {
for (c2=0;c2<NUM_CHARSETS;c2++) {
if (conv_handles[c1][c2] != NULL) {
if (conv_handles[c1][c2] != (smb_iconv_t)-1) {
smb_iconv_close(conv_handles[c1][c2]);
}
conv_handles[c1][c2] = NULL;
}
}
}
}
/*
on-demand initialisation of conversion handles
*/
static smb_iconv_t get_conv_handle(charset_t from, charset_t to)
{
const char *n1, *n2;
static int initialised;
/* auto-free iconv memory on exit so valgrind reports are easier
to look at */
if (initialised == 0) {
initialised = 1;
#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
atexit(init_iconv);
}
if (conv_handles[from][to]) {
return conv_handles[from][to];
}
n1 = charset_name(from);
n2 = charset_name(to);
conv_handles[from][to] = smb_iconv_open(n2,n1);
if (conv_handles[from][to] == (smb_iconv_t)-1) {
if ((from == CH_DOS || to == CH_DOS) &&
strcasecmp(charset_name(CH_DOS), "ASCII") != 0) {
DEBUG(0,("dos charset '%s' unavailable - using ASCII\n",
charset_name(CH_DOS)));
lp_set_cmdline("dos charset", "ASCII");
n1 = charset_name(from);
n2 = charset_name(to);
conv_handles[from][to] = smb_iconv_open(n2,n1);
}
}
return 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(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(src)+1;
descriptor = get_conv_handle(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(from), charset_name(to),
(int)srclen, (int)destlen,
(const char *)src));
} else {
DEBUG(0,("E2BIG: convert_string(%s,%s): srclen=%d destlen=%d\n",
charset_name(from), charset_name(to),
(int)srclen, (int)destlen));
}
return -1;
case EILSEQ:
reason="Illegal multibyte sequence";
return -1;
}
/* smb_panic(reason); */
}
return destlen-o_len;
}
/**
* 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, charset_t from, charset_t to,
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;
smb_iconv_t descriptor;
*dest = NULL;
if (src == NULL || srclen == (size_t)-1 || srclen == 0)
return (size_t)-1;
descriptor = get_conv_handle(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(from), charset_name(to)));
return -1;
}
/* 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;
}
/**
* 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(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(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(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, char **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
return convert_string_talloc(ctx, 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.
**/
static ssize_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
{
size_t ret;
if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII)) {
if (src_len == (size_t)-1) {
src_len = strlen(src) + 1;
} else {
size_t len = strnlen(src, src_len);
if (len < src_len)
len++;
src_len = len;
}
}
ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len);
if (dest_len)
dest[MIN(ret, dest_len-1)] = 0;
return src_len;
}
/**
* Copy a string from a char* src to a unicode destination.
*
* @returns the number of bytes occupied by the string in the destination.
*
* @param flags can have:
*
* <dl>
* <dt>STR_TERMINATE <dd>means include the null termination.
* <dt>STR_UPPER <dd>means uppercase in the destination.
* <dt>STR_NOALIGN <dd>means don't do alignment.
* </dl>
*
* @param dest_len is the maximum length allowed in the
* destination. If dest_len is -1 then no maxiumum is used.
**/
static ssize_t push_ucs2(void *dest, const char *src, size_t dest_len, int flags)
{
size_t len=0;
size_t src_len = strlen(src);
size_t ret;
if (flags & STR_UPPER) {
char *tmpbuf = strupper_talloc(NULL, src);
if (tmpbuf == NULL) {
return -1;
}
ret = push_ucs2(dest, tmpbuf, dest_len, flags & ~STR_UPPER);
talloc_free(tmpbuf);
return ret;
}
if (flags & STR_TERMINATE)
src_len++;
if (ucs2_align(NULL, dest, flags)) {
*(char *)dest = 0;
dest = (void *)((char *)dest + 1);
if (dest_len) dest_len--;
len++;
}
/* ucs2 is always a multiple of 2 bytes */
dest_len &= ~1;
ret = convert_string(CH_UNIX, CH_UTF16, src, src_len, dest, dest_len);
if (ret == (size_t)-1) {
return 0;
}
len += ret;
return len;
}
/**
* Copy a string from a unix char* src to a UCS2 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_ucs2_talloc(TALLOC_CTX *ctx, void **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
return convert_string_talloc(ctx, CH_UNIX, CH_UTF16, src, src_len, dest);
}
/**
* Copy a string from a unix char* src to a UTF-8 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
**/
_PUBLIC_ ssize_t push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len, (void **)dest);
}
/**
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 if it is -1.
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.
**/
static size_t pull_ucs2(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
{
size_t ret;
if (ucs2_align(NULL, src, flags)) {
src = (const void *)((const char *)src + 1);
if (src_len > 0)
src_len--;
}
if (flags & STR_TERMINATE) {
if (src_len == (size_t)-1) {
src_len = utf16_len(src);
} else {
src_len = utf16_len_n(src, src_len);
}
}
/* ucs2 is always a multiple of 2 bytes */
if (src_len != (size_t)-1)
src_len &= ~1;
ret = convert_string(CH_UTF16, CH_UNIX, src, src_len, dest, dest_len);
if (dest_len)
dest[MIN(ret, dest_len-1)] = 0;
return src_len;
}
/**
* Copy a string from a ASCII src to a unix char * 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
**/
_PUBLIC_ ssize_t pull_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
return convert_string_talloc(ctx, CH_DOS, CH_UNIX, src, src_len, (void **)dest);
}
/**
* Copy a string from a UCS2 src to a unix char * 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
**/
_PUBLIC_ ssize_t pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const void *src)
{
size_t src_len = utf16_len(src);
*dest = NULL;
return convert_string_talloc(ctx, CH_UTF16, CH_UNIX, src, src_len, (void **)dest);
}
/**
* Copy a string from a UTF-8 src to a unix char * 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
**/
_PUBLIC_ ssize_t pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len, (void **)dest);
}
/**
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.
**/
_PUBLIC_ ssize_t push_string(void *dest, const char *src, size_t dest_len, int flags)
{
if (flags & STR_ASCII) {
return push_ascii(dest, src, dest_len, flags);
} else if (flags & STR_UNICODE) {
return push_ucs2(dest, src, dest_len, flags);
} else {
smb_panic("push_string requires either STR_ASCII or STR_UNICODE flag to be set");
return -1;
}
}
/**
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 is it is -1
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.
**/
_PUBLIC_ ssize_t pull_string(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
{
if (flags & STR_ASCII) {
return pull_ascii(dest, src, dest_len, src_len, flags);
} else if (flags & STR_UNICODE) {
return pull_ucs2(dest, src, dest_len, src_len, flags);
} else {
smb_panic("pull_string requires either STR_ASCII or STR_UNICODE flag to be set");
return -1;
}
}
/*
return the unicode codepoint for the next multi-byte CH_UNIX character
in the string
also return the number of bytes consumed (which tells the caller
how many bytes to skip to get to the next CH_UNIX character)
return INVALID_CODEPOINT if the next character cannot be converted
*/
_PUBLIC_ codepoint_t next_codepoint(const char *str, size_t *size)
{
/* it cannot occupy more than 4 bytes in UTF16 format */
uint8_t buf[4];
smb_iconv_t descriptor;
size_t ilen_orig;
size_t ilen;
size_t olen;
char *outbuf;
if ((str[0] & 0x80) == 0) {
*size = 1;
return (codepoint_t)str[0];
}
/* we assume that no multi-byte character can take
more than 5 bytes. This is OK as we only
support codepoints up to 1M */
ilen_orig = strnlen(str, 5);
ilen = ilen_orig;
descriptor = get_conv_handle(CH_UNIX, CH_UTF16);
if (descriptor == (smb_iconv_t)-1) {
*size = 1;
return INVALID_CODEPOINT;
}
/* this looks a little strange, but it is needed to cope
with codepoints above 64k */
olen = 2;
outbuf = (char *)buf;
smb_iconv(descriptor, &str, &ilen, &outbuf, &olen);
if (olen == 2) {
olen = 4;
outbuf = (char *)buf;
smb_iconv(descriptor, &str, &ilen, &outbuf, &olen);
if (olen == 4) {
/* we didn't convert any bytes */
*size = 1;
return INVALID_CODEPOINT;
}
olen = 4 - olen;
} else {
olen = 2 - olen;
}
*size = ilen_orig - ilen;
if (olen == 2) {
return (codepoint_t)SVAL(buf, 0);
}
if (olen == 4) {
/* decode a 4 byte UTF16 character manually */
return (codepoint_t)0x10000 +
(buf[2] | ((buf[3] & 0x3)<<8) |
(buf[0]<<10) | ((buf[1] & 0x3)<<18));
}
/* no other length is valid */
return INVALID_CODEPOINT;
}
/*
push a single codepoint into a CH_UNIX string the target string must
be able to hold the full character, which is guaranteed if it is at
least 5 bytes in size. The caller may pass less than 5 bytes if they
are sure the character will fit (for example, you can assume that
uppercase/lowercase of a character will not add more than 1 byte)
return the number of bytes occupied by the CH_UNIX character, or
-1 on failure
*/
_PUBLIC_ ssize_t push_codepoint(char *str, codepoint_t c)
{
smb_iconv_t descriptor;
uint8_t buf[4];
size_t ilen, olen;
const char *inbuf;
if (c < 128) {
*str = c;
return 1;
}
descriptor = get_conv_handle(CH_UTF16, CH_UNIX);
if (descriptor == (smb_iconv_t)-1) {
return -1;
}
if (c < 0x10000) {
ilen = 2;
olen = 5;
inbuf = (char *)buf;
SSVAL(buf, 0, c);
smb_iconv(descriptor, &inbuf, &ilen, &str, &olen);
if (ilen != 0) {
return -1;
}
return 5 - olen;
}
c -= 0x10000;
buf[0] = (c>>10) & 0xFF;
buf[1] = (c>>18) | 0xd8;
buf[2] = c & 0xFF;
buf[3] = ((c>>8) & 0x3) | 0xdc;
ilen = 4;
olen = 5;
inbuf = (char *)buf;
smb_iconv(descriptor, &inbuf, &ilen, &str, &olen);
if (ilen != 0) {
return -1;
}
return 5 - olen;
}
+81
View File
@@ -0,0 +1,81 @@
/*
Unix SMB/CIFS implementation.
charset defines
Copyright (C) Andrew Tridgell 2001
Copyright (C) Jelmer Vernooij 2002
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.
*/
#ifndef __CHARSET_H__
#define __CHARSET_H__
#include "lib/talloc/talloc.h"
/* this defines the charset types used in samba */
typedef enum {CH_UTF16=0, CH_UNIX=1, CH_DISPLAY=2, CH_DOS=3, CH_UTF8=4, CH_UTF16BE=5} charset_t;
#define NUM_CHARSETS 6
/*
* for each charset we have a function that pulls from that charset to
* a ucs2 buffer, and a function that pushes to a ucs2 buffer
* */
struct charset_functions {
const char *name;
size_t (*pull)(void *, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
size_t (*push)(void *, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
struct charset_functions *prev, *next;
};
/* this type is used for manipulating unicode codepoints */
typedef uint32_t codepoint_t;
#define INVALID_CODEPOINT ((codepoint_t)-1)
/* generic iconv conversion structure */
typedef struct {
size_t (*direct)(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
size_t (*pull)(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
size_t (*push)(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
void *cd_direct, *cd_pull, *cd_push;
} *smb_iconv_t;
/* string manipulation flags */
#define STR_TERMINATE 1
#define STR_UPPER 2
#define STR_ASCII 4
#define STR_UNICODE 8
#define STR_NOALIGN 16
#define STR_NO_RANGE_CHECK 32
#define STR_LEN8BIT 64
#define STR_TERMINATE_ASCII 128 /* only terminate if ascii */
#define STR_LEN_NOTERM 256 /* the length field is the unterminated length */
#include "lib/charset/charset_proto.h"
/* replace some string functions with multi-byte
versions */
#define strlower(s) strlower_m(s)
#define strupper(s) strupper_m(s)
#endif /* __CHARSET_H__ */
+83
View File
@@ -0,0 +1,83 @@
dnl SMB_CHECK_ICONV(hdr, msg, action-if-found,action-if-not-found)
AC_DEFUN(SMB_CHECK_ICONV,[
AC_MSG_CHECKING($2)
AC_TRY_RUN([#include <stdlib.h>
#include <$1>
int main()
{
iconv_t cd = iconv_open("ASCII","UCS-2LE");
if (cd == 0 || cd == (iconv_t)-1) return -1;
return 0;
}
],[AC_MSG_RESULT(yes); $3],[AC_MSG_RESULT(no); $4])
])
dnl SMB_CHECK_ICONV_DIR(dir,action-if-found,action-if-not-found)
AC_DEFUN(SMB_CHECK_ICONV_DIR,
[
save_CPPFLAGS="$CPPFLAGS"
save_LDFLAGS="$LDFLAGS"
save_LIBS="$LIBS"
CPPFLAGS="-I$1/include"
LDFLAGS="-L$1/lib"
LIBS=-liconv
SMB_CHECK_ICONV(iconv.h,Whether iconv.h is present,[ AC_DEFINE(HAVE_ICONV_H,1,[Whether iconv.h is present]) $2 ], [
LIBS=-lgiconv
SMB_CHECK_ICONV(giconv.h,Whether giconv.h is present, [AC_DEFINE(HAVE_GICONV_H,1,[Whether giconv.h is present]) $2],[$3])
])
CPPFLAGS="$save_CPPFLAGS"
LDFLAGS="$save_LDFLAGS"
LIBS="$save_LIBS"
])
ICONV_FOUND=no
LOOK_DIRS="/usr /usr/local /sw"
AC_ARG_WITH(libiconv,
[ --with-libiconv=BASEDIR Use libiconv in BASEDIR/lib and BASEDIR/include (default=auto) ],
[
if test "$withval" = "no" ; then
AC_MSG_ERROR(I won't take no for an answer)
else
if test "$withval" != "yes" ; then
SMB_CHECK_ICONV_DIR($withval, [
ICONV_FOUND=yes;
ICONV_CPPFLAGS="$CPPFLAGS"
ICONV_LIBS="$LIBS"
ICONV_LDFLAGS="$LDFLAGS"
], [AC_MSG_ERROR([No iconv library found in $withval])])
fi
fi
])
if test x$ICONV_FOUND = xno; then
SMB_CHECK_ICONV(iconv.h,
[Whether iconv.h is present],
[AC_DEFINE(HAVE_ICONV_H,1,[Whether iconv.h is present]) ICONV_FOUND=yes])
fi
for i in $LOOK_DIRS ; do
if test x$ICONV_FOUND = xyes; then
break
fi
SMB_CHECK_ICONV_DIR($i, [
ICONV_FOUND=yes
ICONV_CPPFLAGS="$CPPFLAGS"
ICONV_LIBS="$LIBS"
ICONV_LDFLAGS="$LDFLAGS"
], [])
done
if test x"$ICONV_FOUND" = x"no"; then
AC_MSG_WARN([Sufficient support for iconv function was not found.
Install libiconv from http://www.gnu.org/software/libiconv/ for better charset compatibility!])
SMB_ENABLE(ICONV,NO)
else
AC_DEFINE(HAVE_NATIVE_ICONV,1,[Whether external iconv is available])
SMB_ENABLE(ICONV,YES)
fi
SMB_EXT_LIB(ICONV,[${ICONV_LIBS}],[${ICONV_CFLAGS}],[${ICONV_CPPFLAGS}],[${ICONV_LDFLAGS}])
+14
View File
@@ -0,0 +1,14 @@
################################################
# Start SUBSYSTEM CHARSET
[SUBSYSTEM::CHARSET]
OBJ_FILES = \
iconv.o \
charcnv.o \
util_unistr.o
PUBLIC_HEADERS = charset.h
PUBLIC_PROTO_HEADER = charset_proto.h
PUBLIC_DEPENDENCIES = ICONV
PRIVATE_DEPENDENCIES = DYNCONFIG
LDFLAGS = bin/static/libsamba-config.a bin/static/libsamba-util.a
# End SUBSYSTEM CHARSET
################################################
+696
View File
@@ -0,0 +1,696 @@
/*
Unix SMB/CIFS implementation.
minimal iconv implementation
Copyright (C) Andrew Tridgell 2001
Copyright (C) Jelmer Vernooij 2002
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"
#include "lib/util/dlinklist.h"
#include "system/iconv.h"
#include "system/filesys.h"
/**
* @file
*
* @brief Samba wrapper/stub for iconv character set conversion.
*
* iconv is the XPG2 interface for converting between character
* encodings. This file provides a Samba wrapper around it, and also
* a simple reimplementation that is used if the system does not
* implement iconv.
*
* Samba only works with encodings that are supersets of ASCII: ascii
* characters like whitespace can be tested for directly, multibyte
* sequences start with a byte with the high bit set, and strings are
* terminated by a nul byte.
*
* Note that the only function provided by iconv is conversion between
* characters. It doesn't directly support operations like
* uppercasing or comparison. We have to convert to UTF-16LE and
* compare there.
*
* @sa Samba Developers Guide
**/
static size_t ascii_pull (void *,const char **, size_t *, char **, size_t *);
static size_t ascii_push (void *,const char **, size_t *, char **, size_t *);
static size_t utf8_pull (void *,const char **, size_t *, char **, size_t *);
static size_t utf8_push (void *,const char **, size_t *, char **, size_t *);
static size_t ucs2hex_pull(void *,const char **, size_t *, char **, size_t *);
static size_t ucs2hex_push(void *,const char **, size_t *, char **, size_t *);
static size_t iconv_copy (void *,const char **, size_t *, char **, size_t *);
static size_t iconv_swab (void *,const char **, size_t *, char **, size_t *);
static const struct charset_functions builtin_functions[] = {
/* windows is closest to UTF-16 */
{"UCS-2LE", iconv_copy, iconv_copy},
{"UTF-16LE", iconv_copy, iconv_copy},
{"UCS-2BE", iconv_swab, iconv_swab},
{"UTF-16BE", iconv_swab, iconv_swab},
/* we include the UTF-8 alias to cope with differing locale settings */
{"UTF8", utf8_pull, utf8_push},
{"UTF-8", utf8_pull, utf8_push},
{"ASCII", ascii_pull, ascii_push},
{"UCS2-HEX", ucs2hex_pull, ucs2hex_push}
};
static struct charset_functions *charsets = NULL;
NTSTATUS charset_register_backend(const void *_funcs)
{
struct charset_functions *funcs = memdup(_funcs,sizeof(struct charset_functions));
struct charset_functions *c = charsets;
/* Check whether we already have this charset... */
while(c) {
if(!strcasecmp(c->name, funcs->name)){
DEBUG(2, ("Duplicate charset %s, not registering\n", funcs->name));
return NT_STATUS_OBJECT_NAME_COLLISION;
}
c = c->next;
}
funcs->next = funcs->prev = NULL;
DLIST_ADD(charsets, funcs);
return NT_STATUS_OK;
}
#ifdef HAVE_NATIVE_ICONV
/* if there was an error then reset the internal state,
this ensures that we don't have a shift state remaining for
character sets like SJIS */
static size_t sys_iconv(void *cd,
const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
size_t ret = iconv((iconv_t)cd,
discard_const_p(char *, inbuf), inbytesleft,
outbuf, outbytesleft);
if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
return ret;
}
#endif
/**
* This is a simple portable iconv() implementaion.
*
* It only knows about a very small number of character sets - just
* enough that Samba works on systems that don't have iconv.
**/
size_t smb_iconv(smb_iconv_t cd,
const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
char cvtbuf[2048];
size_t bufsize;
/* in many cases we can go direct */
if (cd->direct) {
return cd->direct(cd->cd_direct,
inbuf, inbytesleft, outbuf, outbytesleft);
}
/* otherwise we have to do it chunks at a time */
while (*inbytesleft > 0) {
char *bufp1 = cvtbuf;
const char *bufp2 = cvtbuf;
bufsize = sizeof(cvtbuf);
if (cd->pull(cd->cd_pull,
inbuf, inbytesleft, &bufp1, &bufsize) == -1
&& errno != E2BIG) return -1;
bufsize = sizeof(cvtbuf) - bufsize;
if (cd->push(cd->cd_push,
&bufp2, &bufsize,
outbuf, outbytesleft) == -1) return -1;
}
return 0;
}
static BOOL is_utf16(const char *name)
{
return strcasecmp(name, "UCS-2LE") == 0 ||
strcasecmp(name, "UTF-16LE") == 0;
}
/*
simple iconv_open() wrapper
*/
smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
{
smb_iconv_t ret;
const struct charset_functions *from=NULL, *to=NULL;
int i;
ret = (smb_iconv_t)talloc_named(NULL, sizeof(*ret),
"iconv(%s,%s)", tocode, fromcode);
if (!ret) {
errno = ENOMEM;
return (smb_iconv_t)-1;
}
memset(ret, 0, sizeof(*ret));
/* check for the simplest null conversion */
if (strcmp(fromcode, tocode) == 0) {
ret->direct = iconv_copy;
return ret;
}
for (i=0;i<ARRAY_SIZE(builtin_functions);i++) {
if (strcasecmp(fromcode, builtin_functions[i].name) == 0) {
from = &builtin_functions[i];
}
if (strcasecmp(tocode, builtin_functions[i].name) == 0) {
to = &builtin_functions[i];
}
}
if (from == NULL) {
for (from=charsets; from; from=from->next) {
if (strcasecmp(from->name, fromcode) == 0) break;
}
}
if (to == NULL) {
for (to=charsets; to; to=to->next) {
if (strcasecmp(to->name, tocode) == 0) break;
}
}
#ifdef HAVE_NATIVE_ICONV
if ((!from || !to) && !lp_parm_bool(-1, "iconv", "native", True)) {
goto failed;
}
if (!from) {
ret->pull = sys_iconv;
ret->cd_pull = iconv_open("UTF-16LE", fromcode);
if (ret->cd_pull == (iconv_t)-1)
ret->cd_pull = iconv_open("UCS-2LE", fromcode);
if (ret->cd_pull == (iconv_t)-1) goto failed;
}
if (!to) {
ret->push = sys_iconv;
ret->cd_push = iconv_open(tocode, "UTF-16LE");
if (ret->cd_push == (iconv_t)-1)
ret->cd_push = iconv_open(tocode, "UCS-2LE");
if (ret->cd_push == (iconv_t)-1) goto failed;
}
#else
if (!from || !to) {
goto failed;
}
#endif
/* check for conversion to/from ucs2 */
if (is_utf16(fromcode) && to) {
ret->direct = to->push;
return ret;
}
if (is_utf16(tocode) && from) {
ret->direct = from->pull;
return ret;
}
#ifdef HAVE_NATIVE_ICONV
if (is_utf16(fromcode)) {
ret->direct = sys_iconv;
ret->cd_direct = ret->cd_push;
ret->cd_push = NULL;
return ret;
}
if (is_utf16(tocode)) {
ret->direct = sys_iconv;
ret->cd_direct = ret->cd_pull;
ret->cd_pull = NULL;
return ret;
}
#endif
/* the general case has to go via a buffer */
if (!ret->pull) ret->pull = from->pull;
if (!ret->push) ret->push = to->push;
return ret;
failed:
talloc_free(ret);
errno = EINVAL;
return (smb_iconv_t)-1;
}
/*
simple iconv_close() wrapper
*/
int smb_iconv_close(smb_iconv_t cd)
{
#ifdef HAVE_NATIVE_ICONV
if (cd->cd_direct) iconv_close((iconv_t)cd->cd_direct);
if (cd->cd_pull) iconv_close((iconv_t)cd->cd_pull);
if (cd->cd_push) iconv_close((iconv_t)cd->cd_push);
#endif
talloc_free(cd);
return 0;
}
/**********************************************************************
the following functions implement the builtin character sets in Samba
and also the "test" character sets that are designed to test
multi-byte character set support for english users
***********************************************************************/
static size_t ascii_pull(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 1 && *outbytesleft >= 2) {
(*outbuf)[0] = (*inbuf)[0];
(*outbuf)[1] = 0;
(*inbytesleft) -= 1;
(*outbytesleft) -= 2;
(*inbuf) += 1;
(*outbuf) += 2;
}
if (*inbytesleft > 0) {
errno = E2BIG;
return -1;
}
return 0;
}
static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
int ir_count=0;
while (*inbytesleft >= 2 && *outbytesleft >= 1) {
(*outbuf)[0] = (*inbuf)[0] & 0x7F;
if ((*inbuf)[1]) ir_count++;
(*inbytesleft) -= 2;
(*outbytesleft) -= 1;
(*inbuf) += 2;
(*outbuf) += 1;
}
if (*inbytesleft == 1) {
errno = EINVAL;
return -1;
}
if (*inbytesleft > 1) {
errno = E2BIG;
return -1;
}
return ir_count;
}
static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 1 && *outbytesleft >= 2) {
uint_t v;
if ((*inbuf)[0] != '@') {
/* seven bit ascii case */
(*outbuf)[0] = (*inbuf)[0];
(*outbuf)[1] = 0;
(*inbytesleft) -= 1;
(*outbytesleft) -= 2;
(*inbuf) += 1;
(*outbuf) += 2;
continue;
}
/* it's a hex character */
if (*inbytesleft < 5) {
errno = EINVAL;
return -1;
}
if (sscanf(&(*inbuf)[1], "%04x", &v) != 1) {
errno = EILSEQ;
return -1;
}
(*outbuf)[0] = v&0xff;
(*outbuf)[1] = v>>8;
(*inbytesleft) -= 5;
(*outbytesleft) -= 2;
(*inbuf) += 5;
(*outbuf) += 2;
}
if (*inbytesleft > 0) {
errno = E2BIG;
return -1;
}
return 0;
}
static size_t ucs2hex_push(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 2 && *outbytesleft >= 1) {
char buf[6];
if ((*inbuf)[1] == 0 &&
((*inbuf)[0] & 0x80) == 0 &&
(*inbuf)[0] != '@') {
(*outbuf)[0] = (*inbuf)[0];
(*inbytesleft) -= 2;
(*outbytesleft) -= 1;
(*inbuf) += 2;
(*outbuf) += 1;
continue;
}
if (*outbytesleft < 5) {
errno = E2BIG;
return -1;
}
snprintf(buf, 6, "@%04x", SVAL(*inbuf, 0));
memcpy(*outbuf, buf, 5);
(*inbytesleft) -= 2;
(*outbytesleft) -= 5;
(*inbuf) += 2;
(*outbuf) += 5;
}
if (*inbytesleft == 1) {
errno = EINVAL;
return -1;
}
if (*inbytesleft > 1) {
errno = E2BIG;
return -1;
}
return 0;
}
static size_t iconv_swab(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
int n;
n = MIN(*inbytesleft, *outbytesleft);
swab(*inbuf, *outbuf, (n&~1));
if (n&1) {
(*outbuf)[n-1] = 0;
}
(*inbytesleft) -= n;
(*outbytesleft) -= n;
(*inbuf) += n;
(*outbuf) += n;
if (*inbytesleft > 0) {
errno = E2BIG;
return -1;
}
return 0;
}
static size_t iconv_copy(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
int n;
n = MIN(*inbytesleft, *outbytesleft);
memmove(*outbuf, *inbuf, n);
(*inbytesleft) -= n;
(*outbytesleft) -= n;
(*inbuf) += n;
(*outbuf) += n;
if (*inbytesleft > 0) {
errno = E2BIG;
return -1;
}
return 0;
}
static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
size_t in_left=*inbytesleft, out_left=*outbytesleft;
const uint8_t *c = (const uint8_t *)*inbuf;
uint8_t *uc = (uint8_t *)*outbuf;
while (in_left >= 1 && out_left >= 2) {
if ((c[0] & 0x80) == 0) {
uc[0] = c[0];
uc[1] = 0;
c += 1;
in_left -= 1;
out_left -= 2;
uc += 2;
continue;
}
if ((c[0] & 0xe0) == 0xc0) {
if (in_left < 2 ||
(c[1] & 0xc0) != 0x80) {
errno = EILSEQ;
goto error;
}
uc[1] = (c[0]>>2) & 0x7;
uc[0] = (c[0]<<6) | (c[1]&0x3f);
c += 2;
in_left -= 2;
out_left -= 2;
uc += 2;
continue;
}
if ((c[0] & 0xf0) == 0xe0) {
if (in_left < 3 ||
(c[1] & 0xc0) != 0x80 ||
(c[2] & 0xc0) != 0x80) {
errno = EILSEQ;
goto error;
}
uc[1] = ((c[0]&0xF)<<4) | ((c[1]>>2)&0xF);
uc[0] = (c[1]<<6) | (c[2]&0x3f);
c += 3;
in_left -= 3;
out_left -= 2;
uc += 2;
continue;
}
if ((c[0] & 0xf8) == 0xf0) {
unsigned int codepoint;
if (in_left < 4 ||
(c[1] & 0xc0) != 0x80 ||
(c[2] & 0xc0) != 0x80 ||
(c[3] & 0xc0) != 0x80) {
errno = EILSEQ;
goto error;
}
codepoint =
(c[3]&0x3f) |
((c[2]&0x3f)<<6) |
((c[1]&0x3f)<<12) |
((c[0]&0x7)<<18);
if (codepoint < 0x10000) {
/* accept UTF-8 characters that are not
minimally packed, but pack the result */
uc[0] = (codepoint & 0xFF);
uc[1] = (codepoint >> 8);
c += 4;
in_left -= 4;
out_left -= 2;
uc += 2;
continue;
}
codepoint -= 0x10000;
if (out_left < 4) {
errno = E2BIG;
goto error;
}
uc[0] = (codepoint>>10) & 0xFF;
uc[1] = (codepoint>>18) | 0xd8;
uc[2] = codepoint & 0xFF;
uc[3] = ((codepoint>>8) & 0x3) | 0xdc;
c += 4;
in_left -= 4;
out_left -= 4;
uc += 4;
continue;
}
/* we don't handle 5 byte sequences */
errno = EINVAL;
goto error;
}
if (in_left > 0) {
errno = E2BIG;
goto error;
}
*inbytesleft = in_left;
*outbytesleft = out_left;
*inbuf = (const char *)c;
*outbuf = (char *)uc;
return 0;
error:
*inbytesleft = in_left;
*outbytesleft = out_left;
*inbuf = (const char *)c;
*outbuf = (char *)uc;
return -1;
}
static size_t utf8_push(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
size_t in_left=*inbytesleft, out_left=*outbytesleft;
uint8_t *c = (uint8_t *)*outbuf;
const uint8_t *uc = (const uint8_t *)*inbuf;
while (in_left >= 2 && out_left >= 1) {
unsigned int codepoint;
if (uc[1] == 0 && !(uc[0] & 0x80)) {
/* simplest case */
c[0] = uc[0];
in_left -= 2;
out_left -= 1;
uc += 2;
c += 1;
continue;
}
if ((uc[1]&0xf8) == 0) {
/* next simplest case */
if (out_left < 2) {
errno = E2BIG;
goto error;
}
c[0] = 0xc0 | (uc[0]>>6) | (uc[1]<<2);
c[1] = 0x80 | (uc[0] & 0x3f);
in_left -= 2;
out_left -= 2;
uc += 2;
c += 2;
continue;
}
if ((uc[1] & 0xfc) == 0xdc) {
/* its the second part of a 4 byte sequence. Illegal */
if (in_left < 4) {
errno = EINVAL;
} else {
errno = EILSEQ;
}
goto error;
}
if ((uc[1] & 0xfc) != 0xd8) {
codepoint = uc[0] | (uc[1]<<8);
if (out_left < 3) {
errno = E2BIG;
goto error;
}
c[0] = 0xe0 | (codepoint >> 12);
c[1] = 0x80 | ((codepoint >> 6) & 0x3f);
c[2] = 0x80 | (codepoint & 0x3f);
in_left -= 2;
out_left -= 3;
uc += 2;
c += 3;
continue;
}
/* its the first part of a 4 byte sequence */
if (in_left < 4) {
errno = EINVAL;
goto error;
}
if ((uc[3] & 0xfc) != 0xdc) {
errno = EILSEQ;
goto error;
}
codepoint = 0x10000 + (uc[2] | ((uc[3] & 0x3)<<8) |
(uc[0]<<10) | ((uc[1] & 0x3)<<18));
if (out_left < 4) {
errno = E2BIG;
goto error;
}
c[0] = 0xf0 | (codepoint >> 18);
c[1] = 0x80 | ((codepoint >> 12) & 0x3f);
c[2] = 0x80 | ((codepoint >> 6) & 0x3f);
c[3] = 0x80 | (codepoint & 0x3f);
in_left -= 4;
out_left -= 4;
uc += 4;
c += 4;
}
if (in_left == 1) {
errno = EINVAL;
goto error;
}
if (in_left > 1) {
errno = E2BIG;
goto error;
}
*inbytesleft = in_left;
*outbytesleft = out_left;
*inbuf = (const char *)uc;
*outbuf = (char *)c;
return 0;
error:
*inbytesleft = in_left;
*outbytesleft = out_left;
*inbuf = (const char *)uc;
*outbuf = (char *)c;
return -1;
}
+645
View File
@@ -0,0 +1,645 @@
/*
Unix SMB/CIFS implementation.
Samba utility functions
Copyright (C) Andrew Tridgell 1992-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"
#include "system/locale.h"
#include "dynconfig.h"
/**
* @file
* @brief Unicode string manipulation
*/
/* these 2 tables define the unicode case handling. They are loaded
at startup either via mmap() or read() from the lib directory */
static void *upcase_table;
static void *lowcase_table;
/*******************************************************************
load the case handling tables
********************************************************************/
static void load_case_tables(void)
{
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_init("load_case_tables");
if (!mem_ctx) {
smb_panic("No memory for case_tables");
}
upcase_table = map_file(talloc_asprintf(mem_ctx, "%s/upcase.dat", dyn_DATADIR), 0x20000);
lowcase_table = map_file(talloc_asprintf(mem_ctx, "%s/lowcase.dat", dyn_DATADIR), 0x20000);
talloc_free(mem_ctx);
if (upcase_table == NULL) {
/* try also under codepages for testing purposes */
upcase_table = map_file("codepages/upcase.dat", 0x20000);
if (upcase_table == NULL) {
upcase_table = (void *)-1;
}
}
if (lowcase_table == NULL) {
/* try also under codepages for testing purposes */
lowcase_table = map_file("codepages/lowcase.dat", 0x20000);
if (lowcase_table == NULL) {
lowcase_table = (void *)-1;
}
}
}
/**
Convert a codepoint_t to upper case.
**/
codepoint_t toupper_w(codepoint_t val)
{
if (val < 128) {
return toupper(val);
}
if (upcase_table == NULL) {
load_case_tables();
}
if (upcase_table == (void *)-1) {
return val;
}
if (val & 0xFFFF0000) {
return val;
}
return SVAL(upcase_table, val*2);
}
/**
Convert a codepoint_t to lower case.
**/
codepoint_t tolower_w(codepoint_t val)
{
if (val < 128) {
return tolower(val);
}
if (lowcase_table == NULL) {
load_case_tables();
}
if (lowcase_table == (void *)-1) {
return val;
}
if (val & 0xFFFF0000) {
return val;
}
return SVAL(lowcase_table, val*2);
}
/**
compare two codepoints case insensitively
*/
int codepoint_cmpi(codepoint_t c1, codepoint_t c2)
{
if (c1 == c2 ||
toupper_w(c1) == toupper_w(c2)) {
return 0;
}
return c1 - c2;
}
/**
Case insensitive string compararison
**/
_PUBLIC_ int strcasecmp_m(const char *s1, const char *s2)
{
codepoint_t c1=0, c2=0;
size_t size1, size2;
/* handle null ptr comparisons to simplify the use in qsort */
if (s1 == s2) return 0;
if (s1 == NULL) return -1;
if (s2 == NULL) return 1;
while (*s1 && *s2) {
c1 = next_codepoint(s1, &size1);
c2 = next_codepoint(s2, &size2);
s1 += size1;
s2 += size2;
if (c1 == c2) {
continue;
}
if (c1 == INVALID_CODEPOINT ||
c2 == INVALID_CODEPOINT) {
/* what else can we do?? */
return strcasecmp(s1, s2);
}
if (toupper_w(c1) != toupper_w(c2)) {
return c1 - c2;
}
}
return *s1 - *s2;
}
/**
* Get the next token from a string, return False if none found.
* Handles double-quotes.
*
* Based on a routine by GJC@VILLAGE.COM.
* Extensively modified by Andrew.Tridgell@anu.edu.au
**/
_PUBLIC_ BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize)
{
const char *s;
BOOL quoted;
size_t len=1;
if (!ptr)
return(False);
s = *ptr;
/* default to simple separators */
if (!sep)
sep = " \t\n\r";
/* find the first non sep char */
while (*s && strchr_m(sep,*s))
s++;
/* nothing left? */
if (! *s)
return(False);
/* copy over the token */
for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
if (*s == '\"') {
quoted = !quoted;
} else {
len++;
*buff++ = *s;
}
}
*ptr = (*s) ? s+1 : s;
*buff = 0;
return(True);
}
/**
Case insensitive string compararison, length limited
**/
_PUBLIC_ int strncasecmp_m(const char *s1, const char *s2, size_t n)
{
codepoint_t c1=0, c2=0;
size_t size1, size2;
/* handle null ptr comparisons to simplify the use in qsort */
if (s1 == s2) return 0;
if (s1 == NULL) return -1;
if (s2 == NULL) return 1;
while (*s1 && *s2 && n) {
n--;
c1 = next_codepoint(s1, &size1);
c2 = next_codepoint(s2, &size2);
s1 += size1;
s2 += size2;
if (c1 == c2) {
continue;
}
if (c1 == INVALID_CODEPOINT ||
c2 == INVALID_CODEPOINT) {
/* what else can we do?? */
return strcasecmp(s1, s2);
}
if (toupper_w(c1) != toupper_w(c2)) {
return c1 - c2;
}
}
if (n == 0) {
return 0;
}
return *s1 - *s2;
}
/**
* Compare 2 strings.
*
* @note The comparison is case-insensitive.
**/
_PUBLIC_ BOOL strequal_w(const char *s1, const char *s2)
{
if (s1 == s2)
return(True);
if (!s1 || !s2)
return(False);
return strcasecmp_m(s1,s2) == 0;
}
/**
Compare 2 strings (case sensitive).
**/
_PUBLIC_ BOOL strcsequal_w(const char *s1,const char *s2)
{
if (s1 == s2)
return(True);
if (!s1 || !s2)
return(False);
return strcmp(s1,s2) == 0;
}
/**
String replace.
NOTE: oldc and newc must be 7 bit characters
**/
_PUBLIC_ void string_replace_w(char *s, char oldc, char newc)
{
for (; s && *s; s++) {
size_t size;
codepoint_t c = next_codepoint(s, &size);
if (c == oldc) {
*s = newc;
}
s += size;
}
}
/**
Paranoid strcpy into a buffer of given length (includes terminating
zero. Strips out all but 'a-Z0-9' and the character in other_safe_chars
and replaces with '_'. Deliberately does *NOT* check for multibyte
characters. Don't change it !
**/
_PUBLIC_ char *alpha_strcpy(char *dest, const char *src, const char *other_safe_chars, size_t maxlength)
{
size_t len, i;
if (maxlength == 0) {
/* can't fit any bytes at all! */
return NULL;
}
if (!dest) {
DEBUG(0,("ERROR: NULL dest in alpha_strcpy\n"));
return NULL;
}
if (!src) {
*dest = 0;
return dest;
}
len = strlen(src);
if (len >= maxlength)
len = maxlength - 1;
if (!other_safe_chars)
other_safe_chars = "";
for(i = 0; i < len; i++) {
int val = (src[i] & 0xff);
if (isupper(val) || islower(val) || isdigit(val) || strchr_m(other_safe_chars, val))
dest[i] = src[i];
else
dest[i] = '_';
}
dest[i] = '\0';
return dest;
}
/**
Count the number of UCS2 characters in a string. Normally this will
be the same as the number of bytes in a string for single byte strings,
but will be different for multibyte.
**/
_PUBLIC_ size_t strlen_m(const char *s)
{
size_t count = 0;
if (!s) {
return 0;
}
while (*s && !(((uint8_t)*s) & 0x80)) {
s++;
count++;
}
if (!*s) {
return count;
}
while (*s) {
size_t c_size;
codepoint_t c = next_codepoint(s, &c_size);
if (c < 0x10000) {
count += 1;
} else {
count += 2;
}
s += c_size;
}
return count;
}
/**
Work out the number of multibyte chars in a string, including the NULL
terminator.
**/
_PUBLIC_ size_t strlen_m_term(const char *s)
{
if (!s) {
return 0;
}
return strlen_m(s) + 1;
}
/**
Strchr and strrchr_m are a bit complex on general multi-byte strings.
**/
_PUBLIC_ char *strchr_m(const char *s, char c)
{
/* characters below 0x3F are guaranteed to not appear in
non-initial position in multi-byte charsets */
if ((c & 0xC0) == 0) {
return strchr(s, c);
}
while (*s) {
size_t size;
codepoint_t c2 = next_codepoint(s, &size);
if (c2 == c) {
return discard_const(s);
}
s += size;
}
return NULL;
}
/**
* Multibyte-character version of strrchr
*/
_PUBLIC_ char *strrchr_m(const char *s, char c)
{
char *ret = NULL;
/* characters below 0x3F are guaranteed to not appear in
non-initial position in multi-byte charsets */
if ((c & 0xC0) == 0) {
return strrchr(s, c);
}
while (*s) {
size_t size;
codepoint_t c2 = next_codepoint(s, &size);
if (c2 == c) {
ret = discard_const(s);
}
s += size;
}
return ret;
}
/**
return True if any (multi-byte) character is lower case
*/
_PUBLIC_ BOOL strhaslower(const char *string)
{
while (*string) {
size_t c_size;
codepoint_t s;
codepoint_t t;
s = next_codepoint(string, &c_size);
string += c_size;
t = toupper_w(s);
if (s != t) {
return True; /* that means it has lower case chars */
}
}
return False;
}
/**
return True if any (multi-byte) character is upper case
*/
_PUBLIC_ BOOL strhasupper(const char *string)
{
while (*string) {
size_t c_size;
codepoint_t s;
codepoint_t t;
s = next_codepoint(string, &c_size);
string += c_size;
t = tolower_w(s);
if (s != t) {
return True; /* that means it has upper case chars */
}
}
return False;
}
/**
Convert a string to lower case, allocated with talloc
**/
_PUBLIC_ char *strlower_talloc(TALLOC_CTX *ctx, const char *src)
{
size_t size=0;
char *dest;
/* this takes advantage of the fact that upper/lower can't
change the length of a character by more than 1 byte */
dest = talloc_size(ctx, 2*(strlen(src))+1);
if (dest == NULL) {
return NULL;
}
while (*src) {
size_t c_size;
codepoint_t c = next_codepoint(src, &c_size);
src += c_size;
c = tolower_w(c);
c_size = push_codepoint(dest+size, c);
if (c_size == -1) {
talloc_free(dest);
return NULL;
}
size += c_size;
}
dest[size] = 0;
return dest;
}
/**
Convert a string to UPPER case, allocated with talloc
**/
_PUBLIC_ char *strupper_talloc(TALLOC_CTX *ctx, const char *src)
{
size_t size=0;
char *dest;
if (!src) {
return NULL;
}
/* this takes advantage of the fact that upper/lower can't
change the length of a character by more than 1 byte */
dest = talloc_size(ctx, 2*(strlen(src))+1);
if (dest == NULL) {
return NULL;
}
while (*src) {
size_t c_size;
codepoint_t c = next_codepoint(src, &c_size);
src += c_size;
c = toupper_w(c);
c_size = push_codepoint(dest+size, c);
if (c_size == -1) {
talloc_free(dest);
return NULL;
}
size += c_size;
}
dest[size] = 0;
return dest;
}
/**
Convert a string to lower case.
**/
_PUBLIC_ void strlower_m(char *s)
{
char *d;
/* this is quite a common operation, so we want it to be
fast. We optimise for the ascii case, knowing that all our
supported multi-byte character sets are ascii-compatible
(ie. they match for the first 128 chars) */
while (*s && !(((uint8_t)*s) & 0x80)) {
*s = tolower((uint8_t)*s);
s++;
}
if (!*s)
return;
d = s;
while (*s) {
size_t c_size, c_size2;
codepoint_t c = next_codepoint(s, &c_size);
c_size2 = push_codepoint(d, tolower_w(c));
if (c_size2 > c_size) {
DEBUG(0,("FATAL: codepoint 0x%x (0x%x) expanded from %d to %d bytes in strlower_m\n",
c, tolower_w(c), (int)c_size, (int)c_size2));
smb_panic("codepoint expansion in strlower_m\n");
}
s += c_size;
d += c_size2;
}
*d = 0;
}
/**
Convert a string to UPPER case.
**/
_PUBLIC_ void strupper_m(char *s)
{
char *d;
/* this is quite a common operation, so we want it to be
fast. We optimise for the ascii case, knowing that all our
supported multi-byte character sets are ascii-compatible
(ie. they match for the first 128 chars) */
while (*s && !(((uint8_t)*s) & 0x80)) {
*s = toupper((uint8_t)*s);
s++;
}
if (!*s)
return;
d = s;
while (*s) {
size_t c_size, c_size2;
codepoint_t c = next_codepoint(s, &c_size);
c_size2 = push_codepoint(d, toupper_w(c));
if (c_size2 > c_size) {
DEBUG(0,("FATAL: codepoint 0x%x (0x%x) expanded from %d to %d bytes in strupper_m\n",
c, toupper_w(c), (int)c_size, (int)c_size2));
smb_panic("codepoint expansion in strupper_m\n");
}
s += c_size;
d += c_size2;
}
*d = 0;
}
/**
Find the number of 'c' chars in a string
**/
_PUBLIC_ size_t count_chars_w(const char *s, char c)
{
size_t count = 0;
while (*s) {
size_t size;
codepoint_t c2 = next_codepoint(s, &size);
if (c2 == c) count++;
s += size;
}
return count;
}