1 /* abcio.cpp
2 *
3 * Copyright (C) 1992-2011,2015,2017-2020 Paul Boersma
4 *
5 * This code is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 *
10 * This code is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this work. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "melder.h"
20 #ifdef macintosh
21 #include <TargetConditionals.h>
22 #endif
23
24 /********** text I/O **********/
25
getInteger(MelderReadText me)26 static int64 getInteger (MelderReadText me) {
27 char buffer [41];
28 char32 c;
29 /*
30 * Look for the first numeric character.
31 */
32 for (c = MelderReadText_getChar (me); c != U'-' && ! Melder_isAsciiDecimalNumber (c) && c != U'+'; c = MelderReadText_getChar (me)) {
33 if (c == U'\0')
34 Melder_throw (U"Early end of text detected while looking for an integer (line ", MelderReadText_getLineNumber (me), U").");
35 if (c == U'!') { // end-of-line comment?
36 while ((c = MelderReadText_getChar (me)) != U'\n' && c != U'\r') {
37 if (c == 0)
38 Melder_throw (U"Early end of text detected in comment while looking for an integer (line ", MelderReadText_getLineNumber (me), U").");
39 }
40 }
41 if (c == U'\"')
42 Melder_throw (U"Found a string while looking for an integer in text (line ", MelderReadText_getLineNumber (me), U").");
43 if (c == U'<')
44 Melder_throw (U"Found an enumerated value while looking for an integer in text (line ", MelderReadText_getLineNumber (me), U").");
45 while (! Melder_isHorizontalOrVerticalSpace (c)) {
46 if (c == U'\0')
47 Melder_throw (U"Early end of text detected in comment (line ", MelderReadText_getLineNumber (me), U").");
48 c = MelderReadText_getChar (me);
49 }
50 }
51 int i = 0;
52 for (; i < 40; i ++) {
53 if (c > 127)
54 Melder_throw (U"Found strange text while looking for an integer in text (line ", MelderReadText_getLineNumber (me), U").");
55 buffer [i] = (char) (char8) c; // guarded conversion down
56 c = MelderReadText_getChar (me);
57 if (c == U'\0') { break; } // this may well be OK here
58 if (Melder_isHorizontalOrVerticalSpace (c)) break;
59 }
60 if (i >= 40)
61 Melder_throw (U"Found long text while looking for an integer in text (line ", MelderReadText_getLineNumber (me), U").");
62 buffer [i + 1] = '\0';
63 return strtoll (buffer, nullptr, 10);
64 }
65
getUnsigned(MelderReadText me)66 static uint64 getUnsigned (MelderReadText me) {
67 char buffer [41];
68 char32 c;
69 for (c = MelderReadText_getChar (me); ! Melder_isAsciiDecimalNumber (c) && c != U'+'; c = MelderReadText_getChar (me)) {
70 if (c == U'\0')
71 Melder_throw (U"Early end of text detected while looking for an unsigned integer (line ", MelderReadText_getLineNumber (me), U").");
72 if (c == U'!') { // end-of-line comment?
73 while ((c = MelderReadText_getChar (me)) != '\n' && c != '\r') {
74 if (c == U'\0')
75 Melder_throw (U"Early end of text detected in comment while looking for an unsigned integer (line ", MelderReadText_getLineNumber (me), U").");
76 }
77 }
78 if (c == U'\"')
79 Melder_throw (U"Found a string while looking for an unsigned integer in text (line ", MelderReadText_getLineNumber (me), U").");
80 if (c == U'<')
81 Melder_throw (U"Found an enumerated value while looking for an unsigned integer in text (line ", MelderReadText_getLineNumber (me), U").");
82 if (c == U'-')
83 Melder_throw (U"Found a negative value while looking for an unsigned integer in text (line ", MelderReadText_getLineNumber (me), U").");
84 while (! Melder_isHorizontalOrVerticalSpace (c)) {
85 if (c == U'\0')
86 Melder_throw (U"Early end of text detected in comment (line ", MelderReadText_getLineNumber (me), U").");
87 c = MelderReadText_getChar (me);
88 }
89 }
90 int i = 0;
91 for (i = 0; i < 40; i ++) {
92 if (c > 127)
93 Melder_throw (U"Found strange text while looking for an unsigned integer in text (line ", MelderReadText_getLineNumber (me), U").");
94 buffer [i] = (char) (char8) c; // guarded conversion down
95 c = MelderReadText_getChar (me);
96 if (c == U'\0') { break; } // this may well be OK here
97 if (Melder_isHorizontalOrVerticalSpace (c)) break;
98 }
99 if (i >= 40)
100 Melder_throw (U"Found long text while searching for an unsigned integer in text (line ", MelderReadText_getLineNumber (me), U").");
101 buffer [i + 1] = '\0';
102 return strtoull (buffer, nullptr, 10);
103 }
104
getReal(MelderReadText me)105 static double getReal (MelderReadText me) {
106 int i;
107 char buffer [41], *slash;
108 char32 c;
109 do {
110 for (c = MelderReadText_getChar (me); c != U'-' && ! Melder_isAsciiDecimalNumber (c) && c != U'+'; c = MelderReadText_getChar (me)) {
111 if (c == U'\0')
112 Melder_throw (U"Early end of text detected while looking for a real number (line ", MelderReadText_getLineNumber (me), U").");
113 if (c == U'!') { // end-of-line comment?
114 while ((c = MelderReadText_getChar (me)) != U'\n' && c != U'\r') {
115 if (c == U'\0')
116 Melder_throw (U"Early end of text detected in comment while looking for a real number (line ", MelderReadText_getLineNumber (me), U").");
117 }
118 }
119 if (c == U'\"')
120 Melder_throw (U"Found a string while looking for a real number in text (line ", MelderReadText_getLineNumber (me), U").");
121 if (c == U'<')
122 Melder_throw (U"Found an enumerated value while looking for a real number in text (line ", MelderReadText_getLineNumber (me), U").");
123 while (! Melder_isHorizontalOrVerticalSpace (c)) {
124 if (c == U'\0')
125 Melder_throw (U"Early end of text detected in comment while looking for a real number (line ", MelderReadText_getLineNumber (me), U").");
126 c = MelderReadText_getChar (me);
127 }
128 }
129 for (i = 0; i < 40; i ++) {
130 if (c > 127)
131 Melder_throw (U"Found strange text while looking for a real number in text (line ", MelderReadText_getLineNumber (me), U").");
132 buffer [i] = (char) (char8) c; // guarded conversion down
133 c = MelderReadText_getChar (me);
134 if (c == U'\0') { break; } // this may well be OK here
135 if (Melder_isHorizontalOrVerticalSpace (c)) break;
136 }
137 if (i >= 40)
138 Melder_throw (U"Found long text while searching for a real number in text (line ", MelderReadText_getLineNumber (me), U").");
139 } while (i == 0 && buffer [0] == '+'); // guard against single '+' symbols, which occur in complex numbers
140 buffer [i + 1] = '\0';
141 slash = strchr (buffer, '/');
142 if (slash) {
143 *slash = '\0';
144 double numerator = Melder_a8tof (buffer), denominator = Melder_a8tof (slash + 1);
145 if (isundef (numerator) || isundef (denominator) || denominator == 0.0)
146 return undefined;
147 return numerator / denominator;
148 }
149 return Melder_a8tof (buffer);
150 }
151
getComplex(MelderReadText me)152 static dcomplex getComplex (MelderReadText me) {
153 dcomplex result;
154 char realBuffer [41], imaginaryBuffer [41];
155 integer ireal = 0, iimag = 0;
156 char32 c;
157 bool inExponent = false, inExponentNumber = false, separatorIsMinus = false;
158 for (c = MelderReadText_getChar (me); c != U'-' && ! Melder_isAsciiDecimalNumber (c) && c != U'+'; c = MelderReadText_getChar (me)) {
159 if (c == U'\0')
160 Melder_throw (U"Early end of text detected while looking for a complex number (line ", MelderReadText_getLineNumber (me), U").");
161 if (c == U'!') { // end-of-line comment?
162 while ((c = MelderReadText_getChar (me)) != U'\n' && c != U'\r') {
163 if (c == U'\0')
164 Melder_throw (U"Early end of text detected in comment while looking for a complex number (line ", MelderReadText_getLineNumber (me), U").");
165 }
166 }
167 if (c == U'\"')
168 Melder_throw (U"Found a string while looking for a complex number in text (line ", MelderReadText_getLineNumber (me), U").");
169 if (c == U'<')
170 Melder_throw (U"Found an enumerated value while looking for a complex number in text (line ", MelderReadText_getLineNumber (me), U").");
171 while (! Melder_isHorizontalOrVerticalSpace (c)) {
172 if (c == U'\0')
173 Melder_throw (U"Early end of text detected in comment while looking for a complex number (line ", MelderReadText_getLineNumber (me), U").");
174 c = MelderReadText_getChar (me);
175 }
176 }
177 for (; ireal < 40; ireal ++) {
178 if (c > 127)
179 Melder_throw (U"Found strange text while looking for a complex number in text (line ", MelderReadText_getLineNumber (me), U").");
180 if (inExponent) {
181 if (c == U'+' || c == U'-') {
182 if (inExponentNumber) {
183 /*
184 This must be the beginning of the imaginary part.
185 */
186 separatorIsMinus = ( c == U'-' );
187 realBuffer [ireal] = U'\0';
188 break;
189 } else {
190 inExponentNumber = true;
191 }
192 } else if (Melder_isAsciiDecimalNumber (c)) {
193 inExponentNumber = true;
194 } else if (inExponentNumber) { // typically a space
195 realBuffer [ireal] = U'\0';
196 break;
197 } else {
198 Melder_throw (U"Found unexpected symbol in the exponent of a complex number (line ", MelderReadText_getLineNumber (me), U").");
199 }
200 } else if (ireal > 0 && (c == U'+' || c == U'-')) { // note: initial signs are not separators
201 separatorIsMinus = ( c == U'-' );
202 realBuffer [ireal] = U'\0';
203 break;
204 }
205 if (c == 'e' || c == 'E')
206 inExponent = true;
207 realBuffer [ireal] = (char) (char8) c; // guarded conversion down
208 c = MelderReadText_getChar (me);
209 if (c == U'\0')
210 Melder_throw (U"Missing imaginary part in complex number (line ", MelderReadText_getLineNumber (me), U").");
211 if (Melder_isHorizontalOrVerticalSpace (c))
212 Melder_throw (U"Found a space within a complex number (line ", MelderReadText_getLineNumber (me), U").");
213 }
214 if (ireal >= 40)
215 Melder_throw (U"Found long text while searching for a complex number in text (line ", MelderReadText_getLineNumber (me), U").");
216 realBuffer [ireal + 1] = '\0';
217 result. real (Melder_a8tof (realBuffer));
218 c = MelderReadText_getChar (me);
219 if (c != U'-' && ! Melder_isAsciiDecimalNumber (c) && c != U'+')
220 Melder_throw (U"Found strange text while looking for the imaginary part of a complex number in text (line ", MelderReadText_getLineNumber (me), U").");
221 if (c == U'\0')
222 Melder_throw (U"Early end of text detected while looking for the imaginary part of a complex number (line ", MelderReadText_getLineNumber (me), U").");
223 if (Melder_isHorizontalOrVerticalSpace (c))
224 Melder_throw (U"Found a space within a complex number (line ", MelderReadText_getLineNumber (me), U").");
225 if (c == U'!') { // end-of-line comment?
226 while ((c = MelderReadText_getChar (me)) != U'\n' && c != U'\r') {
227 if (c == U'\0')
228 Melder_throw (U"Early end of text detected in comment while looking for the imaginary part of a complex number (line ", MelderReadText_getLineNumber (me), U").");
229 }
230 }
231 if (c == U'\"')
232 Melder_throw (U"Found a string while looking for the imaginary part of a complex number in text (line ", MelderReadText_getLineNumber (me), U").");
233 if (c == U'<')
234 Melder_throw (U"Found an enumerated value while looking for the imaginary part of a complex number in text (line ", MelderReadText_getLineNumber (me), U").");
235 for (; iimag < 40; iimag ++) {
236 if (c > 127)
237 Melder_throw (U"Found strange text while looking for the imaginary part of a complex number in text (line ", MelderReadText_getLineNumber (me), U").");
238 imaginaryBuffer [iimag] = (char) (char8) c; // guarded conversion down
239 c = MelderReadText_getChar (me);
240 if (c == U'\0')
241 Melder_throw (U"Missing i in a complex number in text (line ", MelderReadText_getLineNumber (me), U").");
242 if (Melder_isHorizontalOrVerticalSpace (c))
243 Melder_throw (U"Missing i in a complex number in text (line ", MelderReadText_getLineNumber (me), U").");
244 if (c == U'i')
245 break;
246 }
247 if (iimag >= 40)
248 Melder_throw (U"Found long text while searching for the imaginary part of a complex number in text (line ", MelderReadText_getLineNumber (me), U").");
249 imaginaryBuffer [iimag + 1] = '\0';
250 result. imag (Melder_a8tof (imaginaryBuffer) * ( separatorIsMinus ? -1.0 : 1.0 ));
251 return result;
252 }
253
getEnum(MelderReadText me,int (* getValue)(conststring32))254 static int getEnum (MelderReadText me, int (*getValue) (conststring32)) {
255 char32 buffer [41], c;
256 for (c = MelderReadText_getChar (me); c != U'<'; c = MelderReadText_getChar (me)) {
257 if (c == U'\0')
258 Melder_throw (U"Early end of text detected while looking for an enumerated value (line ", MelderReadText_getLineNumber (me), U").");
259 if (c == U'!') { /* End-of-line comment? */
260 while ((c = MelderReadText_getChar (me)) != U'\n' && c != U'\r') {
261 if (c == U'\0')
262 Melder_throw (U"Early end of text detected in comment while looking for an enumerated value (line ", MelderReadText_getLineNumber (me), U").");
263 }
264 }
265 if (c == U'-' || Melder_isAsciiDecimalNumber (c) || c == U'+')
266 Melder_throw (U"Found a number while looking for an enumerated value in text (line ", MelderReadText_getLineNumber (me), U").");
267 if (c == U'\"')
268 Melder_throw (U"Found a string while looking for an enumerated value in text (line ", MelderReadText_getLineNumber (me), U").");
269 while (! Melder_isHorizontalOrVerticalSpace (c)) {
270 if (c == U'\0')
271 Melder_throw (U"Early end of text detected in comment while looking for an enumerated value (line ", MelderReadText_getLineNumber (me), U").");
272 c = MelderReadText_getChar (me);
273 }
274 }
275 int i = 0;
276 for (; i < 40; i ++) {
277 c = MelderReadText_getChar (me); // read past first '<'
278 if (c == U'\0')
279 Melder_throw (U"Early end of text detected while reading an enumerated value (line ", MelderReadText_getLineNumber (me), U").");
280 constexpr char32 theOnlySpaceAllowedInAnEnum = U' ';
281 if (Melder_isHorizontalOrVerticalSpace (c) && c != theOnlySpaceAllowedInAnEnum)
282 Melder_throw (U"No matching '>' while reading an enumerated value (line ", MelderReadText_getLineNumber (me), U").");
283 if (c == U'>')
284 break; // the expected closing bracket; not added to the buffer
285 buffer [i] = c;
286 }
287 if (i >= 40)
288 Melder_throw (U"Found strange text while reading an enumerated value in text (line ", MelderReadText_getLineNumber (me), U").");
289 buffer [i] = U'\0';
290 int value = getValue (buffer);
291 if (value < 0)
292 Melder_throw (U"\"", buffer, U"\" is not a value of the enumerated type.");
293 return value;
294 }
295
peekString(MelderReadText me)296 static char32 * peekString (MelderReadText me) {
297 static MelderString buffer;
298 MelderString_empty (& buffer);
299 for (char32 c = MelderReadText_getChar (me); c != U'\"'; c = MelderReadText_getChar (me)) {
300 if (c == U'\0')
301 Melder_throw (U"Early end of text detected while looking for a string (line ", MelderReadText_getLineNumber (me), U").");
302 if (c == U'!') { // end-of-line comment?
303 while ((c = MelderReadText_getChar (me)) != '\n' && c != '\r') {
304 if (c == U'\0')
305 Melder_throw (U"Early end of text detected in comment while looking for a string (line ", MelderReadText_getLineNumber (me), U").");
306 }
307 }
308 if (c == U'-' || Melder_isAsciiDecimalNumber (c) || c == U'+')
309 Melder_throw (U"Found a number while looking for a string in text (line ", MelderReadText_getLineNumber (me), U").");
310 if (c == U'<')
311 Melder_throw (U"Found an enumerated value while looking for a string in text (line ", MelderReadText_getLineNumber (me), U").");
312 while (! Melder_isHorizontalOrVerticalSpace (c)) {
313 if (c == U'\0')
314 Melder_throw (U"Early end of text detected while looking for a string (line ", MelderReadText_getLineNumber (me), U").");
315 c = MelderReadText_getChar (me);
316 }
317 }
318 for (int i = 0; 1; i ++) {
319 char32 c = MelderReadText_getChar (me); // read past first '"'
320 if (c == U'\0')
321 Melder_throw (U"Early end of text detected while reading a string (line ", MelderReadText_getLineNumber (me), U").");
322 if (c == U'\"') {
323 char32 next = MelderReadText_getChar (me);
324 if (next == U'\0') { break; } // closing quote is last character in file: OK
325 if (next != U'\"') {
326 if (Melder_isHorizontalOrVerticalSpace (next)) {
327 // closing quote is followed by whitespace: it is OK to skip this whitespace (no need to "ungetChar")
328 } else {
329 char32 kar2 [2] = { next, U'\0' };
330 Melder_throw (U"Character ", kar2, U" following quote (line ", MelderReadText_getLineNumber (me), U"). End of string or undoubled quote?");
331 }
332 break; // the expected closing double quote; not added to the buffer
333 } // else: add only one of the two quotes to the buffer
334 }
335 MelderString_appendCharacter (& buffer, c);
336 }
337 return buffer. string;
338 }
339
340 #include "enums_getText.h"
341 #include "abcio_enums.h"
342 #include "enums_getValue.h"
343 #include "abcio_enums.h"
344
texgeti8(MelderReadText text)345 int texgeti8 (MelderReadText text) {
346 try {
347 int64 externalValue = getInteger (text);
348 if (externalValue < INT8_MIN || externalValue > INT8_MAX)
349 Melder_throw (U"Value (", externalValue, U") out of range (-128 .. +127).");
350 return (int) externalValue;
351 } catch (MelderError) {
352 Melder_throw (U"Signed small integer not read from text file.");
353 }
354 }
355
texgeti16(MelderReadText text)356 int16 texgeti16 (MelderReadText text) {
357 try {
358 int64 externalValue = getInteger (text);
359 if (externalValue < INT16_MIN || externalValue > INT16_MAX)
360 Melder_throw (U"Value (", externalValue, U") out of range (-32768 .. +32767).");
361 return (int16) externalValue;
362 } catch (MelderError) {
363 Melder_throw (U"Signed short integer not read from text file.");
364 }
365 }
366
texgeti32(MelderReadText text)367 int32 texgeti32 (MelderReadText text) {
368 try {
369 int64 externalValue = getInteger (text);
370 if (externalValue < INT32_MIN || externalValue > INT32_MAX)
371 Melder_throw (U"Value (", externalValue, U") out of range (-2147483648 .. +2147483647).");
372 return (int32) externalValue;
373 } catch (MelderError) {
374 Melder_throw (U"Signed integer not read from text file.");
375 }
376 }
377
texgetinteger(MelderReadText text)378 integer texgetinteger (MelderReadText text) {
379 try {
380 int64 externalValue = getInteger (text);
381 if (externalValue < INT32_MIN || externalValue > INT32_MAX)
382 Melder_throw (U"Value (", externalValue, U") out of range (-2147483648 .. +2147483647)."); // this will change
383 return (integer) externalValue;
384 } catch (MelderError) {
385 Melder_throw (U"Signed integer not read from text file.");
386 }
387 }
388
texgetu8(MelderReadText text)389 unsigned int texgetu8 (MelderReadText text) {
390 try {
391 uint64 externalValue = getUnsigned (text);
392 if (externalValue > UINT8_MAX)
393 Melder_throw (U"Value (", externalValue, U") out of range (0 .. 255).");
394 return (unsigned int) externalValue;
395 } catch (MelderError) {
396 Melder_throw (U"Unsigned small integer not read from text file.");
397 }
398 }
399
texgetu16(MelderReadText text)400 uint16 texgetu16 (MelderReadText text) {
401 try {
402 uint64 externalValue = getUnsigned (text);
403 if (externalValue > UINT16_MAX)
404 Melder_throw (U"Value (", externalValue, U") out of range (0 .. 65535).");
405 return (uint16) externalValue;
406 } catch (MelderError) {
407 Melder_throw (U"Unsigned short integer not read from text file.");
408 }
409 }
410
texgetu32(MelderReadText text)411 uint32 texgetu32 (MelderReadText text) {
412 try {
413 uint64 externalValue = getUnsigned (text);
414 if (externalValue > UINT32_MAX)
415 Melder_throw (U"Value (", externalValue, U") out of range (0 .. 4294967295).");
416 return (uint32) externalValue;
417 } catch (MelderError) {
418 Melder_throw (U"Unsigned integer not read from text file.");
419 }
420 }
421
texgetr32(MelderReadText text)422 double texgetr32 (MelderReadText text) { return getReal (text); }
texgetr64(MelderReadText text)423 double texgetr64 (MelderReadText text) { return getReal (text); }
texgetr80(MelderReadText text)424 double texgetr80 (MelderReadText text) { return getReal (text); }
texgetc64(MelderReadText text)425 dcomplex texgetc64 (MelderReadText text) { return getComplex (text); }
texgetc128(MelderReadText text)426 dcomplex texgetc128 (MelderReadText text) { return getComplex (text); }
427
texgete8(MelderReadText text,enum_generic_getValue getValue)428 int texgete8 (MelderReadText text, enum_generic_getValue getValue) { return getEnum (text, getValue); }
texgete16(MelderReadText text,enum_generic_getValue getValue)429 int texgete16 (MelderReadText text, enum_generic_getValue getValue) { return getEnum (text, getValue); }
texgeteb(MelderReadText text)430 bool texgeteb (MelderReadText text) { return getEnum (text, (enum_generic_getValue) kBoolean_getValue); }
texgeteq(MelderReadText text)431 bool texgeteq (MelderReadText text) { return getEnum (text, (enum_generic_getValue) kQuestion_getValue); }
texgetex(MelderReadText text)432 bool texgetex (MelderReadText text) { return getEnum (text, (enum_generic_getValue) kExistence_getValue); }
texgetw16(MelderReadText text)433 autostring32 texgetw16 (MelderReadText text) { return Melder_dup (peekString (text)); }
texgetw32(MelderReadText text)434 autostring32 texgetw32 (MelderReadText text) { return Melder_dup (peekString (text)); }
435
texindent(MelderFile file)436 void texindent (MelderFile file) { file -> indent += 4; }
texexdent(MelderFile file)437 void texexdent (MelderFile file) { file -> indent -= 4; }
texresetindent(MelderFile file)438 void texresetindent (MelderFile file) { file -> indent = 0; }
439
440 #define texput_UP_TO_NINE_NULLABLE_STRINGS \
441 conststring32 s1, conststring32 s2, conststring32 s3, \
442 conststring32 s4, conststring32 s5, conststring32 s6, \
443 conststring32 s7, conststring32 s8, conststring32 s9
444
texputintro(MelderFile file,texput_UP_TO_NINE_NULLABLE_STRINGS)445 void texputintro (MelderFile file, texput_UP_TO_NINE_NULLABLE_STRINGS) {
446 if (file -> verbose) {
447 MelderFile_write (file, U"\n");
448 for (int iindent = 1; iindent <= file -> indent; iindent ++) {
449 MelderFile_write (file, U" ");
450 }
451 MelderFile_write (file,
452 s1 && s1 [0] == U'd' && s1 [1] == U'_' ? & s1 [2] : & s1 [0],
453 s2 && s2 [0] == U'd' && s2 [1] == U'_' ? & s2 [2] : & s2 [0],
454 s3 && s3 [0] == U'd' && s3 [1] == U'_' ? & s3 [2] : & s3 [0],
455 s4 && s4 [0] == U'd' && s4 [1] == U'_' ? & s4 [2] : & s4 [0],
456 s5 && s5 [0] == U'd' && s5 [1] == U'_' ? & s5 [2] : & s5 [0],
457 s6 && s6 [0] == U'd' && s6 [1] == U'_' ? & s6 [2] : & s6 [0],
458 s7 && s7 [0] == U'd' && s7 [1] == U'_' ? & s7 [2] : & s7 [0],
459 s8 && s8 [0] == U'd' && s8 [1] == U'_' ? & s8 [2] : & s8 [0],
460 s9 && s9 [0] == U'd' && s9 [1] == U'_' ? & s9 [2] : & s9 [0]);
461 }
462 file -> indent += 4;
463 }
464
465 #define PUTLEADER \
466 MelderFile_write (file, U"\n"); \
467 if (file -> verbose) { \
468 for (int iindent = 1; iindent <= file -> indent; iindent ++) { \
469 MelderFile_write (file, U" "); \
470 } \
471 MelderFile_write (file, \
472 s1 && s1 [0] == U'd' && s1 [1] == U'_' ? & s1 [2] : & s1 [0], \
473 s2 && s2 [0] == U'd' && s2 [1] == U'_' ? & s2 [2] : & s2 [0], \
474 s3 && s3 [0] == U'd' && s3 [1] == U'_' ? & s3 [2] : & s3 [0], \
475 s4 && s4 [0] == U'd' && s4 [1] == U'_' ? & s4 [2] : & s4 [0], \
476 s5 && s5 [0] == U'd' && s5 [1] == U'_' ? & s5 [2] : & s5 [0], \
477 s6 && s6 [0] == U'd' && s6 [1] == U'_' ? & s6 [2] : & s6 [0], \
478 s7 && s7 [0] == U'd' && s7 [1] == U'_' ? & s7 [2] : & s7 [0], \
479 s8 && s8 [0] == U'd' && s8 [1] == U'_' ? & s8 [2] : & s8 [0], \
480 s9 && s9 [0] == U'd' && s9 [1] == U'_' ? & s9 [2] : & s9 [0]); \
481 }
482
texputi8(MelderFile file,int i,texput_UP_TO_NINE_NULLABLE_STRINGS)483 void texputi8 (MelderFile file, int i, texput_UP_TO_NINE_NULLABLE_STRINGS) {
484 PUTLEADER
485 MelderFile_write (file, file -> verbose ? U" = " : nullptr, i, file -> verbose ? U" " : nullptr);
486 }
texputi16(MelderFile file,int i,texput_UP_TO_NINE_NULLABLE_STRINGS)487 void texputi16 (MelderFile file, int i, texput_UP_TO_NINE_NULLABLE_STRINGS) {
488 PUTLEADER
489 MelderFile_write (file, file -> verbose ? U" = " : nullptr, i, file -> verbose ? U" " : nullptr);
490 }
texputi32(MelderFile file,long i,texput_UP_TO_NINE_NULLABLE_STRINGS)491 void texputi32 (MelderFile file, long i, texput_UP_TO_NINE_NULLABLE_STRINGS) {
492 PUTLEADER
493 MelderFile_write (file, file -> verbose ? U" = " : nullptr, i, file -> verbose ? U" " : nullptr);
494 }
texputinteger(MelderFile file,integer number,texput_UP_TO_NINE_NULLABLE_STRINGS)495 void texputinteger (MelderFile file, integer number, texput_UP_TO_NINE_NULLABLE_STRINGS) {
496 PUTLEADER
497 MelderFile_write (file, file -> verbose ? U" = " : nullptr, number, file -> verbose ? U" " : nullptr);
498 }
texputu8(MelderFile file,unsigned int u,texput_UP_TO_NINE_NULLABLE_STRINGS)499 void texputu8 (MelderFile file, unsigned int u, texput_UP_TO_NINE_NULLABLE_STRINGS) {
500 PUTLEADER
501 MelderFile_write (file, file -> verbose ? U" = " : nullptr, u, file -> verbose ? U" " : nullptr);
502 }
texputu16(MelderFile file,unsigned int u,texput_UP_TO_NINE_NULLABLE_STRINGS)503 void texputu16 (MelderFile file, unsigned int u, texput_UP_TO_NINE_NULLABLE_STRINGS) {
504 PUTLEADER
505 MelderFile_write (file, file -> verbose ? U" = " : nullptr, u, file -> verbose ? U" " : nullptr);
506 }
texputu32(MelderFile file,unsigned long u,texput_UP_TO_NINE_NULLABLE_STRINGS)507 void texputu32 (MelderFile file, unsigned long u, texput_UP_TO_NINE_NULLABLE_STRINGS) {
508 PUTLEADER
509 MelderFile_write (file, file -> verbose ? U" = " : nullptr, u, file -> verbose ? U" " : nullptr);
510 }
texputr32(MelderFile file,double x,texput_UP_TO_NINE_NULLABLE_STRINGS)511 void texputr32 (MelderFile file, double x, texput_UP_TO_NINE_NULLABLE_STRINGS) {
512 PUTLEADER
513 MelderFile_write (file, file -> verbose ? U" = " : nullptr, Melder_single (x), file -> verbose ? U" " : nullptr);
514 }
texputr64(MelderFile file,double x,texput_UP_TO_NINE_NULLABLE_STRINGS)515 void texputr64 (MelderFile file, double x, texput_UP_TO_NINE_NULLABLE_STRINGS) {
516 PUTLEADER
517 MelderFile_write (file, file -> verbose ? U" = " : nullptr, x, file -> verbose ? U" " : nullptr);
518 }
texputc64(MelderFile file,dcomplex z,texput_UP_TO_NINE_NULLABLE_STRINGS)519 void texputc64 (MelderFile file, dcomplex z, texput_UP_TO_NINE_NULLABLE_STRINGS) {
520 PUTLEADER
521 MelderFile_write (file, file -> verbose ? U" = " : nullptr, z, file -> verbose ? U" " : nullptr);
522 }
texputc128(MelderFile file,dcomplex z,texput_UP_TO_NINE_NULLABLE_STRINGS)523 void texputc128 (MelderFile file, dcomplex z, texput_UP_TO_NINE_NULLABLE_STRINGS) {
524 PUTLEADER
525 MelderFile_write (file, file -> verbose ? U" = " : nullptr, z, file -> verbose ? U" " : nullptr);
526 }
texpute8(MelderFile file,int i,conststring32 (* getText)(int),texput_UP_TO_NINE_NULLABLE_STRINGS)527 void texpute8 (MelderFile file, int i, conststring32 (*getText) (int), texput_UP_TO_NINE_NULLABLE_STRINGS) {
528 PUTLEADER
529 MelderFile_write (file, file -> verbose ? U" = <" : U"<", getText (i), file -> verbose ? U"> " : U">");
530 }
texpute16(MelderFile file,int i,conststring32 (* getText)(int),texput_UP_TO_NINE_NULLABLE_STRINGS)531 void texpute16 (MelderFile file, int i, conststring32 (*getText) (int), texput_UP_TO_NINE_NULLABLE_STRINGS) {
532 PUTLEADER
533 MelderFile_write (file, file -> verbose ? U" = <" : U"<", getText (i), file -> verbose ? U"> " : U">");
534 }
texputeb(MelderFile file,bool i,texput_UP_TO_NINE_NULLABLE_STRINGS)535 void texputeb (MelderFile file, bool i, texput_UP_TO_NINE_NULLABLE_STRINGS) {
536 PUTLEADER
537 MelderFile_write (file, file -> verbose ? U" = " : nullptr, i ? U"<true>" : U"<false>", file -> verbose ? U" " : nullptr);
538 }
texputeq(MelderFile file,bool i,texput_UP_TO_NINE_NULLABLE_STRINGS)539 void texputeq (MelderFile file, bool i, texput_UP_TO_NINE_NULLABLE_STRINGS) {
540 PUTLEADER
541 MelderFile_write (file, file -> verbose ? U"? " : nullptr, i ? U"<yes>" : U"<no>", file -> verbose ? U" " : nullptr);
542 }
texputex(MelderFile file,bool i,texput_UP_TO_NINE_NULLABLE_STRINGS)543 void texputex (MelderFile file, bool i, texput_UP_TO_NINE_NULLABLE_STRINGS) {
544 PUTLEADER
545 MelderFile_write (file, file -> verbose ? U"? " : nullptr, i ? U"<exists>" : U"<absent>", file -> verbose ? U" " : nullptr);
546 }
texputs8(MelderFile file,const char * s,texput_UP_TO_NINE_NULLABLE_STRINGS)547 void texputs8 (MelderFile file, const char *s, texput_UP_TO_NINE_NULLABLE_STRINGS) {
548 PUTLEADER
549 MelderFile_write (file, file -> verbose ? U" = \"" : U"\"");
550 if (s) {
551 char c;
552 while ((c = *s ++) != '\0') {
553 MelderFile_writeCharacter (file, (char32) (char8) c);
554 if (c == U'\"') MelderFile_writeCharacter (file, (char32) (char8) c); // double any internal quotes
555 }
556 }
557 MelderFile_write (file, file -> verbose ? U"\" " : U"\"");
558 }
texputs16(MelderFile file,const char * s,texput_UP_TO_NINE_NULLABLE_STRINGS)559 void texputs16 (MelderFile file, const char *s, texput_UP_TO_NINE_NULLABLE_STRINGS) {
560 PUTLEADER
561 MelderFile_write (file, file -> verbose ? U" = \"" : U"\"");
562 if (s) {
563 char c;
564 while ((c = *s ++) != '\0') {
565 MelderFile_writeCharacter (file, (char32) (char8) c);
566 if (c == '\"') MelderFile_writeCharacter (file, (char32) (char8) c); // double any internal quotes
567 }
568 }
569 MelderFile_write (file, file -> verbose ? U"\" " : U"\"");
570 }
texputs32(MelderFile file,const char * s,texput_UP_TO_NINE_NULLABLE_STRINGS)571 void texputs32 (MelderFile file, const char *s, texput_UP_TO_NINE_NULLABLE_STRINGS) {
572 PUTLEADER
573 MelderFile_write (file, file -> verbose ? U" = \"" : U"\"");
574 if (s) {
575 char c;
576 while ((c = *s ++) != '\0') {
577 MelderFile_writeCharacter (file, (char32) (char8) c);
578 if (c == '\"') MelderFile_writeCharacter (file, (char32) (char8) c); // double any internal quotes
579 }
580 }
581 MelderFile_write (file, file -> verbose ? U"\" " : U"\"");
582 }
texputw16(MelderFile file,conststring32 s,texput_UP_TO_NINE_NULLABLE_STRINGS)583 void texputw16 (MelderFile file, conststring32 s, texput_UP_TO_NINE_NULLABLE_STRINGS) {
584 PUTLEADER
585 MelderFile_write (file, file -> verbose ? U" = \"" : U"\"");
586 if (s) {
587 char32 c;
588 while ((c = *s ++) != U'\0') {
589 MelderFile_writeCharacter (file, c);
590 if (c == U'\"') MelderFile_writeCharacter (file, c); // double any internal quotes
591 }
592 }
593 MelderFile_write (file, file -> verbose ? U"\" " : U"\"");
594 }
texputw32(MelderFile file,conststring32 s,texput_UP_TO_NINE_NULLABLE_STRINGS)595 void texputw32 (MelderFile file, conststring32 s, texput_UP_TO_NINE_NULLABLE_STRINGS) {
596 PUTLEADER
597 MelderFile_write (file, file -> verbose ? U" = \"" : U"\"");
598 if (s) {
599 char32 c;
600 while ((c = *s ++) != U'\0') {
601 MelderFile_writeCharacter (file, c);
602 if (c == U'\"') MelderFile_writeCharacter (file, c); // double any internal quotes
603 }
604 }
605 MelderFile_write (file, file -> verbose ? U"\" " : U"\"");
606 }
607
608 /********** machine-independent binary I/O **********/
609
610 /* Optimizations for machines for which some of the formats are native. */
611
612 /* On which machines is "short" a two's complement Big-Endian (MSB-first) 2-byte word? */
613
614 #if defined (macintosh) && TARGET_RT_BIG_ENDIAN == 1
615 #define binario_16bitBE 1
616 #define binario_16bitLE 0
617 #elif defined (_WIN32) || defined (macintosh) && TARGET_RT_LITTLE_ENDIAN == 1
618 #define binario_16bitBE 0
619 #define binario_16bitLE 1
620 #else
621 #define binario_16bitBE 0
622 #define binario_16bitLE 0
623 #endif
624
625 /* On which machines is "long" a two's complement Big-Endian (MSB-first) 4-byte word? */
626
627 #if defined (macintosh) && TARGET_RT_BIG_ENDIAN == 1
628 #define binario_32bitBE 1
629 #define binario_32bitLE 0
630 #elif defined (_WIN32) || defined (macintosh) && TARGET_RT_LITTLE_ENDIAN == 1
631 #define binario_32bitBE 0
632 #define binario_32bitLE 1
633 #else
634 #define binario_32bitBE 0
635 #define binario_32bitLE 0
636 #endif
637
638 /* On which machines is "float" IEEE, four bytes, Most Significant Bit first? */
639
640 #if defined (macintosh) && TARGET_RT_BIG_ENDIAN == 1
641 #define binario_floatIEEE4msb (sizeof (float) == 4)
642 #define binario_floatIEEE4lsb 0
643 #elif defined (_WIN32) || defined (macintosh) && TARGET_RT_LITTLE_ENDIAN == 1
644 #define binario_floatIEEE4msb 0
645 #define binario_floatIEEE4lsb (sizeof (float) == 4)
646 #else
647 #define binario_floatIEEE4msb 0
648 #define binario_floatIEEE4lsb 0
649 #endif
650
651 /* On which machines is "double" IEEE, eight bytes, Most Significant Bit first? */
652
653 #if defined (macintosh) && TARGET_RT_BIG_ENDIAN == 1
654 #define binario_doubleIEEE8msb (sizeof (double) == 8)
655 #define binario_doubleIEEE8lsb 0
656 #elif defined (_WIN32) || defined (macintosh) && TARGET_RT_LITTLE_ENDIAN == 1
657 #define binario_doubleIEEE8msb 0
658 #define binario_doubleIEEE8lsb (sizeof (double) == 8)
659 #else
660 #define binario_doubleIEEE8msb 0
661 #define binario_doubleIEEE8lsb 0
662 #endif
663
664 /*
665 The routines bingetr32, bingetr64, binputr32, and binputr64,
666 were implemented by Paul Boersma from the descriptions of the IEEE floating-point formats,
667 as found in the MC68881/MC68882 User's Manual by Motorola (second edition, 1989).
668 The following copyright notice only refers to the code of bingetr10 and binputr10.
669 */
670
671 /* Copyright (C) 1988-1991 Apple Computer, Inc.
672 * All rights reserved.
673 *
674 * Warranty Information
675 * Even though Apple has reviewed this software, Apple makes no warranty
676 * or representation, either express or implied, with respect to this
677 * software, its quality, accuracy, merchantability, or fitness for a
678 * particular purpose. As a result, this software is provided "as is,"
679 * and you, its user, are assuming the entire risk as to its quality
680 * and accuracy.
681 *
682 * This code may be used and freely distributed as long as it includes
683 * this copyright notice and the above warranty information.
684 *
685 * Machine-independent I/O routines for IEEE floating-point numbers.
686 *
687 * NaN's and infinities are converted to HUGE_VAL or HUGE, which
688 * happens to be infinity on IEEE machines. Unfortunately, it is
689 * impossible to preserve NaN's in a machine-independent way.
690 * Infinities are, however, preserved on IEEE machines.
691 *
692 * These routines have been tested on the following machines:
693 * Apple Macintosh, MPW 3.1 C compiler
694 * Apple Macintosh, THINK C compiler
695 * Silicon Graphics IRIS, MIPS compiler
696 * Cray X/MP and Y/MP
697 * Digital Equipment VAX
698 *
699 * Implemented by Malcolm Slaney and Ken Turkowski.
700 *
701 * Malcolm Slaney contributions during 1988-1990 include big- and little-
702 * endian file I/O, conversion to and from Motorola's extended 80-bit
703 * floating-point format, and conversions to and from IEEE single-
704 * precision floating-point format.
705 *
706 * In 1991, Ken Turkowski implemented the conversions to and from
707 * IEEE double-precision format, added more precision to the extended
708 * conversions, and accommodated conversions involving +/- infinity,
709 * NaN's, and denormalized numbers.
710 */
711
712 // QUESTION: do the following work correctly if a long is 64 bits?
713
714 # define FloatToUnsigned(f) \
715 ((unsigned long)(((long)((f) - 2147483648.0)) + 2147483647L + 1))
716
717 # define UnsignedToFloat(u) \
718 (((double)((long)((u) - 2147483647L - 1))) + 2147483648.0)
719
720 //#define FloatToUnsigned(f) (uint32) (f)
721 //#define UnsignedToFloat(u) (double) (u)
722
723 /****************************************************************
724 * Extended precision IEEE floating-point conversion routines.
725 ****************************************************************/
726
727 /*
728 * C O N V E R T T O I E E E E X T E N D E D
729 */
730
731 /*
732 * C O N V E R T F R O M I E E E E X T E N D E D
733 */
734
735 /*************** End of Apple Computer intermezzo. ***************/
736
readError(FILE * f,conststring32 text)737 static void readError (FILE *f, conststring32 text) {
738 Melder_throw (feof (f) ? U"Reached end of file" : U"Error in file", U" while trying to read ", text);
739 }
740
writeError(conststring32 text)741 static void writeError (conststring32 text) {
742 Melder_throw (U"Error in file while trying to write ", text);
743 }
744
bingetu8(FILE * f)745 unsigned int bingetu8 (FILE *f) {
746 try {
747 int externalValue = getc (f); // either -1 (EOF) or in the range 0..255
748 if (externalValue < 0) readError (f, U"a byte.");
749 return (unsigned int) externalValue;
750 } catch (MelderError) {
751 Melder_throw (U"Unsigned integer not read from 1 byte in binary file.");
752 }
753 }
754
binputu8(unsigned int u,FILE * f)755 void binputu8 (unsigned int u, FILE *f) {
756 try {
757 if (putc ((int) u, f) < 0) writeError (U"a byte.");
758 } catch (MelderError) {
759 Melder_throw (U"Unsigned integer not written to 1 byte in binary file.");
760 }
761 }
762
bingeti8(FILE * f)763 int bingeti8 (FILE *f) {
764 try {
765 int externalValue = getc (f);
766 if (externalValue < 0) readError (f, U"a byte.");
767 return (signed char) externalValue; // this converts e.g. 200 to -56
768 } catch (MelderError) {
769 Melder_throw (U"Signed integer not read from 1 byte in binary file.");
770 }
771 }
772
binputi8(int u,FILE * f)773 void binputi8 (int u, FILE *f) {
774 try {
775 if (putc (u, f) < 0) writeError (U"a byte.");
776 } catch (MelderError) {
777 Melder_throw (U"Signed integer not written to 1 byte in binary file.");
778 }
779 }
780
bingetbool8(FILE * f)781 bool bingetbool8 (FILE *f) {
782 try {
783 int externalValue = getc (f);
784 if (externalValue < 0) readError (f, U"a byte.");
785 return (bool) externalValue; // this converts e.g. 200 to true
786 } catch (MelderError) {
787 Melder_throw (U"Boolean not read from 1 byte in binary file.");
788 }
789 }
790
binputbool8(bool value,FILE * f)791 void binputbool8 (bool value, FILE *f) {
792 try {
793 if (putc (value, f) < 0) writeError (U"a byte.");
794 } catch (MelderError) {
795 Melder_throw (U"Boolean not written to 1 byte in binary file.");
796 }
797 }
798
bingete8(FILE * f,int min,int max,conststring32 type)799 int bingete8 (FILE *f, int min, int max, conststring32 type) {
800 try {
801 int externalValue = getc (f);
802 if (externalValue < 0) readError (f, U"a byte.");
803 int result = (signed char) externalValue; // this converts e.g. 200 to -56, so the enumerated type is signed
804 if (result < min || result > max)
805 Melder_throw (result, U" is not a value of enumerated type <", type, U">.");
806 return result;
807 } catch (MelderError) {
808 Melder_throw (U"Enumerated type not read from 1 byte in binary file.");
809 }
810 }
811
binpute8(int value,FILE * f)812 void binpute8 (int value, FILE *f) {
813 try {
814 if (putc (value, f) < 0) writeError (U"a byte.");
815 } catch (MelderError) {
816 Melder_throw (U"Enumerated type not written to 1 byte in binary file.");
817 }
818 }
819
820 static int bitsInReadBuffer = 0;
821 static unsigned char readBuffer;
822
823 #define macro_bingetb(nbits) \
824 unsigned int bingetb##nbits (FILE *f) { \
825 if (bitsInReadBuffer < nbits) { \
826 int externalValue = fgetc (f); \
827 if (externalValue < 0) readError (f, U"a bit."); \
828 readBuffer = (unsigned char) externalValue; \
829 bitsInReadBuffer = 8; \
830 } \
831 unsigned char result = (unsigned char) ((uint32) readBuffer << (8 - bitsInReadBuffer)); \
832 bitsInReadBuffer -= nbits; \
833 return result >> (8 - nbits); \
834 }
835 macro_bingetb (1)
836 macro_bingetb (2)
837 macro_bingetb (3)
838 macro_bingetb (4)
839 macro_bingetb (5)
840 macro_bingetb (6)
841 macro_bingetb (7)
842
bingetb(FILE * f)843 void bingetb (FILE *f) { (void) f; bitsInReadBuffer = 0; }
844
bingeti16(FILE * f)845 int16 bingeti16 (FILE *f) {
846 try {
847 if (binario_16bitBE && Melder_debug != 18) {
848 int16 s;
849 if (fread (& s, sizeof (int16), 1, f) != 1) readError (f, U"a signed 16-bit integer.");
850 return s;
851 } else {
852 uint8 bytes [2];
853 if (fread (bytes, sizeof (uint8), 2, f) != 2) readError (f, U"two bytes.");
854 return (int16) // reinterpret sign bit
855 ((uint16) ((uint16) bytes [0] << 8) |
856 (uint16) bytes [1]);
857 }
858 } catch (MelderError) {
859 Melder_throw (U"Signed integer not read from 2 bytes in binary file.");
860 }
861 }
862
bingeti16LE(FILE * f)863 int16 bingeti16LE (FILE *f) {
864 try {
865 if (binario_16bitLE && Melder_debug != 18) {
866 int16 s;
867 if (fread (& s, sizeof (int16), 1, f) != 1) readError (f, U"a signed 16-bit integer.");
868 return s;
869 } else {
870 uint8 bytes [2];
871 if (fread (bytes, sizeof (uint8), 2, f) != 2) readError (f, U"two bytes.");
872 return (int16) // reinterpret sign bit
873 ((uint16) ((uint16) bytes [1] << 8) |
874 (uint16) bytes [0]);
875 }
876 } catch (MelderError) {
877 Melder_throw (U"Signed integer not read from 2 bytes in binary file.");
878 }
879 }
880
bingetinteger16BE(FILE * f)881 integer bingetinteger16BE (FILE *f) {
882 try {
883 if (binario_16bitBE && Melder_debug != 18) {
884 int16 s;
885 if (fread (& s, sizeof (int16), 1, f) != 1) readError (f, U"a signed 16-bit integer.");
886 return s;
887 } else {
888 uint8 bytes [2];
889 if (fread (bytes, sizeof (uint8), 2, f) != 2) readError (f, U"two bytes.");
890 return (int16) // reinterpret sign bit
891 ((uint16) ((uint16) bytes [0] << 8) |
892 (uint16) bytes [1]);
893 }
894 } catch (MelderError) {
895 Melder_throw (U"Signed integer not read from 2 bytes in binary file.");
896 }
897 }
898
bingetu16(FILE * f)899 uint16 bingetu16 (FILE *f) {
900 try {
901 if (binario_16bitBE && Melder_debug != 18) {
902 uint16 s;
903 if (fread (& s, sizeof (uint16), 1, f) != 1) readError (f, U"an unsigned 16-bit integer.");
904 return s; // without sign extension
905 } else {
906 uint8 bytes [2];
907 if (fread (bytes, sizeof (uint8), 2, f) != 2) readError (f, U"two bytes.");
908 return
909 (uint16) ((uint16) bytes [0] << 8) |
910 (uint16) bytes [1];
911 }
912 } catch (MelderError) {
913 Melder_throw (U"Unsigned integer not read from 2 bytes in binary file.");
914 }
915 }
916
bingetu16LE(FILE * f)917 uint16 bingetu16LE (FILE *f) {
918 try {
919 if (binario_16bitLE && Melder_debug != 18) {
920 uint16 s;
921 if (fread (& s, sizeof (uint16), 1, f) != 1) readError (f, U"an unsigned 16-bit integer.");
922 return s; // without sign extension
923 } else {
924 uint8 bytes [2];
925 if (fread (bytes, sizeof (uint8), 2, f) != 2) readError (f, U"two bytes.");
926 return
927 (uint16) ((uint16) bytes [1] << 8) |
928 (uint16) bytes [0];
929 }
930 } catch (MelderError) {
931 Melder_throw (U"Unsigned integer not read from 2 bytes in binary file.");
932 }
933 }
934
bingete16(FILE * f,int min,int max,conststring32 type)935 int bingete16 (FILE *f, int min, int max, conststring32 type) {
936 try {
937 int16 result;
938 if (binario_16bitBE && Melder_debug != 18) {
939 if (fread (& result, sizeof (int16), 1, f) != 1) readError (f, U"a signed 16-bit integer.");
940 } else {
941 uint8 bytes [2];
942 if (fread (bytes, sizeof (uint8), 2, f) != 2) readError (f, U"two bytes.");
943 uint16 externalValue =
944 (uint16) ((uint16) bytes [0] << 8) |
945 (uint16) bytes [1];
946 result = (int16) externalValue;
947 }
948 if (result < min || result > max)
949 Melder_throw (result, U" is not a value of enumerated type \"", type, U"\".");
950 return (int) result;
951 } catch (MelderError) {
952 Melder_throw (U"Enumerated value not read from 2 bytes in binary file.");
953 }
954 }
955
bingeti24(FILE * f)956 int32 bingeti24 (FILE *f) {
957 try {
958 uint8 bytes [3];
959 if (fread (bytes, sizeof (uint8), 3, f) != 3) readError (f, U"three bytes.");
960 uint32 externalValue =
961 (uint32) ((uint32) bytes [0] << 16) |
962 (uint32) ((uint32) bytes [1] << 8) |
963 (uint32) bytes [2];
964 if ((bytes [0] & 128) != 0) // is the 24-bit sign bit on?
965 externalValue |= 0xFF00'0000; // extend negative sign to 32 bits
966 return (int32) externalValue; // reinterpret sign bit
967 } catch (MelderError) {
968 Melder_throw (U"Signed integer not read from 3 bytes in binary file.");
969 }
970 }
971
bingeti24LE(FILE * f)972 int32 bingeti24LE (FILE *f) {
973 try {
974 uint8 bytes [3];
975 if (fread (bytes, sizeof (uint8), 3, f) != 3) readError (f, U"three bytes.");
976 uint32 externalValue =
977 (uint32) ((uint32) bytes [2] << 16) |
978 (uint32) ((uint32) bytes [1] << 8) |
979 (uint32) bytes [0];
980 if ((bytes [2] & 128) != 0) // is the 24-bit sign bit on?
981 externalValue |= 0xFF00'0000; // extend negative sign to 32 bits
982 return (int32) externalValue; // reinterpret sign bit
983 } catch (MelderError) {
984 Melder_throw (U"Signed integer not read from 3 bytes in binary file.");
985 }
986 }
987
bingeti32(FILE * f)988 int32 bingeti32 (FILE *f) {
989 try {
990 if (binario_32bitBE && Melder_debug != 18) {
991 int32 l;
992 if (fread (& l, sizeof (int32), 1, f) != 1) readError (f, U"a signed 32-bit integer.");
993 return l;
994 } else {
995 uint8 bytes [4];
996 if (fread (bytes, sizeof (uint8), 4, f) != 4) readError (f, U"four bytes.");
997 return (int32)
998 ((uint32) ((uint32) bytes [0] << 24) |
999 (uint32) ((uint32) bytes [1] << 16) |
1000 (uint32) ((uint32) bytes [2] << 8) |
1001 (uint32) bytes [3]);
1002 }
1003 } catch (MelderError) {
1004 Melder_throw (U"Signed integer not read from 4 bytes in binary file.");
1005 }
1006 }
1007
bingeti32LE(FILE * f)1008 int32 bingeti32LE (FILE *f) {
1009 try {
1010 if (binario_32bitLE && Melder_debug != 18) {
1011 int32 l;
1012 if (fread (& l, sizeof (int32), 1, f) != 1) readError (f, U"a signed 32-bit integer.");
1013 return l;
1014 } else {
1015 uint8 bytes [4];
1016 if (fread (bytes, sizeof (uint8), 4, f) != 4) readError (f, U"four bytes.");
1017 return (int32) // reinterpret sign bit
1018 ((uint32) ((uint32) bytes [3] << 24) |
1019 (uint32) ((uint32) bytes [2] << 16) |
1020 (uint32) ((uint32) bytes [1] << 8) |
1021 (uint32) bytes [0]);
1022 }
1023 } catch (MelderError) {
1024 Melder_throw (U"Signed integer not read from 4 bytes in binary file.");
1025 }
1026 }
1027
bingetinteger32BE(FILE * f)1028 integer bingetinteger32BE (FILE *f) {
1029 try {
1030 if (binario_32bitBE && Melder_debug != 18) {
1031 int32 l;
1032 if (fread (& l, sizeof (int32), 1, f) != 1) readError (f, U"a signed 32-bit integer.");
1033 return (integer) l;
1034 } else {
1035 uint8 bytes [4];
1036 if (fread (bytes, sizeof (uint8), 4, f) != 4) readError (f, U"four bytes.");
1037 return (integer) (int32)
1038 ((uint32) ((uint32) bytes [0] << 24) |
1039 (uint32) ((uint32) bytes [1] << 16) |
1040 (uint32) ((uint32) bytes [2] << 8) |
1041 (uint32) bytes [3]);
1042 }
1043 } catch (MelderError) {
1044 Melder_throw (U"Signed integer not read from 4 bytes in binary file.");
1045 }
1046 }
1047
bingetu32(FILE * f)1048 uint32 bingetu32 (FILE *f) {
1049 try {
1050 if (binario_32bitBE && Melder_debug != 18) {
1051 uint32 l;
1052 if (fread (& l, sizeof (uint32), 1, f) != 1) readError (f, U"an unsigned 32-bit integer.");
1053 return l;
1054 } else {
1055 uint8 bytes [4];
1056 if (fread (bytes, sizeof (uint8), 4, f) != 4) readError (f, U"four bytes.");
1057 return
1058 (uint32) ((uint32) bytes [0] << 24) |
1059 (uint32) ((uint32) bytes [1] << 16) |
1060 (uint32) ((uint32) bytes [2] << 8) |
1061 (uint32) bytes [3];
1062 }
1063 } catch (MelderError) {
1064 Melder_throw (U"Unsigned integer not read from 4 bytes in binary file.");
1065 }
1066 }
1067
bingetu32LE(FILE * f)1068 uint32 bingetu32LE (FILE *f) {
1069 try {
1070 if (binario_32bitLE && Melder_debug != 18) {
1071 uint32 l;
1072 if (fread (& l, sizeof (uint32), 1, f) != 1) readError (f, U"an unsigned 32-bit integer.");
1073 return l;
1074 } else {
1075 uint8 bytes [4];
1076 if (fread (bytes, sizeof (uint8), 4, f) != 4) readError (f, U"four bytes.");
1077 return
1078 (uint32) ((uint32) bytes [3] << 24) |
1079 (uint32) ((uint32) bytes [2] << 16) |
1080 (uint32) ((uint32) bytes [1] << 8) |
1081 (uint32) bytes [0];
1082 }
1083 } catch (MelderError) {
1084 Melder_throw (U"Unsigned integer not read from 4 bytes in binary file.");
1085 }
1086 }
1087
bingetr32(FILE * f)1088 double bingetr32 (FILE *f) {
1089 try {
1090 if (binario_floatIEEE4msb && Melder_debug != 18) {
1091 float x;
1092 if (fread (& x, sizeof (float), 1, f) != 1) readError (f, U"a 32-bit floating-point number.");
1093 return x;
1094 } else {
1095 uint8 bytes [4];
1096 if (fread (bytes, sizeof (uint8), 4, f) != 4) readError (f, U"four bytes.");
1097 int32 exponent = (int32)
1098 ((uint32) ((uint32) ((uint32) bytes [0] & 0x0000'007F) << 1) |
1099 (uint32) ((uint32) ((uint32) bytes [1] & 0x0000'0080) >> 7)); // between 0 and 255 (it's signed because we're going to subtract something)
1100 uint32 mantissa =
1101 (uint32) ((uint32) ((uint32) bytes [1] & 0x0000'007F) << 16) |
1102 (uint32) ((uint32) bytes [2] << 8) |
1103 (uint32) bytes [3];
1104 double x;
1105 if (exponent == 0)
1106 if (mantissa == 0) x = 0.0;
1107 else x = ldexp ((double) mantissa, exponent - 149); // denormalized
1108 else if (exponent == 0x0000'00FF) // Infinity or Not-a-Number
1109 return undefined;
1110 else // finite
1111 x = ldexp ((double) (mantissa | 0x0080'0000), exponent - 150);
1112 return bytes [0] & 0x80 ? - x : x;
1113 }
1114 } catch (MelderError) {
1115 Melder_throw (U"Floating-point number not read from 4 bytes in binary file.");
1116 }
1117 }
1118
bingetr32LE(FILE * f)1119 double bingetr32LE (FILE *f) {
1120 try {
1121 if (binario_floatIEEE4lsb && Melder_debug != 18) {
1122 float x;
1123 if (fread (& x, sizeof (float), 1, f) != 1) readError (f, U"a 32-bit floating-point number.");
1124 return x;
1125 } else {
1126 uint8 bytes [4];
1127 if (fread (bytes, sizeof (uint8), 4, f) != 4) readError (f, U"four bytes.");
1128 int32 exponent = (int32)
1129 ((uint32) ((uint32) ((uint32) bytes [3] & 0x0000'007F) << 1) |
1130 (uint32) ((uint32) ((uint32) bytes [2] & 0x0000'0080) >> 7));
1131 uint32 mantissa =
1132 (uint32) ((uint32) ((uint32) bytes [2] & 0x0000'007F) << 16) |
1133 (uint32) ((uint32) bytes [1] << 8) |
1134 (uint32) bytes [0];
1135 double x;
1136 if (exponent == 0)
1137 if (mantissa == 0) x = 0.0;
1138 else x = ldexp ((double) mantissa, exponent - 149); // denormalized
1139 else if (exponent == 0x0000'00FF) // Infinity or Not-a-Number
1140 return undefined;
1141 else // finite
1142 x = ldexp ((double) (mantissa | 0x0080'0000), exponent - 150);
1143 return bytes [3] & 0x80 ? - x : x;
1144 }
1145 } catch (MelderError) {
1146 Melder_throw (U"Floating-point number not read from 4 bytes in binary file.");
1147 }
1148 }
1149
bingetr64(FILE * f)1150 double bingetr64 (FILE *f) {
1151 try {
1152 if (binario_doubleIEEE8msb && Melder_debug != 18 || Melder_debug == 181) {
1153 double x;
1154 if (fread (& x, sizeof (double), 1, f) != 1) readError (f, U"a 64-bit floating-point number.");
1155 return x;
1156 } else {
1157 uint8 bytes [8];
1158 if (fread (bytes, sizeof (uint8), 8, f) != 8) readError (f, U"eight bytes.");
1159 int32 exponent = (int32)
1160 ((uint32) ((uint32) ((uint32) bytes [0] & 0x0000'007F) << 4) |
1161 (uint32) ((uint32) ((uint32) bytes [1] & 0x0000'00F0) >> 4));
1162 uint32 highMantissa =
1163 (uint32) ((uint32) ((uint32) bytes [1] & 0x0000'000F) << 16) |
1164 (uint32) ((uint32) bytes [2] << 8) |
1165 (uint32) bytes [3];
1166 uint32 lowMantissa =
1167 (uint32) ((uint32) bytes [4] << 24) |
1168 (uint32) ((uint32) bytes [5] << 16) |
1169 (uint32) ((uint32) bytes [6] << 8) |
1170 (uint32) bytes [7];
1171 double x;
1172 if (exponent == 0)
1173 if (highMantissa == 0 && lowMantissa == 0) x = 0.0;
1174 else x = ldexp ((double) highMantissa, exponent - 1042) +
1175 ldexp ((double) lowMantissa, exponent - 1074); // denormalized
1176 else if (exponent == 0x0000'07FF) // Infinity or Not-a-Number
1177 return undefined;
1178 else
1179 x = ldexp ((double) (highMantissa | 0x0010'0000), exponent - 1043) +
1180 ldexp ((double) lowMantissa, exponent - 1075);
1181 return bytes [0] & 0x80 ? - x : x;
1182 }
1183 } catch (MelderError) {
1184 Melder_throw (U"Floating-point number not read from 8 bytes in binary file.");
1185 }
1186 }
1187
bingetr64LE(FILE * f)1188 double bingetr64LE (FILE *f) {
1189 try {
1190 if (binario_doubleIEEE8lsb && Melder_debug != 18 || Melder_debug == 181) {
1191 double x;
1192 if (fread (& x, sizeof (double), 1, f) != 1) readError (f, U"a 64-bit floating-point number.");
1193 return x;
1194 } else {
1195 uint8 bytes [8];
1196 if (fread (bytes, sizeof (uint8), 8, f) != 8) readError (f, U"eight bytes.");
1197 int32 exponent = (int32)
1198 ((uint32) ((uint32) ((uint32) bytes [7] & 0x0000'007F) << 4) |
1199 (uint32) ((uint32) ((uint32) bytes [6] & 0x0000'00F0) >> 4));
1200 uint32 highMantissa =
1201 (uint32) ((uint32) ((uint32) bytes [6] & 0x0000'000F) << 16) |
1202 (uint32) ((uint32) bytes [5] << 8) |
1203 (uint32) bytes [4];
1204 uint32 lowMantissa =
1205 (uint32) ((uint32) bytes [3] << 24) |
1206 (uint32) ((uint32) bytes [2] << 16) |
1207 (uint32) ((uint32) bytes [1] << 8) |
1208 (uint32) bytes [0];
1209 double x;
1210 if (exponent == 0)
1211 if (highMantissa == 0 && lowMantissa == 0) x = 0.0;
1212 else x = ldexp ((double) highMantissa, exponent - 1042) +
1213 ldexp ((double) lowMantissa, exponent - 1074); // denormalized
1214 else if (exponent == 0x0000'07FF) // Infinity or Not-a-Number
1215 return undefined;
1216 else
1217 x = ldexp ((double) (highMantissa | 0x0010'0000), exponent - 1043) +
1218 ldexp ((double) lowMantissa, exponent - 1075);
1219 return bytes [7] & 0x80 ? - x : x;
1220 }
1221 } catch (MelderError) {
1222 Melder_throw (U"Floating-point number not read from 8 bytes in binary file.");
1223 }
1224 }
1225
bingetr80(FILE * f)1226 double bingetr80 (FILE *f) {
1227 try {
1228 uint8 bytes [10];
1229 if (fread (bytes, sizeof (uint8), 10, f) != 10) readError (f, U"ten bytes.");
1230 int32 exponent = (int32)
1231 ((uint32) ((uint32) ((uint32) bytes [0] & 0x0000'007F) << 8) |
1232 (uint32) bytes [1]); // between 0 and 32767
1233 uint32 highMantissa =
1234 (uint32) ((uint32) bytes [2] << 24) |
1235 (uint32) ((uint32) bytes [3] << 16) |
1236 (uint32) ((uint32) bytes [4] << 8) |
1237 (uint32) bytes [5];
1238 uint32 lowMantissa =
1239 (uint32) ((uint32) bytes [6] << 24) |
1240 (uint32) ((uint32) bytes [7] << 16) |
1241 (uint32) ((uint32) bytes [8] << 8) |
1242 (uint32) bytes [9];
1243 double x;
1244 if (exponent == 0 && highMantissa == 0 && lowMantissa == 0) x = 0.0;
1245 else if (exponent == 0x0000'7FFF) return undefined; // Infinity or NaN
1246 else {
1247 exponent -= 16'383; // between -16'382 and +16'383
1248 x = ldexp ((double) highMantissa, exponent - 31);
1249 x += ldexp ((double) lowMantissa, exponent - 63);
1250 }
1251 return bytes [0] & 0x80 ? - x : x;
1252 } catch (MelderError) {
1253 Melder_throw (U"Floating-point number not read from 10 bytes in binary file.");
1254 }
1255 }
1256
1257 static int bitsInWriteBuffer = 0;
1258 static unsigned char writeBuffer = 0;
1259
1260 #define macro_binputb(nbits) \
1261 void binputb##nbits (unsigned int value, FILE *f) { \
1262 if (bitsInWriteBuffer + nbits > 8) { \
1263 if (fputc (writeBuffer, f) < 0) writeError (U"a bit."); \
1264 bitsInWriteBuffer = 0; \
1265 writeBuffer = 0; \
1266 } \
1267 writeBuffer |= (value << (8 - nbits)) >> bitsInWriteBuffer; \
1268 bitsInWriteBuffer += nbits; \
1269 }
1270 macro_binputb (1)
1271 macro_binputb (2)
1272 macro_binputb (3)
1273 macro_binputb (4)
1274 macro_binputb (5)
1275 macro_binputb (6)
1276 macro_binputb (7)
binputb(FILE * f)1277 void binputb (FILE *f) {
1278 if (bitsInWriteBuffer == 0) return;
1279 if (fputc (writeBuffer, f) < 0) writeError (U"a bit."); // flush
1280 bitsInWriteBuffer = 0;
1281 writeBuffer = 0;
1282 }
1283
binputi16(int16 i,FILE * f)1284 void binputi16 (int16 i, FILE *f) {
1285 try {
1286 if (binario_16bitBE && Melder_debug != 18) {
1287 if (fwrite (& i, sizeof (short), 1, f) != 1) writeError (U"a signed 16-bit integer.");
1288 } else {
1289 uint8 bytes [2];
1290 bytes [0] = (uint8) (i >> 8); // truncate
1291 bytes [1] = (uint8) i; // truncate
1292 if (fwrite (bytes, sizeof (uint8), 2, f) != 2) writeError (U"two bytes.");
1293 }
1294 } catch (MelderError) {
1295 Melder_throw (U"Signed integer not written to 2 bytes in binary file.");
1296 }
1297 }
1298
binputi16LE(int16 i,FILE * f)1299 void binputi16LE (int16 i, FILE *f) {
1300 try {
1301 if (binario_16bitLE && Melder_debug != 18) {
1302 if (fwrite (& i, sizeof (short), 1, f) != 1) writeError (U"a signed 16-bit integer.");
1303 } else {
1304 uint8 bytes [2];
1305 bytes [1] = (uint8) (i >> 8); // truncate
1306 bytes [0] = (uint8) i; // truncate
1307 if (fwrite (bytes, sizeof (uint8), 2, f) != 2) writeError (U"two bytes.");
1308 }
1309 } catch (MelderError) {
1310 Melder_throw (U"Signed integer not written to 2 bytes in binary file.");
1311 }
1312 }
1313
binputinteger16BE(integer i,FILE * f)1314 void binputinteger16BE (integer i, FILE *f) {
1315 try {
1316 if (i < INT16_MIN || i > INT16_MAX)
1317 Melder_throw (U"The number ", i, U" is too big to fit into 16 bits."); // this will change in the future
1318 uint8 bytes [2];
1319 bytes [0] = (uint8) (i >> 8); // truncate
1320 bytes [1] = (uint8) i; // truncate
1321 if (fwrite (bytes, sizeof (uint8), 2, f) != 2) writeError (U"two bytes.");
1322 } catch (MelderError) {
1323 Melder_throw (U"Signed integer not written to 2 bytes in binary file.");
1324 }
1325 }
1326
binputu16(uint16 u,FILE * f)1327 void binputu16 (uint16 u, FILE *f) {
1328 try {
1329 if (binario_16bitBE && Melder_debug != 18) {
1330 if (fwrite (& u, sizeof (uint16), 1, f) != 1) writeError (U"an unsigned 16-bit integer.");
1331 } else {
1332 uint8 bytes [2];
1333 bytes [0] = (uint8) (u >> 8); // truncate
1334 bytes [1] = (uint8) u; // truncate
1335 if (fwrite (bytes, sizeof (uint8), 2, f) != 2) writeError (U"two bytes.");
1336 }
1337 } catch (MelderError) {
1338 Melder_throw (U"Unsigned integer not written to 2 bytes in binary file.");
1339 }
1340 }
1341
binputu16LE(uint16 u,FILE * f)1342 void binputu16LE (uint16 u, FILE *f) {
1343 try {
1344 if (binario_16bitLE && Melder_debug != 18) {
1345 if (fwrite (& u, sizeof (uint16), 1, f) != 1) writeError (U"an unsigned 16-bit integer.");
1346 } else {
1347 uint8 bytes [2];
1348 bytes [1] = (uint8) (u >> 8); // truncate
1349 bytes [0] = (uint8) u; // truncate
1350 if (fwrite (bytes, sizeof (uint8), 2, f) != 2) writeError (U"two bytes.");
1351 }
1352 } catch (MelderError) {
1353 Melder_throw (U"Unsigned integer not written to 2 bytes in binary file.");
1354 }
1355 }
1356
binpute16(int value,FILE * f)1357 void binpute16 (int value, FILE *f) {
1358 try {
1359 if (binario_16bitBE && Melder_debug != 18) {
1360 short s = value;
1361 if (fwrite (& s, sizeof (short), 1, f) != 1) writeError (U"a signed 16-bit integer");
1362 } else {
1363 uint8 bytes [2];
1364 bytes [0] = (uint8) (value >> 8); // truncate
1365 bytes [1] = (uint8) value; // truncate
1366 if (fwrite (bytes, sizeof (uint8), 2, f) != 2) writeError (U"two bytes.");
1367 }
1368 } catch (MelderError) {
1369 Melder_throw (U"Enumerated value not written to 2 bytes in binary file.");
1370 }
1371 }
1372
binputi24(int32 i,FILE * f)1373 void binputi24 (int32 i, FILE *f) {
1374 try {
1375 uint8 bytes [3];
1376 bytes [0] = (uint8) (i >> 16); // truncate
1377 bytes [1] = (uint8) (i >> 8); // truncate
1378 bytes [2] = (uint8) i; // truncate
1379 if (fwrite (bytes, sizeof (uint8), 3, f) != 3) writeError (U"three bytes");
1380 } catch (MelderError) {
1381 Melder_throw (U"Signed integer not written to 3 bytes in binary file.");
1382 }
1383 }
1384
binputi24LE(int32 i,FILE * f)1385 void binputi24LE (int32 i, FILE *f) {
1386 try {
1387 uint8 bytes [3];
1388 bytes [2] = (uint8) (i >> 16); // truncate
1389 bytes [1] = (uint8) (i >> 8); // truncate
1390 bytes [0] = (uint8) i; // truncate
1391 if (fwrite (bytes, sizeof (uint8), 3, f) != 3) writeError (U"three bytes");
1392 } catch (MelderError) {
1393 Melder_throw (U"Signed integer not written to 3 bytes in binary file.");
1394 }
1395 }
1396
binputi32(int32 i,FILE * f)1397 void binputi32 (int32 i, FILE *f) {
1398 try {
1399 if (binario_32bitBE && Melder_debug != 18) {
1400 if (fwrite (& i, sizeof (int32), 1, f) != 1) writeError (U"a signed 32-bit integer.");
1401 } else {
1402 uint8 bytes [4];
1403 bytes [0] = (uint8) (i >> 24); // truncate
1404 bytes [1] = (uint8) (i >> 16); // truncate
1405 bytes [2] = (uint8) (i >> 8); // truncate
1406 bytes [3] = (uint8) i; // truncate
1407 if (fwrite (bytes, sizeof (uint8), 4, f) != 4) writeError (U"four bytes.");
1408 }
1409 } catch (MelderError) {
1410 Melder_throw (U"Signed integer not written to 4 bytes in binary file.");
1411 }
1412 }
1413
binputi32LE(int32 i,FILE * f)1414 void binputi32LE (int32 i, FILE *f) {
1415 try {
1416 if (binario_32bitLE && Melder_debug != 18) {
1417 if (fwrite (& i, sizeof (int32), 1, f) != 1) writeError (U"a signed 32-bit integer.");
1418 } else {
1419 uint8 bytes [4];
1420 bytes [3] = (uint8) (i >> 24); // truncate
1421 bytes [2] = (uint8) (i >> 16); // truncate
1422 bytes [1] = (uint8) (i >> 8); // truncate
1423 bytes [0] = (uint8) i; // truncate
1424 if (fwrite (bytes, sizeof (uint8), 4, f) != 4) writeError (U"four bytes.");
1425 }
1426 } catch (MelderError) {
1427 Melder_throw (U"Signed integer not written to 4 bytes in binary file.");
1428 }
1429 }
1430
binputinteger32BE(integer i,FILE * f)1431 void binputinteger32BE (integer i, FILE *f) {
1432 try {
1433 if (i < INT32_MIN || i > INT32_MAX)
1434 Melder_throw (U"The number ", i, U" is too big to fit into 32 bits."); // this will change in the future
1435 uint8 bytes [4];
1436 bytes [0] = (uint8) (i >> 24); // truncate
1437 bytes [1] = (uint8) (i >> 16); // truncate
1438 bytes [2] = (uint8) (i >> 8); // truncate
1439 bytes [3] = (uint8) i; // truncate
1440 if (fwrite (bytes, sizeof (uint8), 4, f) != 4) writeError (U"a signed 32-bit integer.");
1441 } catch (MelderError) {
1442 Melder_throw (U"Signed integer not written to 4 bytes in binary file.");
1443 }
1444 }
1445
binputu32(uint32 u,FILE * f)1446 void binputu32 (uint32 u, FILE *f) {
1447 try {
1448 if (binario_32bitBE && Melder_debug != 18) {
1449 if (fwrite (& u, sizeof (uint32), 1, f) != 1) writeError (U"an unsigned 32-bit integer.");
1450 } else {
1451 uint8 bytes [4];
1452 bytes [0] = (uint8) (u >> 24); // truncate
1453 bytes [1] = (uint8) (u >> 16); // truncate
1454 bytes [2] = (uint8) (u >> 8); // truncate
1455 bytes [3] = (uint8) u; // truncate
1456 if (fwrite (bytes, sizeof (uint8), 4, f) != 4) writeError (U"four bytes.");
1457 }
1458 } catch (MelderError) {
1459 Melder_throw (U"Unsigned integer not written to 4 bytes in binary file.");
1460 }
1461 }
1462
binputu32LE(uint32 u,FILE * f)1463 void binputu32LE (uint32 u, FILE *f) {
1464 try {
1465 if (binario_32bitLE && Melder_debug != 18) {
1466 if (fwrite (& u, sizeof (uint32), 1, f) != 1) writeError (U"an unsigned 32-bit integer.");
1467 } else {
1468 uint8 bytes [4];
1469 bytes [3] = (uint8) (u >> 24); // truncate
1470 bytes [2] = (uint8) (u >> 16); // truncate
1471 bytes [1] = (uint8) (u >> 8); // truncate
1472 bytes [0] = (uint8) u; // truncate
1473 if (fwrite (bytes, sizeof (uint8), 4, f) != 4) writeError (U"four bytes.");
1474 }
1475 } catch (MelderError) {
1476 Melder_throw (U"Unsigned integer not written to 4 bytes in binary file.");
1477 }
1478 }
1479
binputr32(double x,FILE * f)1480 void binputr32 (double x, FILE *f) {
1481 try {
1482 if (binario_floatIEEE4msb && Melder_debug != 18) {
1483 float x32 = (float) x; // convert down, with loss of precision
1484 if (fwrite (& x32, sizeof (float), 1, f) != 1) writeError (U"a 32-bit floating-point number.");
1485 } else {
1486 uint8 bytes [4];
1487 int sign, exponent;
1488 double fMantissa, fsMantissa;
1489 uint32 mantissa;
1490 if (x < 0.0) { sign = 0x0100; x *= -1.0; }
1491 else sign = 0;
1492 if (x == 0.0) { exponent = 0; mantissa = 0; }
1493 else {
1494 fMantissa = frexp (x, & exponent);
1495 if ((exponent > 128) || ! (fMantissa < 1.0)) // Infinity or Not-a-Number
1496 { exponent = sign | 0x00FF; mantissa = 0; } // Infinity
1497 else { // finite
1498 exponent += 126; // add bias
1499 if (exponent <= 0) { // denormalized
1500 fMantissa = ldexp (fMantissa, exponent - 1);
1501 exponent = 0;
1502 }
1503 exponent |= sign;
1504 fMantissa = ldexp (fMantissa, 24);
1505 fsMantissa = floor (fMantissa);
1506 mantissa = (uint32) fsMantissa & 0x007FFFFF;
1507 }
1508 }
1509 bytes [0] = (uint8) (exponent >> 1); // truncate: bits 2 through 9 (bit 9 is the sign bit)
1510 bytes [1] = (uint8) ((exponent << 7) | (mantissa >> 16)); // truncate
1511 bytes [2] = (uint8) (mantissa >> 8); // truncate
1512 bytes [3] = (uint8) mantissa; // truncate
1513 if (fwrite (bytes, sizeof (uint8), 4, f) != 4) writeError (U"four bytes.");
1514 }
1515 } catch (MelderError) {
1516 Melder_throw (U"Floating-point number not written to 4 bytes in binary file.");
1517 }
1518 }
1519
binputr32LE(double x,FILE * f)1520 void binputr32LE (double x, FILE *f) {
1521 try {
1522 if (binario_floatIEEE4lsb && Melder_debug != 18) {
1523 float x32 = (float) x; // convert down, with loss of precision
1524 if (fwrite (& x32, sizeof (float), 1, f) != 1) writeError (U"a 32-bit floating-point number.");
1525 } else {
1526 uint8 bytes [4];
1527 int sign, exponent;
1528 double fMantissa, fsMantissa;
1529 uint32 mantissa;
1530 if (x < 0.0) { sign = 0x0100; x *= -1.0; }
1531 else sign = 0;
1532 if (x == 0.0) { exponent = 0; mantissa = 0; }
1533 else {
1534 fMantissa = frexp (x, & exponent);
1535 if ((exponent > 128) || ! (fMantissa < 1.0)) // Infinity or Not-a-Number
1536 { exponent = sign | 0x00FF; mantissa = 0; } // Infinity
1537 else { // finite
1538 exponent += 126; // add bias
1539 if (exponent <= 0) { // denormalized
1540 fMantissa = ldexp (fMantissa, exponent - 1);
1541 exponent = 0;
1542 }
1543 exponent |= sign;
1544 fMantissa = ldexp (fMantissa, 24);
1545 fsMantissa = floor (fMantissa);
1546 mantissa = (uint32) fsMantissa & 0x007F'FFFF;
1547 }
1548 }
1549 bytes [3] = (uint8) (exponent >> 1);
1550 bytes [2] = (uint8) ((exponent << 7) | (mantissa >> 16));
1551 bytes [1] = (uint8) (mantissa >> 8);
1552 bytes [0] = (uint8) mantissa;
1553 if (fwrite (bytes, sizeof (uint8), 4, f) != 4) writeError (U"four bytes.");
1554 }
1555 } catch (MelderError) {
1556 Melder_throw (U"Floating-point number not written to 4 bytes in binary file.");
1557 }
1558 }
1559
binputr64(double x,FILE * f)1560 void binputr64 (double x, FILE *f) {
1561 try {
1562 if (binario_doubleIEEE8msb && Melder_debug != 18 || Melder_debug == 181) {
1563 if (fwrite (& x, sizeof (double), 1, f) != 1) writeError (U"a 64-bit floating-point number.");
1564 } else if (binario_doubleIEEE8lsb && Melder_debug != 18) {
1565 union { double xx; uint8 bytes [8]; };
1566 xx = x;
1567 std::swap (bytes [0], bytes [7]);
1568 std::swap (bytes [1], bytes [6]);
1569 std::swap (bytes [2], bytes [5]);
1570 std::swap (bytes [3], bytes [4]);
1571 if (fwrite (& xx, sizeof (double), 1, f) != 1) writeError (U"a 64-bit floating-point number.");
1572 } else {
1573 uint8 bytes [8];
1574 int sign, exponent;
1575 double fMantissa, fsMantissa;
1576 uint32 highMantissa, lowMantissa;
1577 if (x < 0.0) { sign = 0x0800; x *= -1.0; }
1578 else sign = 0;
1579 if (x == 0.0) { exponent = 0; highMantissa = 0; lowMantissa = 0; }
1580 else {
1581 fMantissa = frexp (x, & exponent);
1582 if (/*(exponent > 1024) ||*/ ! (fMantissa < 1.0)) // Infinity or Not-a-Number
1583 { exponent = sign | 0x07FF; highMantissa = 0; lowMantissa = 0; } // Infinity
1584 else { // finite
1585 exponent += 1022; // add bias
1586 if (exponent <= 0) { // denormalized
1587 fMantissa = ldexp (fMantissa, exponent - 1);
1588 exponent = 0;
1589 }
1590 exponent |= sign;
1591 fMantissa = ldexp (fMantissa, 21);
1592 fsMantissa = floor (fMantissa);
1593 highMantissa = (uint32) fsMantissa & 0x000F'FFFF;
1594 fMantissa = ldexp (fMantissa - fsMantissa, 32);
1595 fsMantissa = floor (fMantissa);
1596 lowMantissa = (uint32) fsMantissa;
1597 }
1598 }
1599 bytes [0] = (uint8) (exponent >> 4);
1600 bytes [1] = (uint8) ((exponent << 4) | (highMantissa >> 16));
1601 bytes [2] = (uint8) (highMantissa >> 8);
1602 bytes [3] = (uint8) highMantissa;
1603 bytes [4] = (uint8) (lowMantissa >> 24);
1604 bytes [5] = (uint8) (lowMantissa >> 16);
1605 bytes [6] = (uint8) (lowMantissa >> 8);
1606 bytes [7] = (uint8) lowMantissa;
1607 if (fwrite (bytes, sizeof (uint8), 8, f) != 8) writeError (U"eight bytes.");
1608 }
1609 } catch (MelderError) {
1610 Melder_throw (U"Floating-point number not written to 8 bytes in binary file.");
1611 }
1612 }
1613
binputr64LE(double x,FILE * f)1614 void binputr64LE (double x, FILE *f) {
1615 try {
1616 if (binario_doubleIEEE8lsb && Melder_debug != 18 || Melder_debug == 181) {
1617 if (fwrite (& x, sizeof (double), 1, f) != 1) writeError (U"a 64-bit floating-point number.");
1618 } else if (binario_doubleIEEE8msb && Melder_debug != 18) {
1619 union { double xx; uint8 bytes [8]; };
1620 xx = x;
1621 std::swap (bytes [0], bytes [7]);
1622 std::swap (bytes [1], bytes [6]);
1623 std::swap (bytes [2], bytes [5]);
1624 std::swap (bytes [3], bytes [4]);
1625 if (fwrite (& xx, sizeof (double), 1, f) != 1) writeError (U"a 64-bit floating-point number.");
1626 } else {
1627 uint8 bytes [8];
1628 int sign, exponent;
1629 double fMantissa, fsMantissa;
1630 uint32 highMantissa, lowMantissa;
1631 if (x < 0.0) { sign = 0x0800; x *= -1.0; }
1632 else sign = 0;
1633 if (x == 0.0) { exponent = 0; highMantissa = 0; lowMantissa = 0; }
1634 else {
1635 fMantissa = frexp (x, & exponent);
1636 if (/*(exponent > 1024) ||*/ ! (fMantissa < 1.0)) // Infinity or Not-a-Number
1637 { exponent = sign | 0x07FF; highMantissa = 0; lowMantissa = 0; } // Infinity
1638 else { // finite
1639 exponent += 1022; // add bias
1640 if (exponent <= 0) { // denormalized
1641 fMantissa = ldexp (fMantissa, exponent - 1);
1642 exponent = 0;
1643 }
1644 exponent |= sign;
1645 fMantissa = ldexp (fMantissa, 21);
1646 fsMantissa = floor (fMantissa);
1647 highMantissa = (uint32) fsMantissa & 0x000F'FFFF;
1648 fMantissa = ldexp (fMantissa - fsMantissa, 32);
1649 fsMantissa = floor (fMantissa);
1650 lowMantissa = (uint32) fsMantissa;
1651 }
1652 }
1653 bytes [7] = (uint8) (exponent >> 4);
1654 bytes [6] = (uint8) ((exponent << 4) | (highMantissa >> 16));
1655 bytes [5] = (uint8) (highMantissa >> 8);
1656 bytes [4] = (uint8) highMantissa;
1657 bytes [3] = (uint8) (lowMantissa >> 24);
1658 bytes [2] = (uint8) (lowMantissa >> 16);
1659 bytes [1] = (uint8) (lowMantissa >> 8);
1660 bytes [0] = (uint8) lowMantissa;
1661 if (fwrite (bytes, sizeof (uint8), 8, f) != 8) writeError (U"eight bytes.");
1662 }
1663 } catch (MelderError) {
1664 Melder_throw (U"Floating-point number not written to 8 bytes in binary file.");
1665 }
1666 }
1667
binputr80(double x,FILE * f)1668 void binputr80 (double x, FILE *f) {
1669 try {
1670 unsigned char bytes [10];
1671 Melder_assert (sizeof (int) > 2);
1672 int sign, exponent; // these should be uint16, but frexp() expects an int
1673 double fMantissa, fsMantissa;
1674 uint32 highMantissa, lowMantissa;
1675 if (x < 0.0) { sign = 0x8000; x *= -1.0; }
1676 else sign = 0;
1677 if (x == 0.0) { exponent = 0; highMantissa = 0; lowMantissa = 0; }
1678 else {
1679 fMantissa = frexp (x, & exponent);
1680 if ((exponent > 16384) || ! (fMantissa < 1.0)) // Infinity or Not-a-Number
1681 { exponent = sign | 0x7FFF; highMantissa = 0; lowMantissa = 0; } // Infinity
1682 else { // finite
1683 exponent += 16382; // add bias
1684 if (exponent < 0) { // denormalized
1685 fMantissa = ldexp (fMantissa, exponent);
1686 exponent = 0;
1687 }
1688 exponent |= sign;
1689 fMantissa = ldexp (fMantissa, 32);
1690 fsMantissa = floor (fMantissa);
1691 highMantissa = (uint32) fsMantissa;
1692 fMantissa = ldexp (fMantissa - fsMantissa, 32);
1693 fsMantissa = floor (fMantissa);
1694 lowMantissa = (uint32) fsMantissa;
1695 }
1696 }
1697 bytes [0] = (uint8) (exponent >> 8);
1698 bytes [1] = (uint8) exponent;
1699 bytes [2] = (uint8) (highMantissa >> 24);
1700 bytes [3] = (uint8) (highMantissa >> 16);
1701 bytes [4] = (uint8) (highMantissa >> 8);
1702 bytes [5] = (uint8) highMantissa;
1703 bytes [6] = (uint8) (lowMantissa >> 24);
1704 bytes [7] = (uint8) (lowMantissa >> 16);
1705 bytes [8] = (uint8) (lowMantissa >> 8);
1706 bytes [9] = (uint8) lowMantissa;
1707 if (fwrite (bytes, sizeof (uint8), 10, f) != 10) writeError (U"ten bytes.");
1708 } catch (MelderError) {
1709 Melder_throw (U"Floating-point number not written to 10 bytes in binary file.");
1710 }
1711 }
1712
bingetc64(FILE * f)1713 dcomplex bingetc64 (FILE *f) {
1714 try {
1715 dcomplex result;
1716 result. real (bingetr32 (f));
1717 result. imag (bingetr32 (f));
1718 return result;
1719 } catch (MelderError) {
1720 Melder_throw (U"Complex number not read from 8 bytes in binary file.");
1721 dcomplex result { };
1722 return result;
1723 }
1724 }
1725
bingetc128(FILE * f)1726 dcomplex bingetc128 (FILE *f) {
1727 try {
1728 dcomplex result;
1729 result. real (bingetr64 (f));
1730 result. imag (bingetr64 (f));
1731 return result;
1732 } catch (MelderError) {
1733 Melder_throw (U"Complex number not read from 16 bytes in binary file.");
1734 dcomplex result { };
1735 return result;
1736 }
1737 }
1738
binputc64(dcomplex z,FILE * f)1739 void binputc64 (dcomplex z, FILE *f) {
1740 try {
1741 binputr32 (z.real(), f);
1742 binputr32 (z.imag(), f);
1743 } catch (MelderError) {
1744 Melder_throw (U"Complex number not written to 8 bytes in binary file.");
1745 }
1746 }
1747
binputc128(dcomplex z,FILE * f)1748 void binputc128 (dcomplex z, FILE *f) {
1749 try {
1750 binputr64 (z.real(), f);
1751 binputr64 (z.imag(), f);
1752 } catch (MelderError) {
1753 Melder_throw (U"Complex number not written to 16 bytes in binary file.");
1754 }
1755 }
1756
bingets8(FILE * f)1757 autostring8 bingets8 (FILE *f) {
1758 try {
1759 unsigned int length = bingetu8 (f);
1760 autostring8 result (length);
1761 if (fread (result.get(), sizeof (char), length, f) != length)
1762 Melder_throw (feof (f) ? U"Reached end of file" : U"Error in file", U" while trying to read ", length, U" one-byte characters.");
1763 result [length] = 0; // trailing null byte
1764 return result;
1765 } catch (MelderError) {
1766 Melder_throw (U"Text not read from a binary file.");
1767 }
1768 }
1769
bingets16(FILE * f)1770 autostring8 bingets16 (FILE *f) {
1771 try {
1772 uint16 length = bingetu16 (f);
1773 autostring8 result (length);
1774 if (fread (result.get(), sizeof (char), length, f) != length)
1775 Melder_throw (feof (f) ? U"Reached end of file" : U"Error in file", U" while trying to read ", length, U" one-byte characters.");
1776 result [length] = 0; // trailing null byte
1777 return result;
1778 } catch (MelderError) {
1779 Melder_throw (U"Text not read from a binary file.");
1780 }
1781 }
1782
bingets32(FILE * f)1783 autostring8 bingets32 (FILE *f) {
1784 try {
1785 uint32 length = bingetu32 (f);
1786 autostring8 result (length);
1787 if (fread (result.get(), sizeof (char), length, f) != length)
1788 Melder_throw (feof (f) ? U"Reached end of file" : U"Error in file", U" while trying to read ", length, U" one-byte characters.");
1789 result [length] = 0; // trailing null byte
1790 return result;
1791 } catch (MelderError) {
1792 Melder_throw (U"Text not read from a binary file.");
1793 }
1794 }
1795
bingetw8(FILE * f)1796 autostring32 bingetw8 (FILE *f) {
1797 try {
1798 autostring32 result;
1799 unsigned int length = bingetu8 (f);
1800 if (length == 0xFF) { // an escape for encoding
1801 /*
1802 UTF-16
1803 */
1804 length = bingetu8 (f);
1805 result = autostring32 (length);
1806 for (unsigned int i = 0; i < length; i ++) {
1807 char32 kar = bingetu16 (f);
1808 if ((kar & 0x00'F800) == 0x00'D800) {
1809 if (kar > 0x00'DBFF)
1810 Melder_throw (U"Incorrect Unicode value (first surrogate member ", kar, U").");
1811 char32 kar2 = bingetu16 (f);
1812 if (kar2 < 0x00'DC'00 || kar2 > 0x00'DF'FF)
1813 Melder_throw (U"Incorrect Unicode value (second surrogate member ", kar2, U").");
1814 result [i] = (((kar & 0x00'03FF) << 10) | (kar2 & 0x00'03FF)) + 0x01'0000;
1815 } else {
1816 result [i] = kar;
1817 }
1818 }
1819 } else {
1820 /*
1821 ASCII
1822 */
1823 result = autostring32 (length);
1824 for (unsigned int i = 0; i < length; i ++) {
1825 result [i] = bingetu8 (f);
1826 }
1827 }
1828 result [length] = U'\0';
1829 return result;
1830 } catch (MelderError) {
1831 Melder_throw (U"Text not read from a binary file.");
1832 }
1833 }
1834
bingetw16(FILE * f)1835 autostring32 bingetw16 (FILE *f) {
1836 try {
1837 autostring32 result;
1838 uint16 length = bingetu16 (f);
1839 if (length == 0xFFFF) { // an escape for encoding
1840 /*
1841 UTF-16
1842 */
1843 length = bingetu16 (f);
1844 result = autostring32 (length);
1845 for (uint16 i = 0; i < length; i ++) {
1846 char32 kar = (char32) (char16) bingetu16 (f);
1847 if ((kar & 0x00'F800) == 0x00'D800) {
1848 if (kar > 0x00'DBFF)
1849 Melder_throw (U"Incorrect Unicode value (first surrogate member ", kar, U").");
1850 char32 kar2 = (char32) (char16) bingetu16 (f);
1851 if (kar2 < 0x00'DC00 || kar2 > 0x00'DFFF)
1852 Melder_throw (U"Incorrect Unicode value (second surrogate member ", kar2, U").");
1853 result [i] = (((kar & 0x00'03FF) << 10) | (kar2 & 0x00'03FF)) + 0x01'0000;
1854 } else {
1855 result [i] = kar;
1856 }
1857 }
1858 } else {
1859 /*
1860 ASCII
1861 */
1862 result = autostring32 (length);
1863 for (unsigned short i = 0; i < length; i ++) {
1864 result [i] = (char32) (char8) bingetu8 (f);
1865 }
1866 }
1867 result [length] = U'\0';
1868 return result;
1869 } catch (MelderError) {
1870 Melder_throw (U"Text not read from a binary file.");
1871 }
1872 }
1873
bingetw32(FILE * f)1874 autostring32 bingetw32 (FILE *f) {
1875 try {
1876 autostring32 result;
1877 uint32 length = bingetu32 (f);
1878 if (length == 0xFFFF'FFFF) { // an escape for encoding
1879 /*
1880 UTF-16
1881 */
1882 length = bingetu32 (f);
1883 result = autostring32 (length);
1884 for (uint32 i = 0; i < length; i ++) {
1885 char32 kar = bingetu16 (f);
1886 if ((kar & 0x00'F800) == 0x00'D800) {
1887 if (kar > 0x00'DBFF)
1888 Melder_throw (U"Incorrect Unicode value (first surrogate member ", kar, U").");
1889 char32 kar2 = bingetu16 (f);
1890 if (kar2 < 0x00'DC00 || kar2 > 0x00'DFFF)
1891 Melder_throw (U"Incorrect Unicode value (second surrogate member ", kar2, U").");
1892 result [i] = (((kar & 0x00'03FF) << 10) | (kar2 & 0x00'03FF)) + 0x01'0000;
1893 } else {
1894 result [i] = kar;
1895 }
1896 }
1897 } else {
1898 /*
1899 ASCII
1900 */
1901 result = autostring32 (length);
1902 for (uint32 i = 0; i < length; i ++) {
1903 result [i] = bingetu8 (f);
1904 }
1905 }
1906 result [length] = U'\0';
1907 return result;
1908 } catch (MelderError) {
1909 Melder_throw (U"Text not read from a binary file.");
1910 }
1911 }
1912
binputs8(const char * s,FILE * f)1913 void binputs8 (const char *s, FILE *f) {
1914 try {
1915 if (! s) {
1916 binputu8 (0, f);
1917 } else {
1918 size_t length = strlen (s);
1919 if (length > UINT8_MAX) {
1920 Melder_warning (U"Text of ", length, U" characters truncated to 255 characters.");
1921 length = UINT8_MAX;
1922 }
1923 binputu8 (length, f);
1924 if (fwrite (s, sizeof (char), length, f) != length)
1925 Melder_throw (U"Error in file while trying to write ", length, U" one-byte characters.");
1926 }
1927 } catch (MelderError) {
1928 Melder_throw (U"Text not written to a binary file.");
1929 }
1930 }
1931
binputs16(const char * s,FILE * f)1932 void binputs16 (const char *s, FILE *f) {
1933 try {
1934 if (! s) {
1935 binputu16 (0, f);
1936 } else {
1937 size_t length = strlen (s);
1938 if (length > UINT16_MAX) {
1939 Melder_warning (U"Text of ", length, U" characters truncated to 65535 characters.");
1940 length = UINT16_MAX;
1941 }
1942 binputu16 ((uint16) length, f); // safe conversion down
1943 if (fwrite (s, sizeof (char), length, f) != length)
1944 Melder_throw (U"Error in file while trying to write ", length, U" one-byte characters.");
1945 }
1946 } catch (MelderError) {
1947 Melder_throw (U"Text not written to a binary file.");
1948 }
1949 }
1950
binputs32(const char * s,FILE * f)1951 void binputs32 (const char *s, FILE *f) {
1952 try {
1953 if (! s) {
1954 binputu32 (0, f);
1955 } else {
1956 size_t length = strlen (s);
1957 if (length > UINT32_MAX) {
1958 Melder_warning (U"Text of ", length, U" characters truncated to 4,294,967,295 characters.");
1959 length = UINT32_MAX;
1960 }
1961 binputu32 (length, f);
1962 if (fwrite (s, sizeof (char), length, f) != length)
1963 Melder_throw (U"Error in file while trying to write ", length, U" one-byte characters.");
1964 }
1965 } catch (MelderError) {
1966 Melder_throw (U"Text not written to a binary file.");
1967 }
1968 }
1969
binpututf16(char32 kar,FILE * f)1970 static inline void binpututf16 (char32 kar, FILE *f) {
1971 if (kar <= 0x00FFFF) {
1972 binputu16 ((uint16) kar, f); // truncate to lower 16 bits
1973 } else if (kar <= 0x10'FFFF) {
1974 kar -= 0x01'0000;
1975 binputu16 ((uint16) (0x00'D800 | (kar >> 10)), f);
1976 binputu16 ((uint16) (0x00'DC00 | (kar & 0x00'03FF)), f);
1977 } else {
1978 Melder_fatal (U"Impossible Unicode value.");
1979 }
1980 }
1981
binputw8(conststring32 s,FILE * f)1982 void binputw8 (conststring32 s, FILE *f) {
1983 try {
1984 if (! s) {
1985 binputu8 (0, f);
1986 } else {
1987 uint32 length = str32len (s);
1988 if (length > UINT8_MAX - 1) {
1989 Melder_warning (U"Text of ", length, U" characters truncated to 254 characters.");
1990 length = UINT8_MAX - 1;
1991 }
1992 if (Melder_isValidAscii (s)) {
1993 /*
1994 * ASCII
1995 */
1996 binputu8 (length, f);
1997 for (size_t i = 0; i < length; i ++) {
1998 binputu8 ((unsigned int) (char) s [i], f);
1999 }
2000 } else {
2001 /*
2002 * UTF-16
2003 */
2004 binputu8 (0xFF, f); // an escape for multibyte encoding
2005 binputu8 (length, f);
2006 for (size_t i = 0; i < length; i ++) {
2007 binpututf16 (s [i], f);
2008 }
2009 }
2010 }
2011 } catch (MelderError) {
2012 Melder_throw (U"Text not written to a binary file.");
2013 }
2014 }
2015
binputw16(conststring32 s,FILE * f)2016 void binputw16 (conststring32 s, FILE *f) {
2017 try {
2018 if (! s) {
2019 binputu16 (0, f);
2020 } else {
2021 int64 length = str32len (s);
2022 if (length > UINT16_MAX - 1) {
2023 Melder_warning (U"Text of ", length, U" characters truncated to 65534 characters.");
2024 length = UINT16_MAX - 1;
2025 }
2026 if (Melder_isValidAscii (s)) {
2027 /*
2028 * ASCII
2029 */
2030 binputu16 ((uint16) length, f);
2031 for (int64 i = 0; i < length; i ++) {
2032 binputu8 ((unsigned int) (char8) s [i], f);
2033 }
2034 } else {
2035 /*
2036 * UTF-16
2037 */
2038 binputu16 (0xFFFF, f); // an escape for multibyte encoding
2039 binputu16 ((uint16) length, f);
2040 for (int64 i = 0; i < length; i ++) {
2041 binpututf16 (s [i], f);
2042 }
2043 }
2044 }
2045 } catch (MelderError) {
2046 Melder_throw (U"Text not written to a binary file.");
2047 }
2048 }
2049
binputw32(conststring32 s,FILE * f)2050 void binputw32 (conststring32 s, FILE *f) {
2051 try {
2052 if (! s) {
2053 binputu32 (0, f);
2054 } else {
2055 int64 length = str32len (s);
2056 if (length > UINT32_MAX - 1) {
2057 Melder_warning (U"Text of ", length, U" characters truncated to 4,294,967,294 characters.");
2058 length = UINT32_MAX - 1;
2059 }
2060 if (Melder_isValidAscii (s)) {
2061 /*
2062 * ASCII
2063 */
2064 binputu32 ((uint32) length, f);
2065 for (int64 i = 0; i < length; i ++) {
2066 binputu8 ((unsigned int) (char) s [i], f);
2067 }
2068 } else {
2069 /*
2070 * UTF-16
2071 */
2072 binputu32 (0xFFFF'FFFF, f); // an escape for multibyte encoding
2073 binputu32 ((uint32) length, f);
2074 for (int64 i = 0; i < length; i ++) {
2075 binpututf16 (s [i], f);
2076 }
2077 }
2078 }
2079 } catch (MelderError) {
2080 Melder_throw (U"Text not written to a binary file.");
2081 }
2082 }
2083
2084 /* End of file abcio.cpp */
2085