abcio.cpp 67 KB

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