/* * Copyright (C) Alexander Borisov * Copyright (C) NGINX, Inc. */ #include njs_inline void njs_utf16_encode_write(uint32_t cp, u_char **start) { #ifdef NJS_HAVE_BIG_ENDIAN *(*start)++ = cp >> 8; *(*start)++ = cp & 0x00FF; #else *(*start)++ = cp & 0x00FF; *(*start)++ = cp >> 8; #endif } ssize_t njs_utf16_encode(uint32_t cp, u_char **start, const u_char *end) { if ((*start + 2) > end) { return NJS_ERROR; } if (cp < 0x10000) { njs_utf16_encode_write(cp, start); return 2; } if ((*start + 4) > end) { return NJS_ERROR; } cp -= 0x10000; njs_utf16_encode_write((0xD800 | (cp >> 0x0A)), start); njs_utf16_encode_write((0xDC00 | (cp & 0x03FF)), start); return 4; } uint32_t njs_utf16_decode(njs_unicode_decode_t *ctx, const u_char **start, const u_char *end) { uint32_t unit; unsigned lead; if (ctx->upper != 0x00) { lead = ctx->upper - 0x01; ctx->upper = 0x00; goto lead_state; } pair_state: lead = *(*start)++; if (*start >= end) { ctx->upper = lead + 0x01; return NJS_UNICODE_CONTINUE; } lead_state: #ifdef NJS_HAVE_BIG_ENDIAN unit = (lead << 8) + *(*start)++; #else unit = (*(*start)++ << 8) + lead; #endif if (ctx->codepoint != 0x00) { if (njs_surrogate_trailing(unit)) { unit = njs_surrogate_pair(ctx->codepoint, unit); ctx->codepoint = 0x00; return unit; } (*start)--; ctx->upper = lead + 0x01; ctx->codepoint = 0x00; return NJS_UNICODE_ERROR; } if (njs_surrogate_any(unit)) { if (njs_surrogate_trailing(unit)) { return NJS_UNICODE_ERROR; } ctx->codepoint = unit; if (*start >= end) { return NJS_UNICODE_CONTINUE; } goto pair_state; } return unit; }