mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
3c490d91f1
If I'm not completely blind, then check_dos_char is *only* used in the case
when we can't mmap() valid.dat. To me this looks as if we initialize the 65536
bits in doschar_table[] with check_dos_char_slowly, use it once to initialize
valid_table[] and *never* use them again. I think there's no point in keeping
these 8k of modified memory around for an unlikely case (no "valid.dat") and
even that only to use it exactly once.
(This used to be commit 0bfea7259e
)
1102 lines
26 KiB
C
1102 lines
26 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
Samba utility functions
|
|
Copyright (C) Andrew Tridgell 1992-2001
|
|
Copyright (C) Simo Sorce 2001
|
|
Copyright (C) Jeremy Allison 2005
|
|
|
|
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"
|
|
|
|
#ifndef MAXUNI
|
|
#define MAXUNI 1024
|
|
#endif
|
|
|
|
/* these 3 tables define the unicode case handling. They are loaded
|
|
at startup either via mmap() or read() from the lib directory */
|
|
static smb_ucs2_t *upcase_table;
|
|
static smb_ucs2_t *lowcase_table;
|
|
static uint8 *valid_table;
|
|
static bool upcase_table_use_unmap;
|
|
static bool lowcase_table_use_unmap;
|
|
static bool valid_table_use_unmap;
|
|
|
|
/**
|
|
* Destroy global objects allocated by load_case_tables()
|
|
**/
|
|
void gfree_case_tables(void)
|
|
{
|
|
if ( upcase_table ) {
|
|
if ( upcase_table_use_unmap )
|
|
unmap_file(upcase_table, 0x20000);
|
|
else
|
|
SAFE_FREE(upcase_table);
|
|
}
|
|
|
|
if ( lowcase_table ) {
|
|
if ( lowcase_table_use_unmap )
|
|
unmap_file(lowcase_table, 0x20000);
|
|
else
|
|
SAFE_FREE(lowcase_table);
|
|
}
|
|
|
|
if ( valid_table ) {
|
|
if ( valid_table_use_unmap )
|
|
unmap_file(valid_table, 0x10000);
|
|
else
|
|
SAFE_FREE(valid_table);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load or generate the case handling tables.
|
|
*
|
|
* The case tables are defined in UCS2 and don't depend on any
|
|
* configured parameters, so they never need to be reloaded.
|
|
**/
|
|
|
|
void load_case_tables(void)
|
|
{
|
|
static int initialised;
|
|
char *old_locale = NULL, *saved_locale = NULL;
|
|
int i;
|
|
TALLOC_CTX *frame = NULL;
|
|
|
|
if (initialised) {
|
|
return;
|
|
}
|
|
initialised = 1;
|
|
|
|
frame = talloc_stackframe();
|
|
|
|
upcase_table = (smb_ucs2_t *)map_file(data_path("upcase.dat"),
|
|
0x20000);
|
|
upcase_table_use_unmap = ( upcase_table != NULL );
|
|
|
|
lowcase_table = (smb_ucs2_t *)map_file(data_path("lowcase.dat"),
|
|
0x20000);
|
|
lowcase_table_use_unmap = ( lowcase_table != NULL );
|
|
|
|
#ifdef HAVE_SETLOCALE
|
|
/* Get the name of the current locale. */
|
|
old_locale = setlocale(LC_ALL, NULL);
|
|
|
|
if (old_locale) {
|
|
/* Save it as it is in static storage. */
|
|
saved_locale = SMB_STRDUP(old_locale);
|
|
}
|
|
|
|
/* We set back the locale to C to get ASCII-compatible toupper/lower functions. */
|
|
setlocale(LC_ALL, "C");
|
|
#endif
|
|
|
|
/* we would like Samba to limp along even if these tables are
|
|
not available */
|
|
if (!upcase_table) {
|
|
DEBUG(1,("creating lame upcase table\n"));
|
|
upcase_table = (smb_ucs2_t *)SMB_MALLOC(0x20000);
|
|
for (i=0;i<0x10000;i++) {
|
|
smb_ucs2_t v;
|
|
SSVAL(&v, 0, i);
|
|
upcase_table[v] = i;
|
|
}
|
|
for (i=0;i<256;i++) {
|
|
smb_ucs2_t v;
|
|
SSVAL(&v, 0, UCS2_CHAR(i));
|
|
upcase_table[v] = UCS2_CHAR(islower(i)?toupper(i):i);
|
|
}
|
|
}
|
|
|
|
if (!lowcase_table) {
|
|
DEBUG(1,("creating lame lowcase table\n"));
|
|
lowcase_table = (smb_ucs2_t *)SMB_MALLOC(0x20000);
|
|
for (i=0;i<0x10000;i++) {
|
|
smb_ucs2_t v;
|
|
SSVAL(&v, 0, i);
|
|
lowcase_table[v] = i;
|
|
}
|
|
for (i=0;i<256;i++) {
|
|
smb_ucs2_t v;
|
|
SSVAL(&v, 0, UCS2_CHAR(i));
|
|
lowcase_table[v] = UCS2_CHAR(isupper(i)?tolower(i):i);
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_SETLOCALE
|
|
/* Restore the old locale. */
|
|
if (saved_locale) {
|
|
setlocale (LC_ALL, saved_locale);
|
|
SAFE_FREE(saved_locale);
|
|
}
|
|
#endif
|
|
TALLOC_FREE(frame);
|
|
}
|
|
|
|
static int check_dos_char_slowly(smb_ucs2_t c)
|
|
{
|
|
char buf[10];
|
|
smb_ucs2_t c2 = 0;
|
|
int len1, len2;
|
|
|
|
len1 = convert_string(CH_UTF16LE, CH_DOS, &c, 2, buf, sizeof(buf),False);
|
|
if (len1 == 0) {
|
|
return 0;
|
|
}
|
|
len2 = convert_string(CH_DOS, CH_UTF16LE, buf, len1, &c2, 2,False);
|
|
if (len2 != 2) {
|
|
return 0;
|
|
}
|
|
return (c == c2);
|
|
}
|
|
|
|
/**
|
|
* Load the valid character map table from <tt>valid.dat</tt> or
|
|
* create from the configured codepage.
|
|
*
|
|
* This function is called whenever the configuration is reloaded.
|
|
* However, the valid character table is not changed if it's loaded
|
|
* from a file, because we can't unmap files.
|
|
**/
|
|
|
|
void init_valid_table(void)
|
|
{
|
|
static int mapped_file;
|
|
int i;
|
|
const char *allowed = ".!#$%&'()_-@^`~";
|
|
uint8 *valid_file;
|
|
|
|
if (mapped_file) {
|
|
/* Can't unmap files, so stick with what we have */
|
|
return;
|
|
}
|
|
|
|
valid_file = (uint8 *)map_file(data_path("valid.dat"), 0x10000);
|
|
if (valid_file) {
|
|
valid_table = valid_file;
|
|
mapped_file = 1;
|
|
valid_table_use_unmap = True;
|
|
return;
|
|
}
|
|
|
|
/* Otherwise, we're using a dynamically created valid_table.
|
|
* It might need to be regenerated if the code page changed.
|
|
* We know that we're not using a mapped file, so we can
|
|
* free() the old one. */
|
|
SAFE_FREE(valid_table);
|
|
|
|
/* use free rather than unmap */
|
|
valid_table_use_unmap = False;
|
|
|
|
DEBUG(2,("creating default valid table\n"));
|
|
valid_table = (uint8 *)SMB_MALLOC(0x10000);
|
|
SMB_ASSERT(valid_table != NULL);
|
|
for (i=0;i<128;i++) {
|
|
valid_table[i] = isalnum(i) || strchr(allowed,i);
|
|
}
|
|
|
|
lazy_initialize_conv();
|
|
|
|
for (;i<0x10000;i++) {
|
|
smb_ucs2_t c;
|
|
SSVAL(&c, 0, i);
|
|
valid_table[i] = check_dos_char_slowly(c);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
Write a string in (little-endian) unicode format. src is in
|
|
the current DOS codepage. len is the length in bytes of the
|
|
string pointed to by dst.
|
|
|
|
if null_terminate is True then null terminate the packet (adds 2 bytes)
|
|
|
|
the return value is the length in bytes consumed by the string, including the
|
|
null termination if applied
|
|
********************************************************************/
|
|
|
|
size_t dos_PutUniCode(char *dst,const char *src, size_t len, bool null_terminate)
|
|
{
|
|
int flags = null_terminate ? STR_UNICODE|STR_NOALIGN|STR_TERMINATE
|
|
: STR_UNICODE|STR_NOALIGN;
|
|
return push_ucs2(NULL, dst, src, len, flags);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
Skip past a unicode string, but not more than len. Always move
|
|
past a terminating zero if found.
|
|
********************************************************************/
|
|
|
|
char *skip_unibuf(char *src, size_t len)
|
|
{
|
|
char *srcend = src + len;
|
|
|
|
while (src < srcend && SVAL(src,0)) {
|
|
src += 2;
|
|
}
|
|
|
|
if(!SVAL(src,0)) {
|
|
src += 2;
|
|
}
|
|
|
|
return src;
|
|
}
|
|
|
|
/* Copy a string from little-endian or big-endian unicode source (depending
|
|
* on flags) to internal samba format destination
|
|
*/
|
|
|
|
int rpcstr_pull(char* dest, void *src, int dest_len, int src_len, int flags)
|
|
{
|
|
if (!src) {
|
|
dest[0] = 0;
|
|
return 0;
|
|
}
|
|
if(dest_len==-1) {
|
|
dest_len=MAXUNI-3;
|
|
}
|
|
return pull_ucs2(NULL, dest, src, dest_len, src_len, flags|STR_UNICODE|STR_NOALIGN);
|
|
}
|
|
|
|
/* Copy a string from little-endian or big-endian unicode source (depending
|
|
* on flags) to internal samba format destination. Allocates on talloc ctx.
|
|
*/
|
|
|
|
int rpcstr_pull_talloc(TALLOC_CTX *ctx,
|
|
char **dest,
|
|
void *src,
|
|
int src_len,
|
|
int flags)
|
|
{
|
|
return pull_ucs2_base_talloc(ctx,
|
|
NULL,
|
|
dest,
|
|
src,
|
|
src_len,
|
|
flags|STR_UNICODE|STR_NOALIGN);
|
|
|
|
}
|
|
|
|
/* Copy a string from a unistr2 source to internal samba format
|
|
destination. Use this instead of direct calls to rpcstr_pull() to avoid
|
|
having to determine whether the source string is null terminated. */
|
|
|
|
int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src)
|
|
{
|
|
return pull_ucs2(NULL, dest, src->buffer, sizeof(fstring),
|
|
src->uni_str_len * 2, 0);
|
|
}
|
|
|
|
/* Helper function to return a talloc'ed string. I have implemented it with a
|
|
* copy because I don't really know how pull_ucs2 and friends calculate the
|
|
* target size. If this turns out to be a major bottleneck someone with deeper
|
|
* multi-byte knowledge needs to revisit this.
|
|
* I just did (JRA :-). No longer uses copy.
|
|
* My (VL) use is dsr_getdcname, which returns 6 strings, the alternative would
|
|
* have been to manually talloc_strdup them in rpc_client/cli_netlogon.c.
|
|
*/
|
|
|
|
char *rpcstr_pull_unistr2_talloc(TALLOC_CTX *ctx, const UNISTR2 *src)
|
|
{
|
|
char *dest = NULL;
|
|
size_t dest_len = convert_string_talloc(ctx,
|
|
CH_UTF16LE,
|
|
CH_UNIX,
|
|
src->buffer,
|
|
src->uni_str_len * 2,
|
|
(void *)&dest,
|
|
true);
|
|
if (dest_len == (size_t)-1) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Ensure we're returning a null terminated string. */
|
|
if (dest_len) {
|
|
/* Did we already process the terminating zero ? */
|
|
if (dest[dest_len-1] != 0) {
|
|
size_t size = talloc_get_size(dest);
|
|
/* Have we got space to append the '\0' ? */
|
|
if (size <= dest_len) {
|
|
/* No, realloc. */
|
|
dest = TALLOC_REALLOC_ARRAY(ctx, dest, char,
|
|
dest_len+1);
|
|
if (!dest) {
|
|
/* talloc fail. */
|
|
dest_len = (size_t)-1;
|
|
return NULL;
|
|
}
|
|
}
|
|
/* Yay - space ! */
|
|
dest[dest_len] = '\0';
|
|
dest_len++;
|
|
}
|
|
} else if (dest) {
|
|
dest[0] = 0;
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
|
|
/* Converts a string from internal samba format to unicode
|
|
*/
|
|
|
|
int rpcstr_push(void *dest, const char *src, size_t dest_len, int flags)
|
|
{
|
|
return push_ucs2(NULL, dest, src, dest_len, flags|STR_UNICODE|STR_NOALIGN);
|
|
}
|
|
|
|
/* Converts a string from internal samba format to unicode. Always terminates.
|
|
* Actually just a wrapper round push_ucs2_talloc().
|
|
*/
|
|
|
|
int rpcstr_push_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src)
|
|
{
|
|
return push_ucs2_talloc(ctx, dest, src);
|
|
}
|
|
|
|
/*******************************************************************
|
|
Convert a (little-endian) UNISTR2 structure to an ASCII string.
|
|
********************************************************************/
|
|
|
|
void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen)
|
|
{
|
|
if ((str == NULL) || (str->uni_str_len == 0)) {
|
|
*dest='\0';
|
|
return;
|
|
}
|
|
pull_ucs2(NULL, dest, str->buffer, maxlen, str->uni_str_len*2, STR_NOALIGN);
|
|
}
|
|
|
|
#if 0
|
|
/*******************************************************************
|
|
Convert a (little-endian) UNISTR3 structure to an ASCII string.
|
|
********************************************************************/
|
|
|
|
void unistr3_to_ascii(char *dest, const UNISTR3 *str, size_t maxlen)
|
|
{
|
|
if ((str == NULL) || (str->uni_str_len == 0)) {
|
|
*dest='\0';
|
|
return;
|
|
}
|
|
pull_ucs2(NULL, dest, str->str.buffer, maxlen, str->uni_str_len*2,
|
|
STR_NOALIGN);
|
|
}
|
|
#endif
|
|
|
|
/*******************************************************************
|
|
Duplicate a UNISTR2 string into a null terminated char*
|
|
using a talloc context.
|
|
********************************************************************/
|
|
|
|
char *unistr2_to_ascii_talloc(TALLOC_CTX *ctx, const UNISTR2 *str)
|
|
{
|
|
char *s = NULL;
|
|
|
|
if (!str || !str->buffer) {
|
|
return NULL;
|
|
}
|
|
if (pull_ucs2_base_talloc(ctx,
|
|
NULL,
|
|
&s,
|
|
str->buffer,
|
|
str->uni_str_len*2,
|
|
STR_NOALIGN) == (size_t)-1) {
|
|
return NULL;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Return a string for displaying a UNISTR2. Guarentees to return a
|
|
valid string - "" if nothing else.
|
|
Changed to use talloc_tos() under the covers.... JRA.
|
|
********************************************************************/
|
|
|
|
const char *unistr2_static(const UNISTR2 *str)
|
|
{
|
|
char *dest = NULL;
|
|
|
|
if ((str == NULL) || (str->uni_str_len == 0)) {
|
|
return "";
|
|
}
|
|
|
|
dest = unistr2_to_ascii_talloc(talloc_tos(), str);
|
|
if (!dest) {
|
|
return "";
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Convert a wchar to upper case.
|
|
********************************************************************/
|
|
|
|
smb_ucs2_t toupper_w(smb_ucs2_t val)
|
|
{
|
|
return upcase_table[SVAL(&val,0)];
|
|
}
|
|
|
|
/*******************************************************************
|
|
Convert a wchar to lower case.
|
|
********************************************************************/
|
|
|
|
smb_ucs2_t tolower_w( smb_ucs2_t val )
|
|
{
|
|
return lowcase_table[SVAL(&val,0)];
|
|
}
|
|
|
|
/*******************************************************************
|
|
Determine if a character is lowercase.
|
|
********************************************************************/
|
|
|
|
bool islower_w(smb_ucs2_t c)
|
|
{
|
|
return upcase_table[SVAL(&c,0)] != c;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Determine if a character is uppercase.
|
|
********************************************************************/
|
|
|
|
bool isupper_w(smb_ucs2_t c)
|
|
{
|
|
return lowcase_table[SVAL(&c,0)] != c;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Determine if a character is valid in a 8.3 name.
|
|
********************************************************************/
|
|
|
|
bool isvalid83_w(smb_ucs2_t c)
|
|
{
|
|
return valid_table[SVAL(&c,0)] != 0;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Count the number of characters in a smb_ucs2_t string.
|
|
********************************************************************/
|
|
|
|
size_t strlen_w(const smb_ucs2_t *src)
|
|
{
|
|
size_t len;
|
|
smb_ucs2_t c;
|
|
|
|
for(len = 0; *(COPY_UCS2_CHAR(&c,src)); src++, len++) {
|
|
;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Count up to max number of characters in a smb_ucs2_t string.
|
|
********************************************************************/
|
|
|
|
size_t strnlen_w(const smb_ucs2_t *src, size_t max)
|
|
{
|
|
size_t len;
|
|
smb_ucs2_t c;
|
|
|
|
for(len = 0; (len < max) && *(COPY_UCS2_CHAR(&c,src)); src++, len++) {
|
|
;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Wide strchr().
|
|
********************************************************************/
|
|
|
|
smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
|
|
{
|
|
smb_ucs2_t cp;
|
|
while (*(COPY_UCS2_CHAR(&cp,s))) {
|
|
if (c == cp) {
|
|
return (smb_ucs2_t *)s;
|
|
}
|
|
s++;
|
|
}
|
|
if (c == cp) {
|
|
return (smb_ucs2_t *)s;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
|
|
{
|
|
return strchr_w(s, UCS2_CHAR(c));
|
|
}
|
|
|
|
/*******************************************************************
|
|
Wide strrchr().
|
|
********************************************************************/
|
|
|
|
smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
|
|
{
|
|
smb_ucs2_t cp;
|
|
const smb_ucs2_t *p = s;
|
|
int len = strlen_w(s);
|
|
|
|
if (len == 0) {
|
|
return NULL;
|
|
}
|
|
p += (len - 1);
|
|
do {
|
|
if (c == *(COPY_UCS2_CHAR(&cp,p))) {
|
|
return (smb_ucs2_t *)p;
|
|
}
|
|
} while (p-- != s);
|
|
return NULL;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Wide version of strrchr that returns after doing strrchr 'n' times.
|
|
********************************************************************/
|
|
|
|
smb_ucs2_t *strnrchr_w(const smb_ucs2_t *s, smb_ucs2_t c, unsigned int n)
|
|
{
|
|
smb_ucs2_t cp;
|
|
const smb_ucs2_t *p = s;
|
|
int len = strlen_w(s);
|
|
|
|
if (len == 0 || !n) {
|
|
return NULL;
|
|
}
|
|
p += (len - 1);
|
|
do {
|
|
if (c == *(COPY_UCS2_CHAR(&cp,p))) {
|
|
n--;
|
|
}
|
|
|
|
if (!n) {
|
|
return (smb_ucs2_t *)p;
|
|
}
|
|
} while (p-- != s);
|
|
return NULL;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Wide strstr().
|
|
********************************************************************/
|
|
|
|
smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins)
|
|
{
|
|
smb_ucs2_t *r;
|
|
size_t inslen;
|
|
|
|
if (!s || !*s || !ins || !*ins) {
|
|
return NULL;
|
|
}
|
|
|
|
inslen = strlen_w(ins);
|
|
r = (smb_ucs2_t *)s;
|
|
|
|
while ((r = strchr_w(r, *ins))) {
|
|
if (strncmp_w(r, ins, inslen) == 0) {
|
|
return r;
|
|
}
|
|
r++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Convert a string to lower case.
|
|
return True if any char is converted
|
|
********************************************************************/
|
|
|
|
bool strlower_w(smb_ucs2_t *s)
|
|
{
|
|
smb_ucs2_t cp;
|
|
bool ret = False;
|
|
|
|
while (*(COPY_UCS2_CHAR(&cp,s))) {
|
|
smb_ucs2_t v = tolower_w(cp);
|
|
if (v != cp) {
|
|
COPY_UCS2_CHAR(s,&v);
|
|
ret = True;
|
|
}
|
|
s++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Convert a string to upper case.
|
|
return True if any char is converted
|
|
********************************************************************/
|
|
|
|
bool strupper_w(smb_ucs2_t *s)
|
|
{
|
|
smb_ucs2_t cp;
|
|
bool ret = False;
|
|
while (*(COPY_UCS2_CHAR(&cp,s))) {
|
|
smb_ucs2_t v = toupper_w(cp);
|
|
if (v != cp) {
|
|
COPY_UCS2_CHAR(s,&v);
|
|
ret = True;
|
|
}
|
|
s++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Convert a string to "normal" form.
|
|
********************************************************************/
|
|
|
|
void strnorm_w(smb_ucs2_t *s, int case_default)
|
|
{
|
|
if (case_default == CASE_UPPER) {
|
|
strupper_w(s);
|
|
} else {
|
|
strlower_w(s);
|
|
}
|
|
}
|
|
|
|
int strcmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
|
|
{
|
|
smb_ucs2_t cpa, cpb;
|
|
|
|
while ((*(COPY_UCS2_CHAR(&cpb,b))) && (*(COPY_UCS2_CHAR(&cpa,a)) == cpb)) {
|
|
a++;
|
|
b++;
|
|
}
|
|
return (*(COPY_UCS2_CHAR(&cpa,a)) - *(COPY_UCS2_CHAR(&cpb,b)));
|
|
/* warning: if *a != *b and both are not 0 we return a random
|
|
greater or lesser than 0 number not realted to which
|
|
string is longer */
|
|
}
|
|
|
|
int strncmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
|
|
{
|
|
smb_ucs2_t cpa, cpb;
|
|
size_t n = 0;
|
|
|
|
while ((n < len) && (*(COPY_UCS2_CHAR(&cpb,b))) && (*(COPY_UCS2_CHAR(&cpa,a)) == cpb)) {
|
|
a++;
|
|
b++;
|
|
n++;
|
|
}
|
|
return (len - n)?(*(COPY_UCS2_CHAR(&cpa,a)) - *(COPY_UCS2_CHAR(&cpb,b))):0;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Case insensitive string comparison.
|
|
********************************************************************/
|
|
|
|
int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
|
|
{
|
|
smb_ucs2_t cpa, cpb;
|
|
|
|
while ((*COPY_UCS2_CHAR(&cpb,b)) && toupper_w(*(COPY_UCS2_CHAR(&cpa,a))) == toupper_w(cpb)) {
|
|
a++;
|
|
b++;
|
|
}
|
|
return (tolower_w(*(COPY_UCS2_CHAR(&cpa,a))) - tolower_w(*(COPY_UCS2_CHAR(&cpb,b))));
|
|
}
|
|
|
|
/*******************************************************************
|
|
Case insensitive string comparison, length limited.
|
|
********************************************************************/
|
|
|
|
int strncasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
|
|
{
|
|
smb_ucs2_t cpa, cpb;
|
|
size_t n = 0;
|
|
|
|
while ((n < len) && *COPY_UCS2_CHAR(&cpb,b) && (toupper_w(*(COPY_UCS2_CHAR(&cpa,a))) == toupper_w(cpb))) {
|
|
a++;
|
|
b++;
|
|
n++;
|
|
}
|
|
return (len - n)?(tolower_w(*(COPY_UCS2_CHAR(&cpa,a))) - tolower_w(*(COPY_UCS2_CHAR(&cpb,b)))):0;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Compare 2 strings.
|
|
********************************************************************/
|
|
|
|
bool strequal_w(const smb_ucs2_t *s1, const smb_ucs2_t *s2)
|
|
{
|
|
if (s1 == s2) {
|
|
return(True);
|
|
}
|
|
if (!s1 || !s2) {
|
|
return(False);
|
|
}
|
|
|
|
return(strcasecmp_w(s1,s2)==0);
|
|
}
|
|
|
|
/*******************************************************************
|
|
Compare 2 strings up to and including the nth char.
|
|
******************************************************************/
|
|
|
|
bool strnequal_w(const smb_ucs2_t *s1,const smb_ucs2_t *s2,size_t n)
|
|
{
|
|
if (s1 == s2) {
|
|
return(True);
|
|
}
|
|
if (!s1 || !s2 || !n) {
|
|
return(False);
|
|
}
|
|
|
|
return(strncasecmp_w(s1,s2,n)==0);
|
|
}
|
|
|
|
/*******************************************************************
|
|
Duplicate string.
|
|
********************************************************************/
|
|
|
|
smb_ucs2_t *strdup_w(const smb_ucs2_t *src)
|
|
{
|
|
return strndup_w(src, 0);
|
|
}
|
|
|
|
/* if len == 0 then duplicate the whole string */
|
|
|
|
smb_ucs2_t *strndup_w(const smb_ucs2_t *src, size_t len)
|
|
{
|
|
smb_ucs2_t *dest;
|
|
|
|
if (!len) {
|
|
len = strlen_w(src);
|
|
}
|
|
dest = SMB_MALLOC_ARRAY(smb_ucs2_t, len + 1);
|
|
if (!dest) {
|
|
DEBUG(0,("strdup_w: out of memory!\n"));
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(dest, src, len * sizeof(smb_ucs2_t));
|
|
dest[len] = 0;
|
|
return dest;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Copy a string with max len.
|
|
********************************************************************/
|
|
|
|
smb_ucs2_t *strncpy_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
|
|
{
|
|
smb_ucs2_t cp;
|
|
size_t len;
|
|
|
|
if (!dest || !src) {
|
|
return NULL;
|
|
}
|
|
|
|
for (len = 0; (*COPY_UCS2_CHAR(&cp,(src+len))) && (len < max); len++) {
|
|
cp = *COPY_UCS2_CHAR(dest+len,src+len);
|
|
}
|
|
cp = 0;
|
|
for ( /*nothing*/ ; len < max; len++ ) {
|
|
cp = *COPY_UCS2_CHAR(dest+len,&cp);
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Append a string of len bytes and add a terminator.
|
|
********************************************************************/
|
|
|
|
smb_ucs2_t *strncat_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
|
|
{
|
|
size_t start;
|
|
size_t len;
|
|
smb_ucs2_t z = 0;
|
|
|
|
if (!dest || !src) {
|
|
return NULL;
|
|
}
|
|
|
|
start = strlen_w(dest);
|
|
len = strnlen_w(src, max);
|
|
|
|
memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));
|
|
z = *COPY_UCS2_CHAR(dest+start+len,&z);
|
|
|
|
return dest;
|
|
}
|
|
|
|
smb_ucs2_t *strcat_w(smb_ucs2_t *dest, const smb_ucs2_t *src)
|
|
{
|
|
size_t start;
|
|
size_t len;
|
|
smb_ucs2_t z = 0;
|
|
|
|
if (!dest || !src) {
|
|
return NULL;
|
|
}
|
|
|
|
start = strlen_w(dest);
|
|
len = strlen_w(src);
|
|
|
|
memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));
|
|
z = *COPY_UCS2_CHAR(dest+start+len,&z);
|
|
|
|
return dest;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
Replace any occurence of oldc with newc in unicode string.
|
|
********************************************************************/
|
|
|
|
void string_replace_w(smb_ucs2_t *s, smb_ucs2_t oldc, smb_ucs2_t newc)
|
|
{
|
|
smb_ucs2_t cp;
|
|
|
|
for(;*(COPY_UCS2_CHAR(&cp,s));s++) {
|
|
if(cp==oldc) {
|
|
COPY_UCS2_CHAR(s,&newc);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
Trim unicode string.
|
|
********************************************************************/
|
|
|
|
bool trim_string_w(smb_ucs2_t *s, const smb_ucs2_t *front,
|
|
const smb_ucs2_t *back)
|
|
{
|
|
bool ret = False;
|
|
size_t len, front_len, back_len;
|
|
|
|
if (!s) {
|
|
return False;
|
|
}
|
|
|
|
len = strlen_w(s);
|
|
|
|
if (front && *front) {
|
|
front_len = strlen_w(front);
|
|
while (len && strncmp_w(s, front, front_len) == 0) {
|
|
memmove(s, (s + front_len), (len - front_len + 1) * sizeof(smb_ucs2_t));
|
|
len -= front_len;
|
|
ret = True;
|
|
}
|
|
}
|
|
|
|
if (back && *back) {
|
|
back_len = strlen_w(back);
|
|
while (len && strncmp_w((s + (len - back_len)), back, back_len) == 0) {
|
|
s[len - back_len] = 0;
|
|
len -= back_len;
|
|
ret = True;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
The *_wa() functions take a combination of 7 bit ascii
|
|
and wide characters They are used so that you can use string
|
|
functions combining C string constants with ucs2 strings
|
|
|
|
The char* arguments must NOT be multibyte - to be completely sure
|
|
of this only pass string constants */
|
|
|
|
int strcmp_wa(const smb_ucs2_t *a, const char *b)
|
|
{
|
|
smb_ucs2_t cp = 0;
|
|
|
|
while (*b && *(COPY_UCS2_CHAR(&cp,a)) == UCS2_CHAR(*b)) {
|
|
a++;
|
|
b++;
|
|
}
|
|
return (*(COPY_UCS2_CHAR(&cp,a)) - UCS2_CHAR(*b));
|
|
}
|
|
|
|
int strncmp_wa(const smb_ucs2_t *a, const char *b, size_t len)
|
|
{
|
|
smb_ucs2_t cp = 0;
|
|
size_t n = 0;
|
|
|
|
while ((n < len) && *b && *(COPY_UCS2_CHAR(&cp,a)) == UCS2_CHAR(*b)) {
|
|
a++;
|
|
b++;
|
|
n++;
|
|
}
|
|
return (len - n)?(*(COPY_UCS2_CHAR(&cp,a)) - UCS2_CHAR(*b)):0;
|
|
}
|
|
|
|
smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p)
|
|
{
|
|
smb_ucs2_t cp;
|
|
|
|
while (*(COPY_UCS2_CHAR(&cp,s))) {
|
|
int i;
|
|
for (i=0; p[i] && cp != UCS2_CHAR(p[i]); i++)
|
|
;
|
|
if (p[i]) {
|
|
return (smb_ucs2_t *)s;
|
|
}
|
|
s++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins)
|
|
{
|
|
smb_ucs2_t *r;
|
|
size_t inslen;
|
|
|
|
if (!s || !ins) {
|
|
return NULL;
|
|
}
|
|
|
|
inslen = strlen(ins);
|
|
r = (smb_ucs2_t *)s;
|
|
|
|
while ((r = strchr_w(r, UCS2_CHAR(*ins)))) {
|
|
if (strncmp_wa(r, ins, inslen) == 0)
|
|
return r;
|
|
r++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Returns the length in number of wide characters.
|
|
******************************************************************/
|
|
|
|
int unistrlen(uint16 *s)
|
|
{
|
|
int len;
|
|
|
|
if (!s) {
|
|
return -1;
|
|
}
|
|
|
|
for (len=0; SVAL(s,0); s++,len++) {
|
|
;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Strcpy for unicode strings. Returns length (in num of wide chars).
|
|
Not odd align safe.
|
|
********************************************************************/
|
|
|
|
int unistrcpy(uint16 *dst, uint16 *src)
|
|
{
|
|
int num_wchars = 0;
|
|
|
|
while (SVAL(src,0)) {
|
|
*dst++ = *src++;
|
|
num_wchars++;
|
|
}
|
|
*dst = 0;
|
|
|
|
return num_wchars;
|
|
}
|
|
|
|
/**
|
|
* Samba ucs2 type to UNISTR2 conversion
|
|
*
|
|
* @param ctx Talloc context to create the dst strcture (if null) and the
|
|
* contents of the unicode string.
|
|
* @param dst UNISTR2 destination. If equals null, then it's allocated.
|
|
* @param src smb_ucs2_t source.
|
|
* @param max_len maximum number of unicode characters to copy. If equals
|
|
* null, then null-termination of src is taken
|
|
*
|
|
* @return copied UNISTR2 destination
|
|
**/
|
|
|
|
UNISTR2* ucs2_to_unistr2(TALLOC_CTX *ctx, UNISTR2* dst, smb_ucs2_t* src)
|
|
{
|
|
size_t len;
|
|
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
len = strlen_w(src);
|
|
|
|
/* allocate UNISTR2 destination if not given */
|
|
if (!dst) {
|
|
dst = TALLOC_P(ctx, UNISTR2);
|
|
if (!dst)
|
|
return NULL;
|
|
}
|
|
if (!dst->buffer) {
|
|
dst->buffer = TALLOC_ARRAY(ctx, uint16, len + 1);
|
|
if (!dst->buffer)
|
|
return NULL;
|
|
}
|
|
|
|
/* set UNISTR2 parameters */
|
|
dst->uni_max_len = len + 1;
|
|
dst->offset = 0;
|
|
dst->uni_str_len = len;
|
|
|
|
/* copy the actual unicode string */
|
|
strncpy_w(dst->buffer, src, dst->uni_max_len);
|
|
|
|
return dst;
|
|
}
|
|
|
|
/*************************************************************
|
|
ascii only toupper - saves the need for smbd to be in C locale.
|
|
*************************************************************/
|
|
|
|
int toupper_ascii(int c)
|
|
{
|
|
smb_ucs2_t uc = toupper_w(UCS2_CHAR(c));
|
|
return UCS2_TO_CHAR(uc);
|
|
}
|
|
|
|
/*************************************************************
|
|
ascii only tolower - saves the need for smbd to be in C locale.
|
|
*************************************************************/
|
|
|
|
int tolower_ascii(int c)
|
|
{
|
|
smb_ucs2_t uc = tolower_w(UCS2_CHAR(c));
|
|
return UCS2_TO_CHAR(uc);
|
|
}
|
|
|
|
/*************************************************************
|
|
ascii only isupper - saves the need for smbd to be in C locale.
|
|
*************************************************************/
|
|
|
|
int isupper_ascii(int c)
|
|
{
|
|
return isupper_w(UCS2_CHAR(c));
|
|
}
|
|
|
|
/*************************************************************
|
|
ascii only islower - saves the need for smbd to be in C locale.
|
|
*************************************************************/
|
|
|
|
int islower_ascii(int c)
|
|
{
|
|
return islower_w(UCS2_CHAR(c));
|
|
}
|