MelderFile.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /* MelderFile.cpp
  2. *
  3. * Copyright (C) 1992-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. #include "melder.h"
  19. #include "../kar/UnicodeData.h"
  20. extern "C" int FLAC__stream_encoder_finish (FLAC__StreamEncoder *);
  21. extern "C" void FLAC__stream_encoder_delete (FLAC__StreamEncoder *);
  22. /*
  23. * Functions for wrapping the file pointers.
  24. */
  25. MelderFile MelderFile_open (MelderFile me) {
  26. my filePointer = Melder_fopen (me, "rb");
  27. my openForReading = true;
  28. return me;
  29. }
  30. char * MelderFile_readLine (MelderFile me) {
  31. if (! my filePointer)
  32. return nullptr;
  33. if (feof (my filePointer))
  34. return nullptr;
  35. static char *buffer;
  36. static integer capacity;
  37. if (! buffer) {
  38. buffer = Melder_malloc (char, capacity = 100);
  39. }
  40. integer i = 0;
  41. for (; true; i ++) {
  42. if (i >= capacity) {
  43. buffer = (char *) Melder_realloc (buffer, capacity *= 2);
  44. }
  45. int c = fgetc (my filePointer);
  46. if (feof (my filePointer))
  47. break;
  48. if (c == '\n') {
  49. c = fgetc (my filePointer);
  50. if (feof (my filePointer)) break; // ignore last empty line (Unix)
  51. ungetc (c, my filePointer);
  52. break; // Unix line separator
  53. }
  54. if (c == '\r') {
  55. c = fgetc (my filePointer);
  56. if (feof (my filePointer)) break; // ignore last empty line (Macintosh)
  57. if (c == '\n') {
  58. c = fgetc (my filePointer);
  59. if (feof (my filePointer)) break; // ignore last empty line (Windows)
  60. ungetc (c, my filePointer);
  61. break; // Windows line separator
  62. }
  63. ungetc (c, my filePointer);
  64. break; // Macintosh line separator
  65. }
  66. buffer [i] = c;
  67. }
  68. buffer [i] = '\0';
  69. return buffer;
  70. }
  71. MelderFile MelderFile_create (MelderFile me) {
  72. my filePointer = Melder_fopen (me, "wb");
  73. my openForWriting = true; // a bit superfluous (will have been set by Melder_fopen)
  74. return me;
  75. }
  76. void MelderFile_write (MelderFile file, conststring32 string) {
  77. if (! file -> filePointer)
  78. return;
  79. if (! string)
  80. return;
  81. int64 length = str32len (string);
  82. FILE *f = file -> filePointer;
  83. if (file -> outputEncoding == kMelder_textOutputEncoding_ASCII || file -> outputEncoding == kMelder_textOutputEncoding_ISO_LATIN1) {
  84. for (int64 i = 0; i < length; i ++) {
  85. char kar = (char) (char8) string [i]; // truncate
  86. if (kar == '\n' && file -> requiresCRLF)
  87. putc (13, f);
  88. putc (kar, f);
  89. }
  90. } else if (file -> outputEncoding == (unsigned long) kMelder_textOutputEncoding::UTF8) {
  91. for (int64 i = 0; i < length; i ++) {
  92. char32 kar = string [i];
  93. if (kar <= 0x00'007F) {
  94. if (kar == U'\n' && file -> requiresCRLF)
  95. putc (13, f);
  96. putc ((int) kar, f); // guarded conversion down
  97. } else if (kar <= 0x00'07FF) {
  98. putc (0xC0 | (kar >> 6), f);
  99. putc (0x80 | (kar & 0x00'003F), f);
  100. } else if (kar <= 0x00'FFFF) {
  101. putc (0xE0 | (kar >> 12), f);
  102. putc (0x80 | ((kar >> 6) & 0x00'003F), f);
  103. putc (0x80 | (kar & 0x00'003F), f);
  104. } else {
  105. putc (0xF0 | (kar >> 18), f);
  106. putc (0x80 | ((kar >> 12) & 0x00'003F), f);
  107. putc (0x80 | ((kar >> 6) & 0x00'003F), f);
  108. putc (0x80 | (kar & 0x00'003F), f);
  109. }
  110. }
  111. } else {
  112. for (int64 i = 0; i < length; i ++) {
  113. char32 kar = string [i];
  114. if (kar == U'\n' && file -> requiresCRLF)
  115. binputu16 (13, f);
  116. if (kar <= 0x00'FFFF) {
  117. binputu16 ((char16) kar, f);
  118. } else if (kar <= 0x10'FFFF) {
  119. kar -= 0x01'0000;
  120. binputu16 (0xD800 | (char16) (kar >> 10), f);
  121. binputu16 (0xDC00 | (char16) ((char16) kar & 0x03ff), f);
  122. } else {
  123. binputu16 (UNICODE_REPLACEMENT_CHARACTER, f);
  124. }
  125. }
  126. }
  127. }
  128. void MelderFile_writeCharacter (MelderFile file, char32 kar) {
  129. FILE *f = file -> filePointer;
  130. if (! f)
  131. return;
  132. if (file -> outputEncoding == kMelder_textOutputEncoding_ASCII || file -> outputEncoding == kMelder_textOutputEncoding_ISO_LATIN1) {
  133. if (kar == U'\n' && file -> requiresCRLF)
  134. putc (13, f);
  135. putc ((int) kar, f);
  136. } else if (file -> outputEncoding == (unsigned long) kMelder_textOutputEncoding::UTF8) {
  137. if (kar <= 0x00'007F) {
  138. if (kar == U'\n' && file -> requiresCRLF)
  139. putc (13, f);
  140. putc ((int) kar, f); // guarded conversion down
  141. } else if (kar <= 0x00'07FF) {
  142. putc (0xC0 | (kar >> 6), f);
  143. putc (0x80 | (kar & 0x00'003F), f);
  144. } else if (kar <= 0x00'FFFF) {
  145. putc (0xE0 | (kar >> 12), f);
  146. putc (0x80 | ((kar >> 6) & 0x00'003F), f);
  147. putc (0x80 | (kar & 0x00'003F), f);
  148. } else {
  149. putc (0xF0 | (kar >> 18), f);
  150. putc (0x80 | ((kar >> 12) & 0x00'003F), f);
  151. putc (0x80 | ((kar >> 6) & 0x00'003F), f);
  152. putc (0x80 | (kar & 0x00'003F), f);
  153. }
  154. } else {
  155. if (kar == U'\n' && file -> requiresCRLF)
  156. binputu16 (13, f);
  157. if (kar <= 0x00'FFFF) {
  158. binputu16 ((uint16) kar, f);
  159. } else if (kar <= 0x10'FFFF) {
  160. kar -= 0x01'0000;
  161. binputu16 (0xD800 | (uint16) (kar >> 10), f);
  162. binputu16 (0xDC00 | (uint16) ((uint16) kar & 0x00'03ff), f);
  163. } else {
  164. binputu16 (UNICODE_REPLACEMENT_CHARACTER, f);
  165. }
  166. }
  167. }
  168. void MelderFile_seek (MelderFile me, integer position, int direction) {
  169. if (! my filePointer)
  170. return;
  171. if (fseek (my filePointer, position, direction)) {
  172. fclose (my filePointer);
  173. my filePointer = nullptr;
  174. Melder_throw (U"Cannot seek in file ", me, U".");
  175. }
  176. }
  177. integer MelderFile_tell (MelderFile me) {
  178. if (! my filePointer)
  179. return 0;
  180. integer result = ftell (my filePointer);
  181. if (result == -1) {
  182. fclose (my filePointer);
  183. my filePointer = nullptr;
  184. Melder_throw (U"Cannot tell in file ", me, U".");
  185. }
  186. return result;
  187. }
  188. void MelderFile_rewind (MelderFile me) {
  189. if (! my filePointer)
  190. return;
  191. rewind (my filePointer);
  192. }
  193. static void _MelderFile_close (MelderFile me, bool mayThrow) {
  194. if (my outputEncoding == kMelder_textOutputEncoding_FLAC) {
  195. if (my flacEncoder) {
  196. FLAC__stream_encoder_finish (my flacEncoder); // This already calls fclose! BUG: we cannot get any error messages out.
  197. FLAC__stream_encoder_delete (my flacEncoder);
  198. }
  199. } else if (my filePointer) {
  200. if (mayThrow) {
  201. Melder_fclose (me, my filePointer);
  202. } else {
  203. fclose (my filePointer);
  204. }
  205. }
  206. /* Set everything to zero, except paths (they stay around for error messages and the like). */
  207. my filePointer = nullptr;
  208. my openForWriting = my openForReading = false;
  209. my indent = 0;
  210. my flacEncoder = nullptr;
  211. }
  212. void MelderFile_close (MelderFile me) {
  213. _MelderFile_close (me, true);
  214. }
  215. void MelderFile_close_nothrow (MelderFile me) {
  216. _MelderFile_close (me, false);
  217. }
  218. /* End of file MelderFile.cpp */