#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/types.h>
#include <sys/sunddi.h>
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#endif
#include <sys/u8_textprep.h>
#include <smbsrv/alloc.h>
#include <sys/errno.h>
#include <smbsrv/string.h>
#include <smbsrv/cp_usascii.h>
#include <smbsrv/cp_unicode.h>
#define UNICODE_N_ENTRIES (sizeof (a_unicode) / sizeof (a_unicode[0]))
static const smb_codepage_t *current_codepage = usascii_codepage;
static boolean_t is_unicode = B_FALSE;
static smb_codepage_t *unicode_codepage = NULL;
static smb_codepage_t *smb_unicode_init(void);
char *
strsubst(char *s, char orgchar, char newchar)
{
char *p = s;
if (p == 0)
return (0);
while (*p) {
if (*p == orgchar)
*p = newchar;
++p;
}
return (s);
}
char *
strcanon(char *buf, const char *class)
{
char *p = buf;
char *q = buf;
char *r;
while (*p) {
*q++ = *p;
if ((r = strchr(class, *p)) != 0) {
while (*p == *r)
++p;
} else
++p;
}
*q = '\0';
return (buf);
}
void
smb_codepage_init(void)
{
smb_codepage_t *cp;
if (is_unicode)
return;
if ((cp = smb_unicode_init()) != NULL) {
current_codepage = cp;
unicode_codepage = cp;
is_unicode = B_TRUE;
} else {
current_codepage = usascii_codepage;
is_unicode = B_FALSE;
}
}
void
smb_codepage_fini(void)
{
if (unicode_codepage != NULL) {
MEM_FREE("unicode", unicode_codepage);
unicode_codepage = NULL;
current_codepage = NULL;
}
}
int
smb_isupper(int c)
{
uint16_t mask = is_unicode ? 0xffff : 0xff;
return (current_codepage[c & mask].ctype & CODEPAGE_ISUPPER);
}
int
smb_islower(int c)
{
uint16_t mask = is_unicode ? 0xffff : 0xff;
return (current_codepage[c & mask].ctype & CODEPAGE_ISLOWER);
}
uint32_t
smb_toupper(uint32_t c)
{
uint16_t mask = is_unicode ? 0xffff : 0xff;
return (current_codepage[c & mask].upper);
}
uint32_t
smb_tolower(uint32_t c)
{
uint16_t mask = is_unicode ? 0xffff : 0xff;
return (current_codepage[c & mask].lower);
}
char *
smb_strupr(char *s)
{
uint32_t c;
char *p = s;
while (*p) {
if (smb_isascii(*p)) {
*p = smb_toupper(*p);
p++;
} else {
if (smb_mbtowc(&c, p, MTS_MB_CHAR_MAX) < 0)
return (0);
if (c == 0)
break;
c = smb_toupper(c);
p += smb_wctomb(p, c);
}
}
return (s);
}
char *
smb_strlwr(char *s)
{
uint32_t c;
char *p = s;
while (*p) {
if (smb_isascii(*p)) {
*p = smb_tolower(*p);
p++;
} else {
if (smb_mbtowc(&c, p, MTS_MB_CHAR_MAX) < 0)
return (0);
if (c == 0)
break;
c = smb_tolower(c);
p += smb_wctomb(p, c);
}
}
return (s);
}
int
smb_isstrlwr(const char *s)
{
uint32_t c;
int n;
const char *p = s;
while (*p) {
if (smb_isascii(*p) && smb_isupper(*p))
return (0);
else {
if ((n = smb_mbtowc(&c, p, MTS_MB_CHAR_MAX)) < 0)
return (-1);
if (c == 0)
break;
if (smb_isupper(c))
return (0);
p += n;
}
}
return (1);
}
int
smb_isstrupr(const char *s)
{
uint32_t c;
int n;
const char *p = s;
while (*p) {
if (smb_isascii(*p) && smb_islower(*p))
return (0);
else {
if ((n = smb_mbtowc(&c, p, MTS_MB_CHAR_MAX)) < 0)
return (-1);
if (c == 0)
break;
if (smb_islower(c))
return (0);
p += n;
}
}
return (1);
}
int
smb_strcasecmp(const char *s1, const char *s2, size_t n)
{
int err = 0;
int rc;
rc = u8_strcmp(s1, s2, n, U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err);
if (err != 0)
return (-1);
return (rc);
}
static smb_codepage_t *
smb_unicode_init(void)
{
smb_codepage_t *unicode;
uint32_t a = 0;
uint32_t b = 0;
unicode = MEM_ZALLOC("unicode", sizeof (smb_codepage_t) << 16);
if (unicode == NULL)
return (NULL);
while (b != 0xffff) {
if (UNICODE_N_ENTRIES <= a || a_unicode[a].val > b) {
unicode[b].ctype = CODEPAGE_ISNONE;
unicode[b].upper = (smb_wchar_t)b;
unicode[b].lower = (smb_wchar_t)b;
b++;
continue;
}
switch (a_unicode[a].ctype) {
case CODEPAGE_ISNONE:
unicode[b].ctype = CODEPAGE_ISNONE;
unicode[b].upper = (smb_wchar_t)b;
unicode[b].lower = (smb_wchar_t)b;
break;
case CODEPAGE_ISUPPER:
if (a_unicode[a].lower == 0xffff) {
unicode[b].ctype = CODEPAGE_ISNONE;
unicode[b].upper = (smb_wchar_t)b;
unicode[b].lower = (smb_wchar_t)b;
} else {
unicode[b].ctype = CODEPAGE_ISUPPER;
unicode[b].upper = (smb_wchar_t)b;
unicode[b].lower = a_unicode[a].lower;
}
break;
case CODEPAGE_ISLOWER:
if (a_unicode[a].upper == 0xffff) {
unicode[b].ctype = CODEPAGE_ISNONE;
unicode[b].upper = (smb_wchar_t)b;
unicode[b].lower = (smb_wchar_t)b;
} else {
unicode[b].ctype = CODEPAGE_ISLOWER;
unicode[b].upper = a_unicode[a].upper;
unicode[b].lower = (smb_wchar_t)b;
}
break;
default:
MEM_FREE("unicode", unicode);
return (NULL);
}
a++;
b++;
};
return (unicode);
}
int
smb_unc_init(const char *path, smb_unc_t *unc)
{
char *p;
if (path == NULL || unc == NULL || (*path != '\\' && *path != '/'))
return (EINVAL);
bzero(unc, sizeof (smb_unc_t));
#if defined(_KERNEL) || defined(_FAKE_KERNEL)
unc->unc_buf = smb_mem_strdup(path);
#else
if ((unc->unc_buf = strdup(path)) == NULL)
return (ENOMEM);
#endif
(void) strsubst(unc->unc_buf, '\\', '/');
(void) strcanon(unc->unc_buf, "/");
unc->unc_server = unc->unc_buf + 1;
if (*unc->unc_server == '\0') {
smb_unc_free(unc);
return (EINVAL);
}
if ((p = strchr(unc->unc_server, '/')) == NULL) {
smb_unc_free(unc);
return (EINVAL);
}
*p++ = '\0';
unc->unc_share = p;
if (*unc->unc_share == '\0') {
smb_unc_free(unc);
return (EINVAL);
}
unc->unc_path = strchr(unc->unc_share, '/');
if ((p = unc->unc_path) == NULL)
return (0);
unc->unc_path++;
*p = '\0';
if ((p = strchr(unc->unc_path, '\0')) != NULL) {
if (*(--p) == '/')
*p = '\0';
}
return (0);
}
void
smb_unc_free(smb_unc_t *unc)
{
if (unc == NULL)
return;
#if defined(_KERNEL) || defined(_FAKE_KERNEL)
smb_mem_free(unc->unc_buf);
#else
free(unc->unc_buf);
#endif
unc->unc_buf = NULL;
}