📄 charcnv.c
字号:
static ssize_t pull_ascii(struct smb_iconv_convenience *ic, char *dest, const void *src, size_t dest_len, size_t src_len, int flags){ size_t ret; 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; } } ret = convert_string(ic, CH_DOS, CH_UNIX, src, src_len, dest, dest_len); if (dest_len) dest[MIN(ret, dest_len-1)] = 0; 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(struct smb_iconv_convenience *ic, void *dest, const char *src, size_t dest_len, int flags){ size_t len=0; size_t src_len = strlen(src); size_t ret; if (flags & STR_UPPER) { char *tmpbuf = strupper_talloc(NULL, src); if (tmpbuf == NULL) { return -1; } ret = push_ucs2(ic, dest, tmpbuf, dest_len, flags & ~STR_UPPER); talloc_free(tmpbuf); return ret; } 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; ret = convert_string(ic, CH_UNIX, CH_UTF16, src, src_len, dest, dest_len); if (ret == (size_t)-1) { return 0; } len += ret; return len;}/** * Copy a string from a unix char* src to a UCS2 destination, * allocating a buffer using talloc(). * * @param dest always set at least to NULL * * @returns The number of bytes occupied by the string in the destination * or -1 in case of error. **/_PUBLIC_ ssize_t push_ucs2_talloc(TALLOC_CTX *ctx, struct smb_iconv_convenience *ic, void **dest, const char *src){ size_t src_len = strlen(src)+1; *dest = NULL; return convert_string_talloc(ctx, ic, CH_UNIX, CH_UTF16, src, src_len, dest);}/** * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer using talloc * * @param dest always set at least to NULL * * @returns The number of bytes occupied by the string in the destination **/_PUBLIC_ ssize_t push_utf8_talloc(TALLOC_CTX *ctx, struct smb_iconv_convenience *ic, char **dest, const char *src){ size_t src_len = strlen(src)+1; *dest = NULL; return convert_string_talloc(ctx, ic, CH_UNIX, CH_UTF8, src, src_len, (void **)dest);}/** 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(struct smb_iconv_convenience *ic, char *dest, const void *src, size_t dest_len, size_t src_len, int flags){ size_t ret; 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; ret = convert_string(ic, CH_UTF16, CH_UNIX, src, src_len, dest, dest_len); if (dest_len) dest[MIN(ret, dest_len-1)] = 0; return src_len;}/** * Copy a string from a ASCII src to a unix char * destination, allocating a buffer using talloc * * @param dest always set at least to NULL * * @returns The number of bytes occupied by the string in the destination **/_PUBLIC_ ssize_t pull_ascii_talloc(TALLOC_CTX *ctx, struct smb_iconv_convenience *ic, char **dest, const char *src){ size_t src_len = strlen(src)+1; *dest = NULL; return convert_string_talloc(ctx, ic, CH_DOS, CH_UNIX, src, src_len, (void **)dest);}/** * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer using talloc * * @param dest always set at least to NULL * * @returns The number of bytes occupied by the string in the destination **/_PUBLIC_ ssize_t pull_ucs2_talloc(TALLOC_CTX *ctx, struct smb_iconv_convenience *ic, char **dest, const void *src){ size_t src_len = utf16_len(src); *dest = NULL; return convert_string_talloc(ctx, ic, CH_UTF16, CH_UNIX, src, src_len, (void **)dest);}/** * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer using talloc * * @param dest always set at least to NULL * * @returns The number of bytes occupied by the string in the destination **/_PUBLIC_ ssize_t pull_utf8_talloc(TALLOC_CTX *ctx, struct smb_iconv_convenience *ic, char **dest, const char *src){ size_t src_len = strlen(src)+1; *dest = NULL; return convert_string_talloc(ctx, ic, CH_UTF8, CH_UNIX, src, src_len, (void **)dest);}/** 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(struct smb_iconv_convenience *ic, void *dest, const char *src, size_t dest_len, int flags){ if (flags & STR_ASCII) { return push_ascii(ic, dest, src, dest_len, flags); } else if (flags & STR_UNICODE) { return push_ucs2(ic, 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(struct smb_iconv_convenience *ic, char *dest, const void *src, size_t dest_len, size_t src_len, int flags){ if (flags & STR_ASCII) { return pull_ascii(ic, dest, src, dest_len, src_len, flags); } else if (flags & STR_UNICODE) { return pull_ucs2(ic, 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; }}/* return the unicode codepoint for the next multi-byte CH_UNIX character in the string also return the number of bytes consumed (which tells the caller how many bytes to skip to get to the next CH_UNIX character) return INVALID_CODEPOINT if the next character cannot be converted*/_PUBLIC_ codepoint_t next_codepoint(struct smb_iconv_convenience *ic, const char *str, size_t *size){ /* it cannot occupy more than 4 bytes in UTF16 format */ uint8_t buf[4]; smb_iconv_t descriptor; size_t ilen_orig; size_t ilen; size_t olen; char *outbuf; if ((str[0] & 0x80) == 0) { *size = 1; return (codepoint_t)str[0]; } /* we assume that no multi-byte character can take more than 5 bytes. This is OK as we only support codepoints up to 1M */ ilen_orig = strnlen(str, 5); ilen = ilen_orig; descriptor = get_conv_handle(ic, CH_UNIX, CH_UTF16); if (descriptor == (smb_iconv_t)-1) { *size = 1; return INVALID_CODEPOINT; } /* this looks a little strange, but it is needed to cope with codepoints above 64k */ olen = 2; outbuf = (char *)buf; smb_iconv(descriptor, &str, &ilen, &outbuf, &olen); if (olen == 2) { olen = 4; outbuf = (char *)buf; smb_iconv(descriptor, &str, &ilen, &outbuf, &olen); if (olen == 4) { /* we didn't convert any bytes */ *size = 1; return INVALID_CODEPOINT; } olen = 4 - olen; } else { olen = 2 - olen; } *size = ilen_orig - ilen; if (olen == 2) { return (codepoint_t)SVAL(buf, 0); } if (olen == 4) { /* decode a 4 byte UTF16 character manually */ return (codepoint_t)0x10000 + (buf[2] | ((buf[3] & 0x3)<<8) | (buf[0]<<10) | ((buf[1] & 0x3)<<18)); } /* no other length is valid */ return INVALID_CODEPOINT;}/* push a single codepoint into a CH_UNIX string the target string must be able to hold the full character, which is guaranteed if it is at least 5 bytes in size. The caller may pass less than 5 bytes if they are sure the character will fit (for example, you can assume that uppercase/lowercase of a character will not add more than 1 byte) return the number of bytes occupied by the CH_UNIX character, or -1 on failure*/_PUBLIC_ ssize_t push_codepoint(struct smb_iconv_convenience *ic, char *str, codepoint_t c){ smb_iconv_t descriptor; uint8_t buf[4]; size_t ilen, olen; const char *inbuf; if (c < 128) { *str = c; return 1; } descriptor = get_conv_handle(ic, CH_UTF16, CH_UNIX); if (descriptor == (smb_iconv_t)-1) { return -1; } if (c < 0x10000) { ilen = 2; olen = 5; inbuf = (char *)buf; SSVAL(buf, 0, c); smb_iconv(descriptor, &inbuf, &ilen, &str, &olen); if (ilen != 0) { return -1; } return 5 - olen; } c -= 0x10000; buf[0] = (c>>10) & 0xFF; buf[1] = (c>>18) | 0xd8; buf[2] = c & 0xFF; buf[3] = ((c>>8) & 0x3) | 0xdc; ilen = 4; olen = 5; inbuf = (char *)buf; smb_iconv(descriptor, &inbuf, &ilen, &str, &olen); if (ilen != 0) { return -1; } return 5 - olen;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -