Files
VBoxGuest/common/encoding.inc
Alexey Mikhailov 0f400bc0e0 #1 init в репу
2026-01-06 15:43:37 +03:00

460 lines
10 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
; =============================================================================
; Encoding Conversion - UTF-8 UTF-16LE
; Based on Linux VirtualBox Guest Additions implementation
; =============================================================================
; =============================================================================
; ПРОЦЕДУРА: utf8_to_utf16le
; Конвертация UTF-8 в UTF-16LE (как требует VirtualBox)
; Вход:
; utf8_ptr - указатель на UTF-8 строку
; utf8_len - длина UTF-8 строки в байтах (без null-terminator)
; utf16_ptr - указатель на выходной буфер UTF-16LE
; utf16_max - максимальный размер выходного буфера в байтах
; Возврат:
; EAX = количество байт записанных в UTF-16LE (включая BOM если есть)
; или -1 при ошибке
; =============================================================================
proc utf8_to_utf16le uses ebx ecx edx esi edi, \
utf8_ptr:dword, utf8_len:dword, utf16_ptr:dword, utf16_max:dword
DEBUGF 2, "[enc] >>> utf8_to_utf16le(src=0x%x, len=%d, dst=0x%x, max=%d)\n", \
[utf8_ptr], [utf8_len], [utf16_ptr], [utf16_max]
mov esi, [utf8_ptr]
test esi, esi
jz .error
mov edi, [utf16_ptr]
test edi, edi
jz .error
mov ecx, [utf8_len]
test ecx, ecx
jz .add_null
mov edx, [utf16_max]
cmp edx, 4 ; Минимум для BOM + null
jb .error
push edi ; Сохраним начало буфера
; Добавляем UTF-16LE BOM (0xFEFF)
mov word [edi], 0xFEFF
add edi, 2
sub edx, 2
.loop:
test ecx, ecx
jz .add_null
cmp edx, 4 ; Нужно место для символа + null
jb .buffer_full
; Читаем первый байт UTF-8
movzx eax, byte [esi]
inc esi
dec ecx
; Проверяем тип символа
cmp al, 0x80
jb .ascii ; 0xxxxxxx - ASCII (1 байт)
cmp al, 0xE0
jb .two_byte ; 110xxxxx - 2 байта
cmp al, 0xF0
jb .three_byte ; 1110xxxx - 3 байта
cmp al, 0xF8
jb .four_byte ; 11110xxx - 4 байта
; Неправильный UTF-8 - заменяем на replacement character
mov word [edi], 0xFFFD
add edi, 2
sub edx, 2
jmp .loop
.ascii:
; ASCII символ - прямая конвертация
mov word [edi], ax
add edi, 2
sub edx, 2
jmp .loop
.two_byte:
; 110xxxxx 10xxxxxx
test ecx, ecx
jz .incomplete
and eax, 0x1F ; Берем 5 бит
shl eax, 6
movzx ebx, byte [esi]
inc esi
dec ecx
and ebx, 0x3F ; Берем 6 бит
or eax, ebx
mov word [edi], ax
add edi, 2
sub edx, 2
jmp .loop
.three_byte:
; 1110xxxx 10xxxxxx 10xxxxxx
cmp ecx, 2
jb .incomplete
and eax, 0x0F ; Берем 4 бита
shl eax, 12
movzx ebx, byte [esi]
inc esi
dec ecx
and ebx, 0x3F
shl ebx, 6
or eax, ebx
movzx ebx, byte [esi]
inc esi
dec ecx
and ebx, 0x3F
or eax, ebx
mov word [edi], ax
add edi, 2
sub edx, 2
jmp .loop
.four_byte:
; 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
; Это символ вне BMP - нужна surrogate pair
cmp ecx, 3
jb .incomplete
cmp edx, 6 ; Нужно 4 байта для surrogate pair + null
jb .buffer_full
and eax, 0x07 ; Берем 3 бита
shl eax, 18
movzx ebx, byte [esi]
inc esi
dec ecx
and ebx, 0x3F
shl ebx, 12
or eax, ebx
movzx ebx, byte [esi]
inc esi
dec ecx
and ebx, 0x3F
shl ebx, 6
or eax, ebx
movzx ebx, byte [esi]
inc esi
dec ecx
and ebx, 0x3F
or eax, ebx
; Преобразуем в surrogate pair
sub eax, 0x10000
; High surrogate: 0xD800 + (code >> 10)
mov ebx, eax
shr ebx, 10
add ebx, 0xD800
mov word [edi], bx
add edi, 2
sub edx, 2
; Low surrogate: 0xDC00 + (code & 0x3FF)
and eax, 0x3FF
add eax, 0xDC00
mov word [edi], ax
add edi, 2
sub edx, 2
jmp .loop
.incomplete:
; Неполная последовательность - заменяем на replacement
mov word [edi], 0xFFFD
add edi, 2
sub edx, 2
jmp .add_null
.add_null:
; Добавляем null-terminator
cmp edx, 2
jb .buffer_full
mov word [edi], 0
add edi, 2
; Вычисляем размер
pop eax ; Начало буфера
sub edi, eax
mov eax, edi
DEBUGF 2, "[enc] Converted: %d bytes UTF-16LE (with BOM)\n", eax
ret
.buffer_full:
pop eax ; Cleanup stack
DEBUGF 1, "[enc] ERROR: Output buffer too small\n"
mov eax, -1
ret
.error:
DEBUGF 1, "[enc] ERROR: Invalid parameters\n"
mov eax, -1
ret
endp
; =============================================================================
; ПРОЦЕДУРА: utf16le_to_utf8
; Конвертация UTF-16LE в UTF-8
; Вход:
; utf16_ptr - указатель на UTF-16LE строку
; utf16_len - длина UTF-16LE в байтах (включая BOM если есть)
; utf8_ptr - указатель на выходной буфер UTF-8
; utf8_max - максимальный размер выходного буфера в байтах
; Возврат:
; EAX = количество байт записанных в UTF-8 (без null-terminator)
; или -1 при ошибке
; =============================================================================
proc utf16le_to_utf8 uses ebx ecx edx esi edi, \
utf16_ptr:dword, utf16_len:dword, utf8_ptr:dword, utf8_max:dword
DEBUGF 2, "[enc] >>> utf16le_to_utf8(src=0x%x, len=%d, dst=0x%x, max=%d)\n", \
[utf16_ptr], [utf16_len], [utf8_ptr], [utf8_max]
mov esi, [utf16_ptr]
test esi, esi
jz .error
mov edi, [utf8_ptr]
test edi, edi
jz .error
mov ecx, [utf16_len]
test ecx, ecx
jz .add_null
; Длина должна быть четной
test ecx, 1
jnz .error
mov edx, [utf8_max]
test edx, edx
jz .error
push edi ; Сохраним начало буфера
; Проверяем и пропускаем BOM если есть
cmp word [esi], 0xFEFF
jne .no_bom
add esi, 2
sub ecx, 2
.no_bom:
shr ecx, 1 ; Конвертируем байты в UTF-16 символы
.loop:
test ecx, ecx
jz .add_null
cmp edx, 4 ; Минимум для UTF-8 символа (макс 4 байта)
jb .buffer_full
; Читаем UTF-16 символ (little-endian)
movzx eax, word [esi]
add esi, 2
dec ecx
; Проверяем является ли это high surrogate
cmp ax, 0xD800
jb .not_surrogate
cmp ax, 0xDBFF
ja .check_low_surrogate
; High surrogate - нужна low surrogate
test ecx, ecx
jz .incomplete
movzx ebx, word [esi]
add esi, 2
dec ecx
; Проверяем low surrogate
cmp bx, 0xDC00
jb .invalid_surrogate
cmp bx, 0xDFFF
ja .invalid_surrogate
; Комбинируем surrogates
sub eax, 0xD800
shl eax, 10
sub ebx, 0xDC00
add eax, ebx
add eax, 0x10000
jmp .encode_utf8
.check_low_surrogate:
cmp ax, 0xDC00
jb .not_surrogate
cmp ax, 0xDFFF
ja .not_surrogate
; Одиночная low surrogate - ошибка
jmp .invalid_surrogate
.not_surrogate:
; Обычный BMP символ
.encode_utf8:
; EAX содержит Unicode code point
cmp eax, 0x80
jb .utf8_1byte
cmp eax, 0x800
jb .utf8_2byte
cmp eax, 0x10000
jb .utf8_3byte
; 4-byte UTF-8
cmp edx, 4
jb .buffer_full
mov ebx, eax
shr ebx, 18
and ebx, 0x07
or bl, 0xF0
mov byte [edi], bl
inc edi
dec edx
mov ebx, eax
shr ebx, 12
and ebx, 0x3F
or bl, 0x80
mov byte [edi], bl
inc edi
dec edx
mov ebx, eax
shr ebx, 6
and ebx, 0x3F
or bl, 0x80
mov byte [edi], bl
inc edi
dec edx
and eax, 0x3F
or al, 0x80
mov byte [edi], al
inc edi
dec edx
jmp .loop
.utf8_3byte:
cmp edx, 3
jb .buffer_full
mov ebx, eax
shr ebx, 12
and ebx, 0x0F
or bl, 0xE0
mov byte [edi], bl
inc edi
dec edx
mov ebx, eax
shr ebx, 6
and ebx, 0x3F
or bl, 0x80
mov byte [edi], bl
inc edi
dec edx
and eax, 0x3F
or al, 0x80
mov byte [edi], al
inc edi
dec edx
jmp .loop
.utf8_2byte:
cmp edx, 2
jb .buffer_full
mov ebx, eax
shr ebx, 6
and ebx, 0x1F
or bl, 0xC0
mov byte [edi], bl
inc edi
dec edx
and eax, 0x3F
or al, 0x80
mov byte [edi], al
inc edi
dec edx
jmp .loop
.utf8_1byte:
; ASCII
mov byte [edi], al
inc edi
dec edx
jmp .loop
.invalid_surrogate:
.incomplete:
; Замена на replacement character (U+FFFD = EF BF BD в UTF-8)
cmp edx, 3
jb .buffer_full
mov byte [edi], 0xEF
mov byte [edi+1], 0xBF
mov byte [edi+2], 0xBD
add edi, 3
sub edx, 3
jmp .loop
.add_null:
; Добавляем null-terminator
cmp edx, 1
jb .buffer_full
mov byte [edi], 0
inc edi
; Вычисляем размер (без null)
pop eax ; Начало буфера
sub edi, eax
dec edi ; Не считаем null
mov eax, edi
DEBUGF 2, "[enc] Converted: %d bytes UTF-8\n", eax
ret
.buffer_full:
pop eax ; Cleanup stack
DEBUGF 1, "[enc] ERROR: Output buffer too small\n"
mov eax, -1
ret
.error:
DEBUGF 1, "[enc] ERROR: Invalid parameters\n"
mov eax, -1
ret
endp