#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/smb_apple.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_converter.h>
typedef struct _UCSTo8BitCharMap {
u_int16_t _u;
u_int8_t _c;
} UCSTo8BitCharMap;
static const u_int16_t cp437_to_ucs2[128] = {
0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
};
static const UCSTo8BitCharMap cp437_from_ucs2[128] = {
{0x00a0, 0xff}, {0x00a1, 0xad}, {0x00a2, 0x9b}, {0x00a3, 0x9c}, {0x00a5, 0x9d}, {0x00aa, 0xa6}, {0x00ab, 0xae}, {0x00ac, 0xaa}, {0x00b0, 0xf8}, {0x00b1, 0xf1}, {0x00b2, 0xfd}, {0x00b5, 0xe6}, {0x00b7, 0xfa}, {0x00ba, 0xa7}, {0x00bb, 0xaf}, {0x00bc, 0xac}, {0x00bd, 0xab}, {0x00bf, 0xa8}, {0x00c4, 0x8e}, {0x00c5, 0x8f}, {0x00c6, 0x92}, {0x00c7, 0x80}, {0x00c9, 0x90}, {0x00d1, 0xa5}, {0x00d6, 0x99}, {0x00dc, 0x9a}, {0x00df, 0xe1}, {0x00e0, 0x85}, {0x00e1, 0xa0}, {0x00e2, 0x83}, {0x00e4, 0x84}, {0x00e5, 0x86}, {0x00e6, 0x91}, {0x00e7, 0x87}, {0x00e8, 0x8a}, {0x00e9, 0x82}, {0x00ea, 0x88}, {0x00eb, 0x89}, {0x00ec, 0x8d}, {0x00ed, 0xa1}, {0x00ee, 0x8c}, {0x00ef, 0x8b}, {0x00f1, 0xa4}, {0x00f2, 0x95}, {0x00f3, 0xa2}, {0x00f4, 0x93}, {0x00f6, 0x94}, {0x00f7, 0xf6}, {0x00f9, 0x97}, {0x00fa, 0xa3}, {0x00fb, 0x96}, {0x00fc, 0x81}, {0x00ff, 0x98}, {0x0192, 0x9f}, {0x0393, 0xe2}, {0x0398, 0xe9}, {0x03a3, 0xe4}, {0x03a6, 0xe8}, {0x03a9, 0xea}, {0x03b1, 0xe0}, {0x03b4, 0xeb}, {0x03b5, 0xee}, {0x03c0, 0xe3}, {0x03c3, 0xe5}, {0x03c4, 0xe7}, {0x03c6, 0xed}, {0x207f, 0xfc}, {0x20a7, 0x9e}, {0x2219, 0xf9}, {0x221a, 0xfb}, {0x221e, 0xec}, {0x2229, 0xef}, {0x2248, 0xf7}, {0x2261, 0xf0}, {0x2264, 0xf3}, {0x2265, 0xf2}, {0x2310, 0xa9}, {0x2320, 0xf4}, {0x2321, 0xf5}, {0x2500, 0xc4}, {0x2502, 0xb3}, {0x250c, 0xda}, {0x2510, 0xbf}, {0x2514, 0xc0}, {0x2518, 0xd9}, {0x251c, 0xc3}, {0x2524, 0xb4}, {0x252c, 0xc2}, {0x2534, 0xc1}, {0x253c, 0xc5}, {0x2550, 0xcd}, {0x2551, 0xba}, {0x2552, 0xd5}, {0x2553, 0xd6}, {0x2554, 0xc9}, {0x2555, 0xb8}, {0x2556, 0xb7}, {0x2557, 0xbb}, {0x2558, 0xd4}, {0x2559, 0xd3}, {0x255a, 0xc8}, {0x255b, 0xbe}, {0x255c, 0xbd}, {0x255d, 0xbc}, {0x255e, 0xc6}, {0x255f, 0xc7}, {0x2560, 0xcc}, {0x2561, 0xb5}, {0x2562, 0xb6}, {0x2563, 0xb9}, {0x2564, 0xd1}, {0x2565, 0xd2}, {0x2566, 0xcb}, {0x2567, 0xcf}, {0x2568, 0xd0}, {0x2569, 0xca}, {0x256a, 0xd8}, {0x256b, 0xd7}, {0x256c, 0xce}, {0x2580, 0xdf}, {0x2584, 0xdc}, {0x2588, 0xdb}, {0x258c, 0xdd}, {0x2590, 0xde}, {0x2591, 0xb0}, {0x2592, 0xb1}, {0x2593, 0xb2}, {0x25a0, 0xfe}, };
static int
codepage_to_ucs2(const u_int16_t *convtbl, const u_int8_t *src, size_t srclen,
size_t bufsize, u_int16_t *unibuf, size_t *unilen)
{
u_int8_t byte;
size_t n, r;
r = n = MIN(srclen, bufsize/2);
while (r--) {
byte = *src++;
if (byte < 0x80)
*unibuf++ = (u_int16_t)byte;
else
*unibuf++ = convtbl[byte - 0x80];
}
*unilen = n * 2;
return 0;
}
static int
UCSTo8BitEncoding(const UCSTo8BitCharMap *theTable, int numElem,
u_int16_t character, u_int8_t *ch)
{
const UCSTo8BitCharMap *p, *q, *divider;
if ((character < theTable[0]._u) || (character > theTable[numElem-1]._u)) {
return 0;
}
p = theTable;
q = p + (numElem-1);
while (p <= q) {
divider = p + ((q - p) >> 1);
if (character < divider->_u) { q = divider - 1; }
else if (character > divider->_u) { p = divider + 1; }
else { *ch = divider->_c; return 1; }
}
return 0;
}
static void
ucs2_to_codepage(const u_int16_t *convtbl, const u_int16_t *src, size_t srclen,
size_t bufsize, char *buf, size_t *buflen)
{
u_int16_t character;
u_int8_t byte;
size_t n, r;
r = n = MIN(srclen/2, bufsize);
while (r--) {
character = *src++;
if (character < 0x80)
*buf++ = (u_int8_t)character;
else if (UCSTo8BitEncoding((const UCSTo8BitCharMap *)convtbl, 128,
character, &byte))
*buf++ = byte;
else
*buf++ = '_';
}
*buflen = n;
}
int smb_convert_to_network(const char **inbuf, size_t *inbytesleft, char **outbuf,
size_t *outbytesleft, int flags, int unicode)
{
int error;
size_t inlen;
size_t outlen;
DBG_ASSERT(inbuf);
DBG_ASSERT(*inbuf);
DBG_ASSERT(outbuf);
DBG_ASSERT(*outbuf);
inlen = *inbytesleft;
outlen = 0;
flags |= UTF_PRECOMPOSED;
if (unicode) {
if (unicode && (BYTE_ORDER != LITTLE_ENDIAN))
flags |= UTF_REVERSE_ENDIAN;
error = utf8_decodestr((const u_int8_t*)*inbuf, inlen, (u_int16_t *)*outbuf, &outlen, *outbytesleft, 0, flags);
} else {
const u_int16_t *cptable = (const u_int16_t *)cp437_from_ucs2;
u_int16_t buf[256];
error = utf8_decodestr((const u_int8_t*)*inbuf, inlen, buf, &outlen, sizeof(buf), 0, flags);
if (!error)
ucs2_to_codepage(cptable, buf, outlen, *outbytesleft, *outbuf, &outlen);
}
if (error)
return error;
*inbuf += inlen;
*outbuf += outlen;
*inbytesleft -= inlen;
*outbytesleft -= outlen;
return 0;
}
int smb_convert_from_network(const char **inbuf, size_t *inbytesleft, char **outbuf,
size_t *outbytesleft, int flags, int unicode)
{
int error;
size_t inlen;
size_t outlen;
DBG_ASSERT(inbuf);
DBG_ASSERT(*inbuf);
DBG_ASSERT(outbuf);
DBG_ASSERT(*outbuf);
inlen = *inbytesleft;
outlen = 0;
flags |= UTF_DECOMPOSED | UTF_NO_NULL_TERM;
if (unicode) {
if (unicode && (BYTE_ORDER != LITTLE_ENDIAN))
flags |= UTF_REVERSE_ENDIAN;
error = utf8_encodestr((u_int16_t *)*inbuf, inlen, (u_int8_t *)*outbuf, &outlen, *outbytesleft, 0, flags);
} else {
const u_int16_t *cptable = (const u_int16_t *)cp437_to_ucs2;
u_int16_t buf[256];
codepage_to_ucs2(cptable, (u_int8_t *)*inbuf, inlen, sizeof(buf), buf, &outlen);
error = utf8_encodestr(buf, outlen, (u_int8_t *)*outbuf, &outlen, *outbytesleft, 0, flags);
}
if (error)
return error;
*inbuf += inlen;
*outbuf += outlen;
*inbytesleft -= inlen;
*outbytesleft -= outlen;
return 0;
}
size_t
smb_strtouni(u_int16_t *dst, const char *src, size_t inlen, int flags)
{
size_t outlen;
if (BYTE_ORDER != LITTLE_ENDIAN)
flags |= UTF_REVERSE_ENDIAN;
if (utf8_decodestr((u_int8_t *)src, inlen, dst, &outlen, inlen * 2, 0, flags) != 0)
outlen = 0;
if (!(flags & UTF_NO_NULL_TERM)) {
dst[outlen/2] = 0;
outlen += 2;
}
return (outlen);
}
size_t
smb_unitostr(char *dst, const u_int16_t *src, size_t inlen, size_t maxlen, int flags)
{
size_t outlen;
if (BYTE_ORDER != LITTLE_ENDIAN)
flags |= UTF_REVERSE_ENDIAN;
if (utf8_encodestr(src, inlen, (u_int8_t *)dst, &outlen, maxlen, 0, flags) != 0)
outlen = 0;
return (outlen);
}
size_t
smb_utf16_strnlen(const uint16_t *s, size_t max) {
const uint16_t *es = s + max, *p = s;
while(*p && p != es) {
p++;
}
return (uint8_t *)p - (uint8_t *)s;
}