#include "aplwc_internal.h" struct string * chars_to_string(struct aplwc *aplwc, const char *chars, int len) { const uint8_t *utf8; size_t bytecount, charcount; struct string *string; uint32_t c; uint8_t b; int seqlen, extra; utf8 = (const uint8_t *)chars; seqlen = extra = 0; for(bytecount = 0, charcount = 0; ((bytecount < (unsigned int)len) || (len == -1)) && utf8[bytecount]; bytecount++){ b = utf8[bytecount]; if(extra == 0){ c = 0; if((b & 0x80) == 0){ seqlen = 0; c |= (b & 0x7F); }else if((b & 0xE0) == 0xC0){ seqlen = 1; c |= (b & 0x1F); }else if((b & 0xF0) == 0xE0){ seqlen = 2; c |= (b & 0x0F); }else if((b & 0xF8) == 0xF0){ seqlen = 3; c |= (b & 0x7); }else{ invalid: aplwc->last_error = APLWC_INVALID_UTF8; return NULL; } extra = seqlen; }else{ extra--; c <<= 6; if((b & 0xC0) == 0x80) c |= (b & 0x3F); else goto invalid; } if(extra == 0){ charcount++; switch(seqlen){ case 0: if(NEVER(c == 0) || NEVER(c > 0x7F)) goto invalid; break; case 1: if((c < 0x80) || NEVER(c > 0x07FF)) goto invalid; break; case 2: if((c < 0x0800) || NEVER(c > 0xFFFF)) goto invalid; break; case 3: if((c < 0x010000) || NEVER(c > 0x10FFFF)) goto invalid; break; } } } if(extra != 0) goto invalid; string = memory_alloc_string(&aplwc->memory, bytecount); if(string){ string->bytes = bytecount; string->chars = charcount; memcpy(string->utf8, utf8, bytecount); }else aplwc->last_error = APLWC_OUT_OF_MEMORY; return string; } uint32_t string_char(struct string *string, size_t offset) { uint32_t c; size_t len, i; c = 0; len = char_length(string, offset); switch(char_length(string, offset)){ case 1: c |= string->utf8[offset] & 0x7F; break; case 2: c |= string->utf8[offset] & 0x1F; break; case 3: c |= string->utf8[offset] & 0x0F; break; case 4: c |= string->utf8[offset] & 0x07; break; } for(i = 1; i < len; i++){ c <<= 6; c |= string->utf8[offset+i] & 0x3F; } return c; } size_t char_length(struct string *string, size_t offset) { uint8_t b; if(offset >= string->bytes) return 0; b = string->utf8[offset]; assert(!((b & 0xC0) == 0x80)); if((b & 0x80) == 0) return 1; else if((b & 0xE0) == 0xC0) return 2; else if((b & 0xF0) == 0xE0) return 3; else return 4; } int string_compare(struct string *a, struct string *b) { size_t i; for(i = 0; (i < a->bytes) && (i < b->bytes); i++){ if(a->utf8[i] < b->utf8[i]) return -1; else if(a->utf8[i] > b->utf8[i]) return 1; } if(a->bytes < b->bytes) return -1; else if(a->bytes > b->bytes) return 1; else return 0; }