/* * BRLTTY - A background process providing access to the console screen (when in * text mode) for a blind person using a refreshable braille display. * * Copyright (C) 1995-2021 by The BRLTTY Developers. * * BRLTTY comes with ABSOLUTELY NO WARRANTY. * * This is free software, placed under the terms of the * GNU Lesser General Public License, as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any * later version. Please see the file LICENSE-LGPL for details. * * Web Page: http://brltty.app/ * * This software is maintained by Dave Mielke . */ #include "prologue.h" #include "ttb.h" #include "ttb_internal.h" #include "ttb_compile.h" static int inUcsBlock; static int getUnicodeCharacter (DataFile *file, wchar_t *character, const char *description) { DataOperand string; if (getDataOperand(file, &string, description)) { if (string.length > 2) { if ((string.characters[0] == WC_C('U')) && (string.characters[1] == WC_C('+'))) { const wchar_t *digit = &string.characters[2]; int length = string.length - 2; *character = 0; while (length) { int value; int shift; if (!isHexadecimalDigit(*digit++, &value, &shift)) break; *character <<= shift; *character |= value; length -= 1; } if (!length) return 1; } } reportDataError(file, "invalid Unicode character: %.*" PRIws, string.length, string.characters); } return 0; } static int testBrailleRepresentation (DataFile *file, wchar_t representation, unsigned char *dots) { if ((representation & ~UNICODE_CELL_MASK) == UNICODE_BRAILLE_ROW) { *dots = representation & UNICODE_CELL_MASK; return 1; } else { reportDataError(file, "invalid braille representation"); } return 0; } static DATA_OPERANDS_PROCESSOR(processEncodingOperands) { DataOperand encoding; if (getDataOperand(file, &encoding, "character encoding name")) { if (!isKeyword(WS_C("UTF-8"), encoding.characters, encoding.length)) { reportDataError(file, "unsupported character encoding: %.*" PRIws, encoding.length, encoding.characters); } } return 1; } static DATA_OPERANDS_PROCESSOR(processDelegateOperands) { DataOperand type; if (getDataOperand(file, &type, "delegate type")) { if (isKeyword(WS_C("FILE"), type.characters, type.length)) { DataOperand name; if (getDataOperand(file, &name, "file name")) { return includeDataFile(file, name.characters, name.length); } } else { return includeDataFile(file, type.characters, type.length); } } return 1; } static DATA_OPERANDS_PROCESSOR(processUcsBlockOperands) { DataOperand action; if (getDataOperand(file, &action, "UCS block action")) { const wchar_t *expected = inUcsBlock? WS_C("END"): WS_C("START"); if (isKeyword(expected, action.characters, action.length)) { inUcsBlock = !inUcsBlock; } else { reportDataError(file, "unexpected UCS block action: %.*" PRIws " (expecting %" PRIws ")", action.length, action.characters, expected); } } return 1; } static DATA_OPERANDS_PROCESSOR(processUcsCharOperands) { TextTableData *ttd = data; DataOperand string; if (getDataOperand(file, &string, "character string")) { if (string.length == 1) { DataOperand representation; if (getDataOperand(file, &representation, "braille representation")) { if (representation.length == 1) { unsigned char dots; if (testBrailleRepresentation(file, representation.characters[0], &dots)) { if (!setTextTableCharacter(ttd, string.characters[0], dots)) return 0; } } else { reportDataError(file, "multi-cell braille representation not supported"); } } } else { reportDataError(file, "multi-character string not supported"); } } return 1; } static DATA_OPERANDS_PROCESSOR(processUnicodeCharOperands) { TextTableData *ttd = data; wchar_t character; if (getUnicodeCharacter(file, &character, "character")) { wchar_t representation; if (getUnicodeCharacter(file, &representation, "braille representation")) { unsigned char dots; if (testBrailleRepresentation(file, representation, &dots)) { if (!setTextTableCharacter(ttd, character, dots)) return 0; } } } return 1; } static DATA_OPERANDS_PROCESSOR(processGnomeBrailleOperands) { if (inUcsBlock) { BEGIN_DATA_DIRECTIVE_TABLE {.name=WS_C("UCS-BLOCK"), .processor=processUcsBlockOperands}, {.name=NULL, .processor=processUcsCharOperands}, END_DATA_DIRECTIVE_TABLE return processDirectiveOperand(file, &directives, "gnome braille UCS block directive", data); } else { BEGIN_DATA_DIRECTIVE_TABLE {.name=WS_C("ENCODING"), .processor=processEncodingOperands}, // {.name=WS_C("NAME"), .processor=processNameOperands}, // {.name=WS_C("LOCALES"), .processor=processLocalesOperands}, // {.name=WS_C("UCS-SUFFIX"), .processor=processUcsSuffixOperands}, {.name=WS_C("DELEGATE"), .processor=processDelegateOperands}, // {.name=WS_C("UTF8-STRING"), .processor=processUtf8StringOperands}, {.name=WS_C("UCS-BLOCK"), .processor=processUcsBlockOperands}, {.name=WS_C("UCS-CHAR"), .processor=processUcsCharOperands}, {.name=WS_C("UNICODE-CHAR"), .processor=processUnicodeCharOperands}, // {.name=WS_C("UNKNOWN-CHAR"), .processor=processUnknownCharOperands}, END_DATA_DIRECTIVE_TABLE return processDirectiveOperand(file, &directives, "gnome braille main directive", data); } } TextTableData * processGnomeBrailleStream (FILE *stream, const char *name) { TextTableData *ttd; inUcsBlock = 0; if ((ttd = processTextTableLines(stream, name, processGnomeBrailleOperands))) { if (inUcsBlock) { reportDataError(NULL, "unterminated UCS block"); } }; return ttd; }