// 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 }