Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

Obsah / Utility / CHARSET / CharUTF8Read

Zdrojový kód: INCLUDE\UTIL\CHARSET.INC, UTIL\CHARSET.ASM


CharUTF8Read - Načtení znaku z bufferu ve formátu UTF-8

Funkce CharUTF8Read načte znak z bufferu ve formátu UTF-8.


; -----------------------------------------------------------------------------
;                     Read character from UTF-8 buffer
; -----------------------------------------------------------------------------
; INPUT:	ECX = remaining bytes
;		EDX = invalid character (in Unicode, 0 = default character)
;		ESI = source buffer
; OUTPUT:	EAX = Unicode character (or invalid character if no data)
;		ECX = next remaining bytes
;		ESI = next source buffer
; -----------------------------------------------------------------------------

Na vstupu funkce obsahuje registr ESI ukazatel na data ve vstupním bufferu, registr ECX počet bajtů ve vstupním bufferu a registr EDX Unicode kód znaku, který se použije v případě neplatných dat v bufferu. Na výstupu z funkce je v registru EAX navrácen Unicode kód načteného znaku (nebo neplatný kód z registru EDX, pokud nejsou k dispozici další data), v registru ESI nový ukazatel na vstupní data a v registru ECX nová velikost vstupních dat.


; ------------- Read first byte

CharUTF8Read:	jecxz	CharUTF8Read9	; no data
		xor	eax,eax		; EAX <- 0
		lodsb			; AL <- load first byte
		dec	ecx		; decrease number of bytes

; ------------- 1 Byte (7 bits, 0xxxxxxx = 0..7F)

		cmp	al,7fh		; 1 byte?
		ja	CharUTF8Read21	; more than 1 byte
		ret

Na začátku funkce je nejdříve provedena kontrola, zda jsou k dispozici další vstupní data. Pokud ne, bude navrácen obsah registru EDX jako příznak chyby. Jsou-li k dospozici další data, je načten do registru EAX další připravený bajt. Jedná-li se o bajt s hodnotou 0 až 7Fh, je jeho hodnota ihned navrácena, protože znaky v tomto rozsahu (7 bitů) jsou v kódu UTF-8 ukládány jako jeden bajt.


; ------------- Invalid bytes (80..BF, FE, FF)

CharUTF8Read21:	cmp	al,0c0h		; check byte validity
		jb	CharUTF8Read9	; invalid byte
		cmp	al,0fdh		; valid code?
		ja	CharUTF8Read	; detection byte, ignore it

Před další obsluhou je ověřena platnost bajtu. První bajt posloupnosti bajtů nesmí mít hodnotu v rozsahu 80h až 0BFh, tento rozsah hodnot je vyhrazen pro další bajty posloupnosti. Proto v případě výskystu na první pozici posloupnosti je navrácen chybový kód. Bajty s hodnotou 0FEh až 0FFh jsou rezervovány jako detekční bajty, s jejichž pomocí se rozlišuje kódování textů big-endian nebo little-endian, a proto se při načítání přeskakují a ignorují.


; ------------- 2 Bytes (11 bits, 110xxxxx 10xxxxxx = C0..DF 80..BF)

		cmp	al,0dfh		; 2-byte code?
		ja	CharUTF8Read3	; more bytes

		and	al,1fh		; mask 5 bits
		mov	ah,al		; AH <- high 5 bits
					; here can be CF = highest bit 30
CharUTF8Read22:	jecxz	CharUTF8Read9	; not enough bytes
		lodsb			; AL <- load next byte
		pushf			; push flags (CF = bit 30)
		cmp	al,80h		; is it control character?
		jb	CharUTF8Read7	; invalid character
		cmp	al,0bfh		; is it control character?
		ja	CharUTF8Read7	; invalid character
		dec	ecx		; decrease number of bytes
		shl	al,2		; rotate data bits
		popf			; pop flags (CF = bit 30)
		rcr	eax,1		; shift to right position
		shr	eax,1		; shift to right position
		ret

Je-li bajt v rozsahu 0C0h až 0DFh, jedná se o 2-bajtový kód (znak je 11-bitový). Zamaskováním nižších 5 bitů obdržíme nejvyšších 5 bitů kódu znaku, hodnota se uchová do registru AH. Dále je potřeba načíst další bajt dat - opět nejdříve s kontrolou registru ECX, zda jsou další data k dispozici a pokud ne, navrátí se chybový kód.

Pokud je k dispozici další bajt, načte se do registru AL a ověří se jeho platnost, zda leží v rozsahu 80h až 0BFh. Z bajtu se použije nižší 6 bitů, bity se sloučí s dříve načteným kódem v registru EAX. Do tohoto místa funkce skáče i z následujících obsluh včetně obsluhy načtení 31-bitového znaku, pro zajištění rozsahu čísla se proto kromě registru EAX použije i obsah příznaku CF, v němž je uchován případný nejvyšší bit 30.


; ------------- 3 Bytes (16 bits, 1110xxxx 10xxxxxx 10xxxxxx =
;					E0..EF 80..BF 80..BF
CharUTF8Read3:	cmp	al,0efh		; 3-byte code?
		ja	CharUTF8Read4	; more bytes

		and	al,0fh		; mask 4 bits
		mov	ah,al		; AH <- high 4 bits

CharUTF8Read32:	jecxz	CharUTF8Read9	; not enough bytes
		lodsb			; AL <- load next byte
		cmp	al,80h		; is it control character?
		jb	CharUTF8Read8	; invalid character
		cmp	al,0bfh		; is it control character?
		ja	CharUTF8Read8	; invalid character
		dec	ecx		; decrease number of bytes
		shl	al,2		; rotate data bits
		shl	eax,6		; free AL
		jmp	short CharUTF8Read22

Je-li bajt v rozsahu 0E0h až 0EFh, jedná se o 3-bajtový kód (znak je 16-bitový). Zamaskováním nižších 4 bitů obdržíme nejvyšší 4 bity kódu znaku, hodnota se uchová do registru AH. Dále je potřeba načíst další bajt dat - opět nejdříve s kontrolou registru ECX, zda jsou další data k dispozici a pokud ne, navrátí se chybový kód.

Pokud je k dispozici další bajt, načte se do registru AL a ověří se jeho platnost, zda leží v rozsahu 80h až 0BFh. Z bajtu se použije nižší 6 bitů, bity se sloučí s dříve načteným kódem v registru EAX.


; ------------- 4 Bytes (21 bits, 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx =
;					F0..F7 80..BF 80..BF 80..BF
CharUTF8Read4:	cmp	al,0f7h		; 4-byte code?
		ja	CharUTF8Read5	; more bytes

		and	al,7		; mask 3 bits
		mov	ah,al		; AH <- high 3 bits

CharUTF8Read42:	jecxz	CharUTF8Read9	; not enough bytes
		lodsb			; AL <- load next byte
		cmp	al,80h		; is it control character?
		jb	CharUTF8Read8	; invalid character
		cmp	al,0bfh		; is it control character?
		ja	CharUTF8Read8	; invalid character
		dec	ecx		; decrease number of bytes
		shl	al,2		; rotate data bits
		shl	eax,6		; free AL
		jmp	short CharUTF8Read32

Je-li bajt v rozsahu 0F0h až 0F7h, jedná se o 4-bajtový kód (znak je 21-bitový). Zamaskováním nižších 3 bitů obdržíme nejvyšší 3 bity kódu znaku, hodnota se uchová do registru AH. Dále je potřeba načíst další bajt dat - opět nejdříve s kontrolou registru ECX, zda jsou další data k dispozici a pokud ne, navrátí se chybový kód.

Pokud je k dispozici další bajt, načte se do registru AL a ověří se jeho platnost, zda leží v rozsahu 80h až 0BFh. Z bajtu se použije nižší 6 bitů, bity se sloučí s dříve načteným kódem v registru EAX.


; ------------- 5 Bytes (26 bits, 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
;					= F8..FB 80..BF 80..BF 80..BF 80..BF
CharUTF8Read5:	cmp	al,0fbh		; 5-byte code?
		ja	CharUTF8Read6	; more bytes

		and	al,3		; mask 2 bits
		mov	ah,al		; AH <- high 2 bits

CharUTF8Read52:	jecxz	CharUTF8Read9	; not enough bytes
		lodsb			; AL <- load next byte
		cmp	al,80h		; is it control character?
		jb	CharUTF8Read8	; invalid character
		cmp	al,0bfh		; is it control character?
		ja	CharUTF8Read8	; invalid character
		dec	ecx		; decrease number of bytes
		shl	al,2		; rotate data bits
		shl	eax,6		; free AL
		jmp	short CharUTF8Read42

Je-li bajt v rozsahu 0F8h až 0FBh, jedná se o 5-bajtový kód (znak je 26-bitový). Zamaskováním nižších 2 bitů obdržíme nejvyšší 2 bity kódu znaku, hodnota se uchová do registru AH. Dále je potřeba načíst další bajt dat - opět nejdříve s kontrolou registru ECX, zda jsou další data k dispozici a pokud ne, navrátí se chybový kód.

Pokud je k dispozici další bajt, načte se do registru AL a ověří se jeho platnost, zda leží v rozsahu 80h až 0BFh. Z bajtu se použije nižší 6 bitů, bity se sloučí s dříve načteným kódem v registru EAX.


; ------------- 6 Bytes (31 bits, 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
;			 10xxxxxx = FC..FD 80..BF 80..BF 80..BF 80..BF 80..BF

CharUTF8Read6:	and	al,1		; mask 1 bit
		mov	ah,al		; AH <- high 1 bit

		jecxz	CharUTF8Read9	; not enough bytes
		lodsb			; AL <- load next byte
		cmp	al,80h		; is it control character?
		jb	CharUTF8Read8	; invalid character
		cmp	al,0bfh		; is it control character?
		ja	CharUTF8Read8	; invalid character
		dec	ecx		; decrease number of bytes
		shl	al,2		; rotate data bits
		shl	eax,6		; free AL
		jmp	short CharUTF8Read52

Je-li bajt v rozsahu 0FCh až 0FDh, jedná se o 6-bajtový kód (znak je 31-bitový). Zamaskováním nejnižšího bitu obdržíme nejvyšší bit kódu znaku, hodnota se uchová do registru AH. Dále je potřeba načíst další bajt dat - opět nejdříve s kontrolou registru ECX, zda jsou další data k dispozici a pokud ne, navrátí se chybový kód.

Pokud je k dispozici další bajt, načte se do registru AL a ověří se jeho platnost, zda leží v rozsahu 80h až 0BFh. Z bajtu se použije nižší 6 bitů, bity se sloučí s dříve načteným kódem v registru EAX.


; ------------- Error

CharUTF8Read7:	popf			; pop flags
CharUTF8Read8:	dec	esi		; return last invalid character
CharUTF8Read9:	mov	eax,edx		; EAX <- invalid character
		or	eax,eax		; default character?
		jnz	CharUTF8Read92	; not default character
		mov	al,UNINOASC	; use default character
CharUTF8Read92:	ret

V případě neplatného znaku se navrátí ukazatel zdrojových dat (pokud byl posunut) a navrátí se v registru EAX buď neplatný znak z registru EDX nebo implicitní neplatný znak UNINOASC, pokud byl obsah registru EDX nulový.


Obsah / Utility / CHARSET / CharUTF8Read