2005-04-17 02:20:36 +04:00
/*
* cifs_unicode : Unicode kernel case support
*
* Function :
* Convert a unicode character to upper or lower case using
* compressed tables .
*
2009-04-30 21:45:10 +04:00
* Copyright ( c ) International Business Machines Corp . , 2000 , 2009
2005-04-17 02:20:36 +04:00
*
* 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-06-28 23:44:13 +04:00
* the Free Software Foundation ; either version 2 of the License , or
2005-04-17 02:20:36 +04:00
* ( at your option ) any later version .
2007-06-28 23:44:13 +04:00
*
2005-04-17 02:20:36 +04:00
* 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-06-28 23:44:13 +04:00
* along with this program ; if not , write to the Free Software
2005-04-17 02:20:36 +04:00
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*
* Notes :
* These APIs are based on the C library functions . The semantics
* should match the C functions but with expanded size operands .
*
* The upper / lower functions are based on a table created by mkupr .
* This is a compressed table of upper and lower case conversion .
*
*/
2010-08-20 00:27:12 +04:00
# ifndef _CIFS_UNICODE_H
# define _CIFS_UNICODE_H
2005-04-17 02:20:36 +04:00
# include <asm/byteorder.h>
# include <linux/types.h>
# include <linux/nls.h>
# define UNIUPR_NOLOWER /* Example to not expand lower case tables */
2009-04-30 14:45:08 +04:00
/*
* Windows maps these to the user defined 16 bit Unicode range since they are
* reserved symbols ( along with \ and / ) , otherwise illegal to store
* in filenames in NTFS
*/
2011-04-05 23:02:37 +04:00
# define UNI_ASTERISK (__u16) ('*' + 0xF000)
2009-04-30 14:45:08 +04:00
# define UNI_QUESTION (__u16) ('?' + 0xF000)
# define UNI_COLON (__u16) (':' + 0xF000)
# define UNI_GRTRTHAN (__u16) ('>' + 0xF000)
# define UNI_LESSTHAN (__u16) ('<' + 0xF000)
# define UNI_PIPE (__u16) ('|' + 0xF000)
# define UNI_SLASH (__u16) ('\\' + 0xF000)
2014-09-25 22:20:05 +04:00
/*
* Macs use an older " SFM " mapping of the symbols above . Fortunately it does
* not conflict ( although almost does ) with the mapping above .
*/
# define SFM_ASTERISK ((__u16) 0xF021)
# define SFM_QUESTION ((__u16) 0xF025)
# define SFM_COLON ((__u16) 0xF022)
# define SFM_GRTRTHAN ((__u16) 0xF024)
# define SFM_LESSTHAN ((__u16) 0xF023)
# define SFM_PIPE ((__u16) 0xF027)
# define SFM_SLASH ((__u16) 0xF026)
2016-06-23 05:07:32 +03:00
# define SFM_PERIOD ((__u16) 0xF028)
# define SFM_SPACE ((__u16) 0xF029)
2014-09-25 22:20:05 +04:00
/*
* Mapping mechanism to use when one of the seven reserved characters is
* encountered . We can only map using one of the mechanisms at a time
* since otherwise readdir could return directory entries which we would
* not be able to open
*
* NO_MAP_UNI_RSVD = do not perform any remapping of the character
* SFM_MAP_UNI_RSVD = map reserved characters using SFM scheme ( MAC compatible )
* SFU_MAP_UNI_RSVD = map reserved characters ala SFU ( " mapchars " option )
*
*/
# define NO_MAP_UNI_RSVD 0
# define SFM_MAP_UNI_RSVD 1
# define SFU_MAP_UNI_RSVD 2
2005-04-17 02:20:36 +04:00
/* Just define what we want from uniupr.h. We don't want to define the tables
* in each source file .
*/
# ifndef UNICASERANGE_DEFINED
struct UniCaseRange {
wchar_t start ;
wchar_t end ;
signed char * table ;
} ;
# endif /* UNICASERANGE_DEFINED */
# ifndef UNIUPR_NOUPPER
extern signed char CifsUniUpperTable [ 512 ] ;
extern const struct UniCaseRange CifsUniUpperRange [ ] ;
# endif /* UNIUPR_NOUPPER */
# ifndef UNIUPR_NOLOWER
2010-08-20 00:27:12 +04:00
extern signed char CifsUniLowerTable [ 512 ] ;
extern const struct UniCaseRange CifsUniLowerRange [ ] ;
2005-04-17 02:20:36 +04:00
# endif /* UNIUPR_NOLOWER */
# ifdef __KERNEL__
2012-01-19 08:32:33 +04:00
int cifs_from_utf16 ( char * to , const __le16 * from , int tolen , int fromlen ,
2014-09-25 22:20:05 +04:00
const struct nls_table * cp , int map_type ) ;
2012-01-19 08:32:33 +04:00
int cifs_utf16_bytes ( const __le16 * from , int maxbytes ,
const struct nls_table * codepage ) ;
int cifs_strtoUTF16 ( __le16 * , const char * , int , const struct nls_table * ) ;
char * cifs_strndup_from_utf16 ( const char * src , const int maxlen ,
const bool is_unicode ,
const struct nls_table * codepage ) ;
extern int cifsConvertToUTF16 ( __le16 * target , const char * source , int maxlen ,
const struct nls_table * cp , int mapChars ) ;
2014-09-27 11:19:01 +04:00
extern int cifs_remap ( struct cifs_sb_info * cifs_sb ) ;
2011-12-26 22:58:46 +04:00
# ifdef CONFIG_CIFS_SMB2
extern __le16 * cifs_strndup_to_utf16 ( const char * src , const int maxlen ,
int * utf16_len , const struct nls_table * cp ,
int remap ) ;
# endif /* CONFIG_CIFS_SMB2 */
2005-04-17 02:20:36 +04:00
# endif
2013-09-05 16:38:11 +04:00
wchar_t cifs_toupper ( wchar_t in ) ;
2005-04-17 02:20:36 +04:00
/*
* UniStrcat : Concatenate the second string to the first
*
* Returns :
* Address of the first string
*/
2017-03-03 00:42:48 +03:00
static inline __le16 *
UniStrcat ( __le16 * ucs1 , const __le16 * ucs2 )
2005-04-17 02:20:36 +04:00
{
2017-03-03 00:42:48 +03:00
__le16 * anchor = ucs1 ; /* save a pointer to start of ucs1 */
2005-04-17 02:20:36 +04:00
while ( * ucs1 + + ) ; /* To end of first string */
ucs1 - - ; /* Return to the null */
while ( ( * ucs1 + + = * ucs2 + + ) ) ; /* copy string 2 over */
return anchor ;
}
/*
* UniStrchr : Find a character in a string
*
* Returns :
* Address of first occurrence of character in string
* or NULL if the character is not in the string
*/
static inline wchar_t *
2007-07-13 04:33:32 +04:00
UniStrchr ( const wchar_t * ucs , wchar_t uc )
2005-04-17 02:20:36 +04:00
{
while ( ( * ucs ! = uc ) & & * ucs )
ucs + + ;
if ( * ucs = = uc )
return ( wchar_t * ) ucs ;
return NULL ;
}
/*
* UniStrcmp : Compare two strings
*
* Returns :
* < 0 : First string is less than second
* = 0 : Strings are equal
* > 0 : First string is greater than second
*/
static inline int
2007-07-13 04:33:32 +04:00
UniStrcmp ( const wchar_t * ucs1 , const wchar_t * ucs2 )
2005-04-17 02:20:36 +04:00
{
while ( ( * ucs1 = = * ucs2 ) & & * ucs1 ) {
ucs1 + + ;
ucs2 + + ;
}
return ( int ) * ucs1 - ( int ) * ucs2 ;
}
/*
* UniStrcpy : Copy a string
*/
static inline wchar_t *
2007-07-13 04:33:32 +04:00
UniStrcpy ( wchar_t * ucs1 , const wchar_t * ucs2 )
2005-04-17 02:20:36 +04:00
{
wchar_t * anchor = ucs1 ; /* save the start of result string */
while ( ( * ucs1 + + = * ucs2 + + ) ) ;
return anchor ;
}
/*
* UniStrlen : Return the length of a string ( in 16 bit Unicode chars not bytes )
*/
static inline size_t
2007-07-13 04:33:32 +04:00
UniStrlen ( const wchar_t * ucs1 )
2005-04-17 02:20:36 +04:00
{
int i = 0 ;
while ( * ucs1 + + )
i + + ;
return i ;
}
/*
2007-06-28 23:44:13 +04:00
* UniStrnlen : Return the length ( in 16 bit Unicode chars not bytes ) of a
* string ( length limited )
2005-04-17 02:20:36 +04:00
*/
static inline size_t
2007-07-13 04:33:32 +04:00
UniStrnlen ( const wchar_t * ucs1 , int maxlen )
2005-04-17 02:20:36 +04:00
{
int i = 0 ;
while ( * ucs1 + + ) {
i + + ;
if ( i > = maxlen )
break ;
}
return i ;
}
/*
* UniStrncat : Concatenate length limited string
*/
static inline wchar_t *
2007-07-13 04:33:32 +04:00
UniStrncat ( wchar_t * ucs1 , const wchar_t * ucs2 , size_t n )
2005-04-17 02:20:36 +04:00
{
wchar_t * anchor = ucs1 ; /* save pointer to string 1 */
while ( * ucs1 + + ) ;
ucs1 - - ; /* point to null terminator of s1 */
while ( n - - & & ( * ucs1 = * ucs2 ) ) { /* copy s2 after s1 */
ucs1 + + ;
ucs2 + + ;
}
* ucs1 = 0 ; /* Null terminate the result */
return ( anchor ) ;
}
/*
* UniStrncmp : Compare length limited string
*/
static inline int
2007-07-13 04:33:32 +04:00
UniStrncmp ( const wchar_t * ucs1 , const wchar_t * ucs2 , size_t n )
2005-04-17 02:20:36 +04:00
{
if ( ! n )
return 0 ; /* Null strings are equal */
while ( ( * ucs1 = = * ucs2 ) & & * ucs1 & & - - n ) {
ucs1 + + ;
ucs2 + + ;
}
return ( int ) * ucs1 - ( int ) * ucs2 ;
}
/*
* UniStrncmp_le : Compare length limited string - native to little - endian
*/
static inline int
2007-07-13 04:33:32 +04:00
UniStrncmp_le ( const wchar_t * ucs1 , const wchar_t * ucs2 , size_t n )
2005-04-17 02:20:36 +04:00
{
if ( ! n )
return 0 ; /* Null strings are equal */
while ( ( * ucs1 = = __le16_to_cpu ( * ucs2 ) ) & & * ucs1 & & - - n ) {
ucs1 + + ;
ucs2 + + ;
}
return ( int ) * ucs1 - ( int ) __le16_to_cpu ( * ucs2 ) ;
}
/*
* UniStrncpy : Copy length limited string with pad
*/
static inline wchar_t *
2007-07-13 04:33:32 +04:00
UniStrncpy ( wchar_t * ucs1 , const wchar_t * ucs2 , size_t n )
2005-04-17 02:20:36 +04:00
{
wchar_t * anchor = ucs1 ;
while ( n - - & & * ucs2 ) /* Copy the strings */
* ucs1 + + = * ucs2 + + ;
n + + ;
while ( n - - ) /* Pad with nulls */
* ucs1 + + = 0 ;
return anchor ;
}
/*
* UniStrncpy_le : Copy length limited string with pad to little - endian
*/
static inline wchar_t *
2007-07-13 04:33:32 +04:00
UniStrncpy_le ( wchar_t * ucs1 , const wchar_t * ucs2 , size_t n )
2005-04-17 02:20:36 +04:00
{
wchar_t * anchor = ucs1 ;
while ( n - - & & * ucs2 ) /* Copy the strings */
* ucs1 + + = __le16_to_cpu ( * ucs2 + + ) ;
n + + ;
while ( n - - ) /* Pad with nulls */
* ucs1 + + = 0 ;
return anchor ;
}
/*
* UniStrstr : Find a string in a string
*
* Returns :
* Address of first match found
* NULL if no matching string is found
*/
static inline wchar_t *
2007-07-13 04:33:32 +04:00
UniStrstr ( const wchar_t * ucs1 , const wchar_t * ucs2 )
2005-04-17 02:20:36 +04:00
{
const wchar_t * anchor1 = ucs1 ;
const wchar_t * anchor2 = ucs2 ;
while ( * ucs1 ) {
2008-02-08 02:25:02 +03:00
if ( * ucs1 = = * ucs2 ) {
/* Partial match found */
2005-04-17 02:20:36 +04:00
ucs1 + + ;
ucs2 + + ;
} else {
if ( ! * ucs2 ) /* Match found */
return ( wchar_t * ) anchor1 ;
ucs1 = + + anchor1 ; /* No match */
ucs2 = anchor2 ;
}
}
if ( ! * ucs2 ) /* Both end together */
return ( wchar_t * ) anchor1 ; /* Match found */
return NULL ; /* No match */
}
# ifndef UNIUPR_NOUPPER
/*
* UniToupper : Convert a unicode character to upper case
*/
static inline wchar_t
UniToupper ( register wchar_t uc )
{
register const struct UniCaseRange * rp ;
2008-02-08 02:25:02 +03:00
if ( uc < sizeof ( CifsUniUpperTable ) ) {
/* Latin characters */
2005-04-17 02:20:36 +04:00
return uc + CifsUniUpperTable [ uc ] ; /* Use base tables */
} else {
rp = CifsUniUpperRange ; /* Use range tables */
while ( rp - > start ) {
if ( uc < rp - > start ) /* Before start of range */
return uc ; /* Uppercase = input */
if ( uc < = rp - > end ) /* In range */
return uc + rp - > table [ uc - rp - > start ] ;
rp + + ; /* Try next range */
}
}
return uc ; /* Past last range */
}
/*
* UniStrupr : Upper case a unicode string
*/
2013-06-25 23:03:16 +04:00
static inline __le16 *
UniStrupr ( register __le16 * upin )
2005-04-17 02:20:36 +04:00
{
2013-06-25 23:03:16 +04:00
register __le16 * up ;
2005-04-17 02:20:36 +04:00
up = upin ;
while ( * up ) { /* For all characters */
2013-06-25 23:03:16 +04:00
* up = cpu_to_le16 ( UniToupper ( le16_to_cpu ( * up ) ) ) ;
2005-04-17 02:20:36 +04:00
up + + ;
}
return upin ; /* Return input pointer */
}
# endif /* UNIUPR_NOUPPER */
# ifndef UNIUPR_NOLOWER
/*
* UniTolower : Convert a unicode character to lower case
*/
static inline wchar_t
2010-08-20 00:27:12 +04:00
UniTolower ( register wchar_t uc )
2005-04-17 02:20:36 +04:00
{
2010-08-20 00:27:12 +04:00
register const struct UniCaseRange * rp ;
2005-04-17 02:20:36 +04:00
2010-08-20 00:27:12 +04:00
if ( uc < sizeof ( CifsUniLowerTable ) ) {
2008-02-08 02:25:02 +03:00
/* Latin characters */
2010-08-20 00:27:12 +04:00
return uc + CifsUniLowerTable [ uc ] ; /* Use base tables */
2005-04-17 02:20:36 +04:00
} else {
2010-08-20 00:27:12 +04:00
rp = CifsUniLowerRange ; /* Use range tables */
2005-04-17 02:20:36 +04:00
while ( rp - > start ) {
if ( uc < rp - > start ) /* Before start of range */
return uc ; /* Uppercase = input */
if ( uc < = rp - > end ) /* In range */
return uc + rp - > table [ uc - rp - > start ] ;
rp + + ; /* Try next range */
}
}
return uc ; /* Past last range */
}
/*
* UniStrlwr : Lower case a unicode string
*/
static inline wchar_t *
2007-07-13 04:33:32 +04:00
UniStrlwr ( register wchar_t * upin )
2005-04-17 02:20:36 +04:00
{
register wchar_t * up ;
up = upin ;
while ( * up ) { /* For all characters */
* up = UniTolower ( * up ) ;
up + + ;
}
return upin ; /* Return input pointer */
}
# endif
2010-08-20 00:27:12 +04:00
# endif /* _CIFS_UNICODE_H */