2006-04-27 20:05:05 +04:00
/*
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2006-04-27 20:05:05 +04:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-04-27 20:05:05 +04:00
*/
# include "includes.h"
2006-05-13 23:14:12 +04:00
# include "system/locale.h"
2008-10-24 16:45:31 +04:00
2006-04-27 20:05:05 +04:00
/**
String replace .
NOTE : oldc and newc must be 7 bit characters
* */
2008-10-24 03:19:33 +04:00
_PUBLIC_ void string_replace_m ( char * s , char oldc , char newc )
2006-04-27 20:05:05 +04:00
{
2011-03-25 00:37:00 +03:00
struct smb_iconv_handle * ic = get_iconv_handle ( ) ;
2007-03-05 03:11:46 +03:00
while ( s & & * s ) {
2006-04-27 20:05:05 +04:00
size_t size ;
2011-03-25 00:37:00 +03:00
codepoint_t c = next_codepoint_handle ( ic , s , & size ) ;
2006-04-27 20:05:05 +04:00
if ( c = = oldc ) {
* s = newc ;
}
s + = size ;
}
}
/**
Convert a string to lower case , allocated with talloc
* */
2011-03-31 09:44:24 +04:00
_PUBLIC_ char * strlower_talloc_handle ( struct smb_iconv_handle * iconv_handle ,
TALLOC_CTX * ctx , const char * src )
2006-04-27 20:05:05 +04:00
{
size_t size = 0 ;
char * dest ;
2009-12-15 04:28:48 +03:00
if ( src = = NULL ) {
return NULL ;
}
2006-04-27 20:05:05 +04:00
/* this takes advantage of the fact that upper/lower can't
change the length of a character by more than 1 byte */
2007-09-08 17:27:14 +04:00
dest = talloc_array ( ctx , char , 2 * ( strlen ( src ) ) + 1 ) ;
2006-04-27 20:05:05 +04:00
if ( dest = = NULL ) {
return NULL ;
}
while ( * src ) {
size_t c_size ;
2011-03-25 00:37:00 +03:00
codepoint_t c = next_codepoint_handle ( iconv_handle , src , & c_size ) ;
2006-04-27 20:05:05 +04:00
src + = c_size ;
2008-10-24 04:51:03 +04:00
c = tolower_m ( c ) ;
2006-04-27 20:05:05 +04:00
2011-03-25 00:37:00 +03:00
c_size = push_codepoint_handle ( iconv_handle , dest + size , c ) ;
2006-04-27 20:05:05 +04:00
if ( c_size = = - 1 ) {
talloc_free ( dest ) ;
return NULL ;
}
size + = c_size ;
}
dest [ size ] = 0 ;
2007-01-10 14:47:27 +03:00
/* trim it so talloc_append_string() works */
2007-09-08 17:27:14 +04:00
dest = talloc_realloc ( ctx , dest , char , size + 1 ) ;
2007-01-10 14:47:27 +03:00
2007-05-07 17:32:34 +04:00
talloc_set_name_const ( dest , dest ) ;
2006-04-27 20:05:05 +04:00
return dest ;
}
2011-03-31 09:44:24 +04:00
_PUBLIC_ char * strlower_talloc ( TALLOC_CTX * ctx , const char * src )
{
struct smb_iconv_handle * iconv_handle = get_iconv_handle ( ) ;
return strlower_talloc_handle ( iconv_handle , ctx , src ) ;
}
2006-04-27 20:05:05 +04:00
/**
Convert a string to UPPER case , allocated with talloc
2011-03-31 09:44:24 +04:00
source length limited to n bytes , iconv handle supplied
2006-04-27 20:05:05 +04:00
* */
2011-03-31 09:44:24 +04:00
_PUBLIC_ char * strupper_talloc_n_handle ( struct smb_iconv_handle * iconv_handle ,
TALLOC_CTX * ctx , const char * src , size_t n )
2006-04-27 20:05:05 +04:00
{
size_t size = 0 ;
char * dest ;
2011-03-18 11:10:23 +03:00
2006-04-27 20:05:05 +04:00
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 */
2008-08-22 11:36:56 +04:00
dest = talloc_array ( ctx , char , 2 * ( n + 1 ) ) ;
2006-04-27 20:05:05 +04:00
if ( dest = = NULL ) {
return NULL ;
}
2015-11-24 03:49:09 +03:00
while ( n & & * src ) {
2006-04-27 20:05:05 +04:00
size_t c_size ;
2015-11-24 03:47:16 +03:00
codepoint_t c = next_codepoint_handle_ext ( iconv_handle , src , n ,
CH_UNIX , & c_size ) ;
2006-04-27 20:05:05 +04:00
src + = c_size ;
2015-11-24 03:49:09 +03:00
n - = c_size ;
2006-04-27 20:05:05 +04:00
2008-10-24 04:51:03 +04:00
c = toupper_m ( c ) ;
2006-04-27 20:05:05 +04:00
2011-03-25 00:37:00 +03:00
c_size = push_codepoint_handle ( iconv_handle , dest + size , c ) ;
2006-04-27 20:05:05 +04:00
if ( c_size = = - 1 ) {
talloc_free ( dest ) ;
return NULL ;
}
size + = c_size ;
}
dest [ size ] = 0 ;
2007-01-10 14:47:27 +03:00
/* trim it so talloc_append_string() works */
2007-09-08 17:27:14 +04:00
dest = talloc_realloc ( ctx , dest , char , size + 1 ) ;
2007-01-10 14:47:27 +03:00
2007-05-07 17:32:34 +04:00
talloc_set_name_const ( dest , dest ) ;
2006-04-27 20:05:05 +04:00
return dest ;
}
2011-03-31 09:44:24 +04:00
/**
Convert a string to UPPER case , allocated with talloc
source length limited to n bytes
* */
_PUBLIC_ char * strupper_talloc_n ( TALLOC_CTX * ctx , const char * src , size_t n )
{
struct smb_iconv_handle * iconv_handle = get_iconv_handle ( ) ;
return strupper_talloc_n_handle ( iconv_handle , ctx , src , n ) ;
}
2008-08-22 11:36:56 +04:00
/**
Convert a string to UPPER case , allocated with talloc
* */
_PUBLIC_ char * strupper_talloc ( TALLOC_CTX * ctx , const char * src )
{
return strupper_talloc_n ( ctx , src , src ? strlen ( src ) : 0 ) ;
}
2008-09-23 10:32:42 +04:00
/**
talloc_strdup ( ) a unix string to upper case .
* */
_PUBLIC_ char * talloc_strdup_upper ( TALLOC_CTX * ctx , const char * src )
{
return strupper_talloc ( ctx , src ) ;
}
2008-08-22 11:36:56 +04:00
2006-04-27 23:50:13 +04:00
/**
Find the number of ' c ' chars in a string
* */
2008-10-24 04:51:03 +04:00
_PUBLIC_ size_t count_chars_m ( const char * s , char c )
2006-04-27 23:50:13 +04:00
{
2011-03-25 00:37:00 +03:00
struct smb_iconv_handle * ic = get_iconv_handle ( ) ;
2006-04-27 23:50:13 +04:00
size_t count = 0 ;
while ( * s ) {
size_t size ;
2011-03-25 00:37:00 +03:00
codepoint_t c2 = next_codepoint_handle ( ic , s , & size ) ;
2006-04-27 23:50:13 +04:00
if ( c2 = = c ) count + + ;
s + = size ;
}
return count ;
}
2008-10-24 05:40:09 +04:00
/**
* Copy a string from a char * unix src to a dos codepage string destination .
*
2011-03-31 00:08:31 +04:00
* @ converted_size the number of bytes occupied by the string in the destination .
* @ return bool true if success .
2008-10-24 05:40:09 +04:00
*
* @ 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 .
* */
2011-05-03 06:29:12 +04:00
static bool push_ascii_string ( void * dest , const char * src , size_t dest_len , int flags , size_t * converted_size )
2008-10-24 05:40:09 +04:00
{
size_t src_len ;
2011-03-31 00:08:31 +04:00
bool ret ;
2008-10-24 05:40:09 +04:00
if ( flags & STR_UPPER ) {
char * tmpbuf = strupper_talloc ( NULL , src ) ;
if ( tmpbuf = = NULL ) {
2011-03-31 00:08:31 +04:00
return false ;
2008-10-24 05:40:09 +04:00
}
2011-05-03 06:29:12 +04:00
ret = push_ascii_string ( dest , tmpbuf , dest_len , flags & ~ STR_UPPER , converted_size ) ;
2008-10-24 05:40:09 +04:00
talloc_free ( tmpbuf ) ;
return ret ;
}
src_len = strlen ( src ) ;
if ( flags & ( STR_TERMINATE | STR_TERMINATE_ASCII ) )
src_len + + ;
2011-03-31 00:08:31 +04:00
return convert_string ( CH_UNIX , CH_DOS , src , src_len , dest , dest_len , converted_size ) ;
2008-10-24 05:40:09 +04:00
}
/**
* 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 .
* */
2011-05-03 06:29:12 +04:00
static ssize_t pull_ascii_string ( char * dest , const void * src , size_t dest_len , size_t src_len , int flags )
2008-10-24 05:40:09 +04:00
{
2011-03-31 00:08:31 +04:00
size_t size = 0 ;
2008-10-24 05:40:09 +04:00
if ( flags & ( STR_TERMINATE | STR_TERMINATE_ASCII ) ) {
if ( src_len = = ( size_t ) - 1 ) {
src_len = strlen ( ( const char * ) src ) + 1 ;
} else {
size_t len = strnlen ( ( const char * ) src , src_len ) ;
if ( len < src_len )
len + + ;
src_len = len ;
}
}
2011-03-31 00:08:31 +04:00
/* We're ignoring the return here.. */
( void ) convert_string ( CH_DOS , CH_UNIX , src , src_len , dest , dest_len , & size ) ;
2008-10-24 05:40:09 +04:00
if ( dest_len )
2011-03-31 00:08:31 +04:00
dest [ MIN ( size , dest_len - 1 ) ] = 0 ;
2008-10-24 05:40:09 +04:00
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 ) ;
2011-03-31 00:08:31 +04:00
size_t size = 0 ;
bool ret ;
2008-10-24 05:40:09 +04:00
if ( flags & STR_UPPER ) {
char * tmpbuf = strupper_talloc ( NULL , src ) ;
2011-03-31 00:08:31 +04:00
ssize_t retval ;
2008-10-24 05:40:09 +04:00
if ( tmpbuf = = NULL ) {
return - 1 ;
}
2011-03-31 00:08:31 +04:00
retval = push_ucs2 ( dest , tmpbuf , dest_len , flags & ~ STR_UPPER ) ;
2008-10-24 05:40:09 +04:00
talloc_free ( tmpbuf ) ;
2011-03-31 00:08:31 +04:00
return retval ;
2008-10-24 05:40:09 +04:00
}
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 ;
2011-03-31 00:08:31 +04:00
ret = convert_string ( CH_UNIX , CH_UTF16 , src , src_len , dest , dest_len , & size ) ;
if ( ret = = false ) {
2008-10-24 05:40:09 +04:00
return 0 ;
}
2011-03-31 00:08:31 +04:00
len + = size ;
2008-10-24 05:40:09 +04:00
2011-03-31 00:08:31 +04:00
return ( ssize_t ) len ;
2008-10-24 05:40:09 +04:00
}
/**
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 )
{
2011-03-31 00:08:31 +04:00
size_t size = 0 ;
2008-10-24 05:40:09 +04:00
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 ;
2011-03-31 00:08:31 +04:00
/* We're ignoring the return here.. */
( void ) convert_string ( CH_UTF16 , CH_UNIX , src , src_len , dest , dest_len , & size ) ;
2008-10-24 05:40:09 +04:00
if ( dest_len )
2011-03-31 00:08:31 +04:00
dest [ MIN ( size , dest_len - 1 ) ] = 0 ;
2008-10-24 05:40:09 +04:00
return src_len ;
}
/**
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 ) {
2011-03-31 00:08:31 +04:00
size_t size = 0 ;
2011-05-03 06:29:12 +04:00
if ( push_ascii_string ( dest , src , dest_len , flags , & size ) ) {
2011-03-31 00:08:31 +04:00
return ( ssize_t ) size ;
} else {
return ( ssize_t ) - 1 ;
}
2008-10-24 05:40:09 +04:00
} 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 ) {
2011-05-03 06:29:12 +04:00
return pull_ascii_string ( dest , src , dest_len , src_len , flags ) ;
2008-10-24 05:40:09 +04:00
} 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 ;
}
}