Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2023 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include <sstream>
24 : #include <stdint.h>
25 : #include <stdio.h>
26 : #include <stdlib.h>
27 : #include <string.h>
28 : #include <vector>
29 :
30 : #include <QString>
31 :
32 : #include "internal.h"
33 : #include "liblouis.h"
34 :
35 : #define WIDECHARS_ARE_UCS4
36 :
37 : #define FUNC u32_to_u8
38 : #define SRC_UNIT uint32_t
39 : #define DST_UNIT uint8_t
40 :
41 : /* Type representing a Unicode character. */
42 : typedef uint32_t ucs4_t;
43 :
44 : int
45 0 : u8_uctomb(uint8_t* s, ucs4_t uc, int n)
46 : {
47 0 : if (uc < 0x80U) {
48 0 : if (n > 0) {
49 0 : s[0] = uc;
50 0 : return 1;
51 : }
52 : /* else return -2, below. */
53 : } else {
54 : int count;
55 :
56 0 : if (uc < 0x800U) {
57 0 : count = 2;
58 0 : } else if (uc < 0x10000U) {
59 0 : if (uc < 0xd800U || uc >= 0xe000U) {
60 0 : count = 3;
61 : } else {
62 0 : return -1;
63 : }
64 0 : } else if (uc < 0x110000U) {
65 0 : count = 4;
66 : } else {
67 0 : return -1;
68 : }
69 :
70 0 : if (n >= count) {
71 0 : switch (count) { /* note: code falls through cases! */
72 0 : case 4: s[3] = 0x80 | (uc & 0x3f);
73 0 : uc = uc >> 6;
74 0 : uc |= 0x10000;
75 : // FALLTHROUGH
76 0 : case 3: s[2] = 0x80 | (uc & 0x3f);
77 0 : uc = uc >> 6;
78 0 : uc |= 0x800;
79 : // FALLTHROUGH
80 0 : case 2: s[1] = 0x80 | (uc & 0x3f);
81 0 : uc = uc >> 6;
82 0 : uc |= 0xc0;
83 0 : /*case 1:*/ s[0] = uc;
84 : }
85 0 : return count;
86 : }
87 : }
88 0 : return -2;
89 : }
90 :
91 : DST_UNIT*
92 0 : FUNC(const SRC_UNIT* s, size_t n, DST_UNIT* resultbuf, size_t* lengthp)
93 : {
94 0 : const SRC_UNIT* s_end = s + n;
95 : /* Output string accumulator. */
96 : DST_UNIT* result;
97 : size_t allocated;
98 : size_t length;
99 :
100 0 : if (resultbuf != NULL) {
101 0 : result = resultbuf;
102 0 : allocated = *lengthp;
103 : } else {
104 0 : result = NULL;
105 0 : allocated = 0;
106 : }
107 0 : length = 0;
108 : /* Invariants:
109 : result is either == resultbuf or == NULL or malloc-allocated.
110 : If length > 0, then result != NULL. */
111 :
112 0 : while (s < s_end)
113 : {
114 : ucs4_t uc;
115 : int count;
116 :
117 : /* Fetch a Unicode character from the input string. */
118 0 : uc = *s++;
119 : /* No need to call the safe variant u32_mbtouc, because
120 : u8_uctomb will verify uc anyway. */
121 :
122 : /* Store it in the output string. */
123 0 : count = u8_uctomb(result + length, uc, static_cast<int>(allocated - length));
124 0 : if (count == -1) {
125 0 : if (!(result == resultbuf || result == NULL)) {
126 0 : free(result);
127 : }
128 0 : errno = EILSEQ;
129 0 : return NULL;
130 : }
131 0 : if (count == -2) {
132 : DST_UNIT* memory;
133 :
134 0 : allocated = (allocated > 0U ? 2 * allocated : 12);
135 0 : if (length + 6 > allocated) {
136 0 : allocated = length + 6;
137 : }
138 0 : if (result == resultbuf || result == NULL) {
139 0 : memory = (DST_UNIT*)malloc(allocated * sizeof(DST_UNIT));
140 : } else {
141 : memory
142 0 : =(DST_UNIT*)realloc(result, allocated * sizeof(DST_UNIT));
143 : }
144 :
145 0 : if (memory == NULL) {
146 0 : if (!(result == resultbuf || result == NULL)) {
147 0 : free(result);
148 : }
149 0 : errno = ENOMEM;
150 0 : return NULL;
151 : }
152 0 : if (result == resultbuf && length > 0) {
153 0 : memcpy((char*)memory, (char*)result,
154 : length * sizeof(DST_UNIT));
155 : }
156 0 : result = memory;
157 0 : count = u8_uctomb(result + length, uc, static_cast<int>(allocated - length));
158 0 : if (count < 0) {
159 0 : abort();
160 : }
161 : }
162 0 : length += count;
163 : }
164 :
165 0 : if (length == 0U) {
166 0 : if (result == NULL) {
167 : /* Return a non-NULL value. NULL means error. */
168 0 : result = (DST_UNIT*)malloc(1);
169 0 : if (result == NULL) {
170 0 : errno = ENOMEM;
171 0 : return NULL;
172 : }
173 : }
174 0 : } else if (result != resultbuf && length < allocated) {
175 : /* Shrink the allocated memory if possible. */
176 : DST_UNIT* memory;
177 :
178 0 : memory = (DST_UNIT*)realloc(result, length * sizeof(DST_UNIT));
179 0 : if (memory != NULL) {
180 0 : result = memory;
181 : }
182 : }
183 :
184 0 : *lengthp = length;
185 0 : return result;
186 : }
187 :
188 : std::string table_unicode_to_ascii = "unicode-to-ascii.dis";
189 : std::string table_ascii_to_unicode = "ascii-to-unicode.dis";
190 : std::string table_for_literature = "unicode.dis,en-us-g2.ctb";
191 : std::string table_for_general = "unicode.dis,en-us-symbols.mus";
192 : std::string tables_dir = "";
193 :
194 0 : void initTables(std::string dir)
195 : {
196 0 : if (dir.empty()) {
197 0 : table_unicode_to_ascii = "unicode-to-ascii.dis";
198 0 : table_ascii_to_unicode = "ascii-to-unicode.dis";
199 0 : table_for_literature = "unicode.dis,en-us-g2.ctb";
200 0 : table_for_general = "unicode.dis,en-us-symbols.mus";
201 : } else {
202 0 : table_unicode_to_ascii = dir + "/unicode-to-ascii.dis";
203 0 : table_ascii_to_unicode = dir + "/ascii-to-unicode.dis";
204 0 : table_for_literature = dir + "/unicode.dis," + dir + "/en-us-g2.ctb";
205 0 : table_for_general = dir + "/unicode.dis," + dir + "/en-us-symbols.mus";
206 : }
207 0 : tables_dir = dir;
208 0 : }
209 :
210 0 : void updateTableForLyrics(std::string table)
211 : {
212 0 : if (tables_dir.empty()) {
213 0 : table_for_literature = "unicode.dis," + table;
214 : } else {
215 0 : table_for_literature = tables_dir + "/unicode.dis," + tables_dir + "/" + table;
216 : }
217 0 : }
218 :
219 0 : std::string braille_translate(const char* table_name, std::string txt)
220 : {
221 0 : uint8_t* outputbuf = nullptr;
222 0 : size_t outlen = 0;
223 : widechar inbuf[MAXSTRING];
224 : widechar transbuf[MAXSTRING];
225 0 : int inlen = 0;
226 0 : int translen = 0;
227 :
228 0 : inlen = _lou_extParseChars(txt.c_str(), inbuf);
229 :
230 0 : translen = MAXSTRING;
231 0 : lou_translateString(
232 : table_name, inbuf, &inlen, transbuf, &translen, NULL, NULL, 0);
233 :
234 : #ifdef WIDECHARS_ARE_UCS4
235 : //outputbuf = (uint8_t *) malloc (translen * sizeof(widechar) * sizeof (uint8_t));
236 0 : outputbuf = u32_to_u8(transbuf, translen, NULL, &outlen);
237 : #else
238 : outputbuf = u16_to_u8(transbuf, translen, NULL, &outlen);
239 : #endif
240 :
241 0 : if (!outputbuf) {
242 0 : return std::string();
243 : }
244 :
245 0 : std::string ret = std::string(outputbuf, outputbuf + outlen);
246 0 : free(outputbuf);
247 :
248 0 : return ret;
249 0 : }
250 :
251 0 : int check_tables(const char* tables)
252 : {
253 0 : if (lou_checkTable(tables) == 0) {
254 0 : return -1;
255 : } else {
256 0 : return 0;
257 : }
258 : }
259 :
260 0 : char* setTablesDir(const char* tablesdir)
261 : {
262 0 : return lou_setDataPath(tablesdir);
263 : }
264 :
265 0 : char* getTablesDir()
266 : {
267 0 : return lou_getDataPath();
268 : }
269 :
270 0 : std::vector<std::string> split_string(std::string txt, int width)
271 : {
272 0 : std::vector<std::string> lines;
273 :
274 0 : QString str = QString::fromStdString(txt);
275 :
276 0 : int len = str.length();
277 :
278 0 : if (len <= width) {
279 0 : lines.push_back(txt);
280 0 : return lines;
281 : }
282 :
283 0 : while (len > width) {
284 0 : int idx = width - 1;
285 0 : for (; idx >= 0; idx--) {
286 0 : QString ch = str.left(idx).right(1);
287 0 : if (ch == "⠀") {
288 0 : break;
289 : }
290 0 : }
291 0 : if (idx == 0 || idx == -1) {
292 0 : idx = width;
293 : }
294 :
295 0 : QString line = str.left(idx);
296 :
297 0 : str = str.right(len - idx);
298 0 : len = str.length();
299 0 : lines.push_back(line.toStdString());
300 0 : }
301 0 : if (len > 0) {
302 0 : lines.push_back(str.toStdString());
303 : }
304 0 : return lines;
305 0 : }
306 :
307 0 : std::string braille_long_translate(const char* table_name, std::string txt)
308 : {
309 0 : std::vector<std::string> lines = split_string(txt, 256);
310 :
311 0 : if (lines.size() == 0U) {
312 0 : return "";
313 : }
314 :
315 0 : std::string buffer = braille_translate(table_name, lines.front());
316 :
317 0 : for (size_t i = 1; i < lines.size(); i++) {
318 0 : std::string text = lines[i] + " ";
319 0 : buffer.append(braille_translate(table_name, text));
320 0 : }
321 0 : return buffer;
322 0 : }
323 :
324 0 : std::string braille_multi_line_translate(const char* table_name, std::string txt)
325 : {
326 0 : std::stringstream ss(txt);
327 0 : std::string line;
328 :
329 0 : std::string buffer = "";
330 :
331 0 : while (std::getline(ss, line)) {
332 0 : if (line == "[EOP]" || line == "[NP]") {
333 0 : buffer.append(line).append("\n");
334 : } else {
335 0 : std::string converted = braille_translate(table_name, line);
336 0 : buffer.append(converted).append("\n");
337 0 : }
338 : }
339 :
340 0 : return buffer;
341 0 : }
342 :
343 0 : int get_braille_text_length(const char* table_name, std::string txt)
344 : {
345 0 : std::string buffer = braille_translate(table_name, txt);
346 0 : return QString::fromStdString(txt).length();
347 0 : }
|