Cthulhu is no longer a fork. Now it is a screen reader written in Golang.
This commit is contained in:
1 parent
a998fe67de
commit
069fc674dc
708 files changed
+112482
-532
No files matched your search
@@ -0,0 +1,210 @@
|
||||
// Package nvda2cthulhu accepts the local WebSocket protocol used by NVDA
|
||||
// compatibility bridges and routes it to Cthulhu's speech and braille queues.
|
||||
package nvda2cthulhu
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
)
|
||||
|
||||
type messagePackBinary string
|
||||
|
||||
func decodeMessagePack(reader *bytes.Reader) (any, error) {
|
||||
return decodeMessagePackDepth(reader, 0)
|
||||
}
|
||||
|
||||
func decodeMessagePackDepth(reader *bytes.Reader, depth int) (any, error) {
|
||||
if depth > 64 {
|
||||
return nil, errors.New("MessagePack nesting exceeds limit")
|
||||
}
|
||||
code, err := reader.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch {
|
||||
case code <= 0x7f:
|
||||
return int64(code), nil
|
||||
case code >= 0xe0:
|
||||
return int64(int8(code)), nil
|
||||
case code >= 0x80 && code <= 0x8f:
|
||||
return decodeMessagePackMap(reader, int(code&0x0f), depth)
|
||||
case code >= 0x90 && code <= 0x9f:
|
||||
return decodeMessagePackArray(reader, int(code&0x0f), depth)
|
||||
case code >= 0xa0 && code <= 0xbf:
|
||||
return decodeMessagePackString(reader, int(code&0x1f))
|
||||
case code == 0xc0:
|
||||
return nil, nil
|
||||
case code == 0xc2:
|
||||
return false, nil
|
||||
case code == 0xc3:
|
||||
return true, nil
|
||||
case code == 0xc4 || code == 0xc5 || code == 0xc6:
|
||||
length, err := decodeLength(reader, code, 0xc4)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value := make([]byte, length)
|
||||
if _, err := io.ReadFull(reader, value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return messagePackBinary(value), nil
|
||||
case code >= 0xca && code <= 0xcb:
|
||||
return decodeMessagePackFloat(reader, code)
|
||||
case code >= 0xcc && code <= 0xd3:
|
||||
return decodeMessagePackInteger(reader, code)
|
||||
case code == 0xd9 || code == 0xda || code == 0xdb:
|
||||
length, err := decodeLength(reader, code, 0xd9)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decodeMessagePackString(reader, length)
|
||||
case code == 0xdc || code == 0xdd:
|
||||
length, err := decodeLength(reader, code, 0xdc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decodeMessagePackArray(reader, length, depth)
|
||||
case code == 0xde || code == 0xdf:
|
||||
length, err := decodeLength(reader, code, 0xde)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decodeMessagePackMap(reader, length, depth)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported MessagePack type 0x%02x", code)
|
||||
}
|
||||
}
|
||||
|
||||
func decodeLength(reader *bytes.Reader, code, base byte) (int, error) {
|
||||
var size int
|
||||
switch code - base {
|
||||
case 0:
|
||||
size = 1
|
||||
case 1:
|
||||
size = 2
|
||||
case 2:
|
||||
size = 4
|
||||
default:
|
||||
return 0, fmt.Errorf("invalid length type 0x%02x", code)
|
||||
}
|
||||
buffer := make([]byte, size)
|
||||
if _, err := io.ReadFull(reader, buffer); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
value := uint64(0)
|
||||
for _, octet := range buffer {
|
||||
value = value<<8 | uint64(octet)
|
||||
}
|
||||
if value > uint64(maxPayload) {
|
||||
return 0, errors.New("MessagePack value exceeds 64 KiB")
|
||||
}
|
||||
return int(value), nil
|
||||
}
|
||||
|
||||
func decodeMessagePackString(reader *bytes.Reader, length int) (string, error) {
|
||||
value := make([]byte, length)
|
||||
if _, err := io.ReadFull(reader, value); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(value), nil
|
||||
}
|
||||
|
||||
func decodeMessagePackFloat(reader *bytes.Reader, code byte) (any, error) {
|
||||
var buffer []byte
|
||||
if code == 0xca {
|
||||
buffer = make([]byte, 4)
|
||||
} else {
|
||||
buffer = make([]byte, 8)
|
||||
}
|
||||
if _, err := io.ReadFull(reader, buffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if code == 0xca {
|
||||
bits := binary.BigEndian.Uint32(buffer)
|
||||
return float64(math.Float32frombits(bits)), nil
|
||||
}
|
||||
return math.Float64frombits(binary.BigEndian.Uint64(buffer)), nil
|
||||
}
|
||||
|
||||
func decodeMessagePackInteger(reader *bytes.Reader, code byte) (any, error) {
|
||||
switch code {
|
||||
case 0xcc, 0xd0:
|
||||
buffer := make([]byte, 1)
|
||||
if _, err := io.ReadFull(reader, buffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if code == 0xcc {
|
||||
return uint64(buffer[0]), nil
|
||||
}
|
||||
return int64(int8(buffer[0])), nil
|
||||
case 0xcd, 0xd1:
|
||||
buffer := make([]byte, 2)
|
||||
if _, err := io.ReadFull(reader, buffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value := binary.BigEndian.Uint16(buffer)
|
||||
if code == 0xcd {
|
||||
return uint64(value), nil
|
||||
}
|
||||
return int64(int16(value)), nil
|
||||
case 0xce, 0xd2:
|
||||
buffer := make([]byte, 4)
|
||||
if _, err := io.ReadFull(reader, buffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value := binary.BigEndian.Uint32(buffer)
|
||||
if code == 0xce {
|
||||
return uint64(value), nil
|
||||
}
|
||||
return int64(int32(value)), nil
|
||||
case 0xcf, 0xd3:
|
||||
buffer := make([]byte, 8)
|
||||
if _, err := io.ReadFull(reader, buffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value := binary.BigEndian.Uint64(buffer)
|
||||
if code == 0xcf {
|
||||
return value, nil
|
||||
}
|
||||
return int64(value), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid integer type 0x%02x", code)
|
||||
}
|
||||
}
|
||||
|
||||
func decodeMessagePackArray(reader *bytes.Reader, length, depth int) ([]any, error) {
|
||||
values := make([]any, length)
|
||||
for index := range values {
|
||||
value, err := decodeMessagePackDepth(reader, depth+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values[index] = value
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func decodeMessagePackMap(reader *bytes.Reader, length, depth int) (map[any]any, error) {
|
||||
values := make(map[any]any, length)
|
||||
for range length {
|
||||
key, err := decodeMessagePackDepth(reader, depth+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch key.(type) {
|
||||
case string, messagePackBinary:
|
||||
default:
|
||||
return nil, errors.New("MessagePack map key must be text")
|
||||
}
|
||||
value, err := decodeMessagePackDepth(reader, depth+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values[key] = value
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
Reference in new issue
Block a user