You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

gbfile.cc 25KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283
  1. /*
  2. Common GPSBabel file I/O API
  3. Copyright (C) 2006,2007,2008 Olaf Klein, o.b.klein@gpsbabel.org
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  15. */
  16. #include "defs.h"
  17. #include "gbfile.h"
  18. #include "src/core/logging.h"
  19. #include <assert.h>
  20. #include <stdarg.h> // for va_copy
  21. #include <stdio.h>
  22. #if __WIN32__
  23. /* taken from minigzip.c (part of the zlib project) */
  24. # include <fcntl.h>
  25. # include <io.h>
  26. # define SET_BINARY_MODE(file) _setmode(fileno(file), O_BINARY)
  27. #else
  28. # define SET_BINARY_MODE(file)
  29. #endif
  30. #define MYNAME "gbfile"
  31. #define NO_ZLIB MYNAME ": No zlib support.\n"
  32. /* About the ZLIB_INHIBITED stuff:
  33. *
  34. * If a user goes out of his way to build with ZLIB_INHIBITED set,
  35. * we jettison our use of zlib entirely within this file, replacing
  36. * all calls out to zlib with calls to abort() as that's an internal
  37. * consistency error.
  38. *
  39. */
  40. /*******************************************************************************/
  41. /* %%% file api wrappers %%% */
  42. /*******************************************************************************/
  43. #if !ZLIB_INHIBITED
  44. /*******************************************************************************/
  45. /* %%% Zlib file api %%% */
  46. /*******************************************************************************/
  47. static gbfile*
  48. gzapi_open(gbfile* self, const char* mode)
  49. {
  50. char openmode[32];
  51. self->gzapi = 1;
  52. /* under non-posix systems files MUST be opened in binary mode */
  53. strcpy(openmode, mode);
  54. if (strchr(mode, 'b') == NULL) {
  55. strncat(openmode, "b", sizeof(openmode) - strlen(openmode) - 1);
  56. }
  57. if (self->is_pipe) {
  58. FILE* fd;
  59. if (self->mode == 'r') {
  60. fd = stdin;
  61. } else {
  62. fd = stdout;
  63. }
  64. SET_BINARY_MODE(fd);
  65. self->handle.gz = gzdopen(fileno(fd), openmode);
  66. } else {
  67. self->handle.gz = gzopen(self->name, openmode);
  68. }
  69. if (self->handle.gz == NULL) {
  70. fatal("%s: Cannot %s file '%s'!\n",
  71. self->module,
  72. (self->mode == 'r') ? "open" : "create",
  73. self->name);
  74. }
  75. return self;
  76. }
  77. static int
  78. gzapi_close(gbfile* self)
  79. {
  80. return gzclose(self->handle.gz);
  81. }
  82. static int
  83. gzapi_seek(gbfile* self, int32_t offset, int whence)
  84. {
  85. int result;
  86. assert(whence != SEEK_END);
  87. if ((whence == SEEK_CUR) && (self->back != -1)) {
  88. offset--;
  89. }
  90. result = gzseek(self->handle.gz, offset, whence);
  91. self->back = -1;
  92. if (result < 0) {
  93. if (self->is_pipe) {
  94. fatal("%s: This format cannot be used in piped commands!\n", self->module);
  95. }
  96. fatal("%s: online compression not yet supported for this format!", self->module);
  97. }
  98. return 0;
  99. }
  100. static gbsize_t
  101. gzapi_read(void* buf, const gbsize_t size, const gbsize_t members, gbfile* self)
  102. {
  103. int result = 0;
  104. char* target = (char*) buf;
  105. int count = size * members;
  106. if (self->back != -1) {
  107. *target++ = self->back;
  108. count--;
  109. result++;
  110. self->back = -1;
  111. }
  112. result += gzread(self->handle.gz, target, count);
  113. /* Check for an incomplete READ */
  114. if ((members == 1) && (size > 1) && (result > 0) && (result < (int)size)) {
  115. fatal("%s: Unexpected end of file (EOF)!\n", self->module);
  116. }
  117. result /= size;
  118. if ((result < 0) || ((gbsize_t)result < members)) {
  119. int errnum;
  120. const char* errtxt;
  121. errtxt = gzerror(self->handle.gz, &errnum);
  122. /* Workaround for zlib bug: buffer error on empty files */
  123. if ((errnum == Z_BUF_ERROR) && (gztell(self->handle.gz) == 0)) {
  124. return (gbsize_t) 0;
  125. }
  126. if ((errnum != Z_STREAM_END) && (errnum != 0))
  127. fatal("%s: zlib returned error %d ('%s')!\n",
  128. self->module, errnum, errtxt);
  129. }
  130. return (gbsize_t) result;
  131. }
  132. static gbsize_t
  133. gzapi_write(const void* buf, const gbsize_t size, const gbsize_t members, gbfile* self)
  134. {
  135. return gzwrite(self->handle.gz, buf, size * members) / size;
  136. }
  137. static int
  138. gzapi_flush(gbfile* self)
  139. {
  140. return gzflush(self->handle.gz, Z_SYNC_FLUSH);
  141. }
  142. static gbsize_t
  143. gzapi_tell(gbfile* self)
  144. {
  145. gbsize_t result;
  146. result = gztell(self->handle.gz);
  147. if (self->back != -1) {
  148. result--;
  149. }
  150. return result;
  151. }
  152. static int
  153. gzapi_eof(gbfile* self)
  154. {
  155. int res = 0;
  156. if (self->back != -1) {
  157. return res;
  158. }
  159. res = gzeof(self->handle.gz);
  160. if (!res) {
  161. unsigned char test;
  162. int len = gzread(self->handle.gz, &test, 1);
  163. if (len == 1) {
  164. /* No EOF, put the single byte back into stream */
  165. self->back = test;
  166. } else {
  167. /* we are at the end of the file */
  168. if (global_opts.debug_level > 0) {
  169. /* now gzeof() should return 1 */
  170. is_fatal(!gzeof(self->handle.gz), "zlib gzeof error!\n");
  171. }
  172. res = 1;
  173. }
  174. }
  175. return res;
  176. }
  177. static int
  178. gzapi_ungetc(const int c, gbfile* self)
  179. {
  180. if (self->back == -1) {
  181. self->back = c;
  182. } else {
  183. fatal(MYNAME ": Cannot store more than one byte back!\n");
  184. }
  185. return c;
  186. }
  187. static void
  188. gzapi_clearerr(gbfile* self)
  189. {
  190. gzclearerr(self->handle.gz);
  191. }
  192. static int
  193. gzapi_error(gbfile* self)
  194. {
  195. int errnum;
  196. (void)gzerror(self->handle.gz, &errnum);
  197. return errnum;
  198. }
  199. #endif // #if !ZLIB_INHIBITED
  200. /*******************************************************************************/
  201. /* %%% Standard C file api %%% */
  202. /*******************************************************************************/
  203. static gbfile*
  204. stdapi_open(gbfile* self, const char* mode)
  205. {
  206. self->handle.std = xfopen(self->name, mode, self->module);
  207. return self;
  208. }
  209. static int
  210. stdapi_close(gbfile* self)
  211. {
  212. return fclose(self->handle.std);
  213. }
  214. static int
  215. stdapi_seek(gbfile* self, int32_t offset, int whence)
  216. {
  217. int result;
  218. gbsize_t pos = 0;
  219. if (whence != SEEK_SET) {
  220. pos = ftell(self->handle.std);
  221. }
  222. result = fseek(self->handle.std, offset, whence);
  223. if (result != 0) {
  224. switch (whence) {
  225. case SEEK_CUR:
  226. case SEEK_END:
  227. pos = pos + offset;
  228. break;
  229. case SEEK_SET:
  230. pos = offset;
  231. break;
  232. default:
  233. fatal("%s: Unknown seek operation (%d) for file %s!\n",
  234. self->module, whence, self->name);
  235. }
  236. fatal("%s: Unable to set file (%s) to position (%llu)!\n",
  237. self->module, self->name, (long long unsigned) pos);
  238. }
  239. return 0;
  240. }
  241. static gbsize_t
  242. stdapi_read(void* buf, const gbsize_t size, const gbsize_t members, gbfile* self)
  243. {
  244. int errno;
  245. gbsize_t result = fread(buf, size, members, self->handle.std);
  246. if ((result < members) && (errno = ferror(self->handle.std))) {
  247. fatal("%s: Error %d occured during read of file '%s'!\n",
  248. self->module, errno, self->name);
  249. }
  250. return result;
  251. }
  252. static gbsize_t
  253. stdapi_write(const void* buf, const gbsize_t size, const gbsize_t members, gbfile* self)
  254. {
  255. return fwrite(buf, size, members, self->handle.std);
  256. }
  257. static int
  258. stdapi_flush(gbfile* self)
  259. {
  260. return fflush(self->handle.std);
  261. }
  262. static gbsize_t
  263. stdapi_tell(gbfile* self)
  264. {
  265. return ftell(self->handle.std);
  266. }
  267. static int
  268. stdapi_eof(gbfile* self)
  269. {
  270. return feof(self->handle.std);
  271. }
  272. static int
  273. stdapi_ungetc(const int c, gbfile* self)
  274. {
  275. return ungetc(c, self->handle.std);
  276. }
  277. static void
  278. stdapi_clearerr(gbfile* self)
  279. {
  280. clearerr(self->handle.std);
  281. }
  282. static int
  283. stdapi_error(gbfile* self)
  284. {
  285. return ferror(self->handle.std);
  286. }
  287. /*******************************************************************************/
  288. /* %%% Memory stream (memapi) %%% */
  289. /*******************************************************************************/
  290. static gbfile*
  291. memapi_open(gbfile* self, const char* mode)
  292. {
  293. (void)mode;
  294. self->mempos = 0;
  295. self->memsz = 0;
  296. self->handle.mem = NULL;
  297. return self;
  298. }
  299. static int
  300. memapi_close(gbfile* self)
  301. {
  302. if (self->handle.mem) {
  303. xfree(self->handle.mem);
  304. }
  305. return 0;
  306. }
  307. static int
  308. memapi_seek(gbfile* self, int32_t offset, int whence)
  309. {
  310. long long pos = (int)self->mempos;
  311. switch (whence) {
  312. case SEEK_CUR:
  313. case SEEK_END:
  314. pos = pos + offset;
  315. break;
  316. case SEEK_SET:
  317. pos = offset;
  318. break;
  319. }
  320. if ((pos < 0) || (pos > self->memlen)) {
  321. return -1;
  322. }
  323. self->mempos = pos;
  324. return 0;
  325. }
  326. static gbsize_t
  327. memapi_read(void* buf, const gbsize_t size, const gbsize_t members, gbfile* self)
  328. {
  329. gbsize_t count;
  330. gbsize_t result = (self->memlen - self->mempos) / size;
  331. if (result > members) {
  332. result = members;
  333. }
  334. count = result * size;
  335. if (count) {
  336. memcpy(buf, self->handle.mem + self->mempos, count);
  337. self->mempos += count;
  338. }
  339. return result;
  340. }
  341. static gbsize_t
  342. memapi_write(const void* buf, const gbsize_t size, const gbsize_t members, gbfile* self)
  343. {
  344. gbsize_t count;
  345. if ((size == 0) && (members == 0)) { /* truncate stream */
  346. self->memlen = self->mempos;
  347. return 0;
  348. }
  349. count = size * members;
  350. if (self->mempos + count > self->memsz) {
  351. self->memsz = ((self->mempos + count + 4095) / 4096) * 4096;
  352. self->handle.mem = (unsigned char*) xrealloc(self->handle.mem, self->memsz);
  353. }
  354. memcpy(self->handle.mem + self->mempos, buf, count);
  355. self->mempos += count;
  356. if (self->mempos > self->memlen) {
  357. self->memlen = self->mempos;
  358. }
  359. return members;
  360. }
  361. static int
  362. memapi_flush(gbfile* self)
  363. {
  364. (void)self;
  365. return 0;
  366. }
  367. static gbsize_t
  368. memapi_tell(gbfile* self)
  369. {
  370. return self->mempos;
  371. }
  372. static int
  373. memapi_eof(gbfile* self)
  374. {
  375. return (self->mempos == self->memlen);
  376. }
  377. static int
  378. memapi_ungetc(const int c, gbfile* self)
  379. {
  380. if (self->mempos == 0) {
  381. return EOF;
  382. } else {
  383. self->mempos--;
  384. self->handle.mem[self->mempos] = (unsigned char) c;
  385. return c;
  386. }
  387. }
  388. static void
  389. memapi_clearerr(gbfile* self)
  390. {
  391. (void)self;
  392. return;
  393. }
  394. static int
  395. memapi_error(gbfile* self)
  396. {
  397. (void)self;
  398. return 0;
  399. }
  400. /* GPSBabel 'file' standard calls */
  401. /*
  402. * gbfopen: (as xfopen) plus the name of the calling GPSBabel module (MYNAME)
  403. */
  404. gbfile*
  405. gbfopen(const QString filename, const char* mode, const char* module)
  406. {
  407. gbfile* file;
  408. const char* m;
  409. int len;
  410. file = (gbfile*) xcalloc(1, sizeof(*file));
  411. file->module = xstrdup(module);
  412. file->mode = 'r'; // default
  413. file->binary = (strchr(mode, 'b') != NULL);
  414. file->back = -1;
  415. file->memapi = (filename == NULL);
  416. for (m = mode; *m; m++) {
  417. switch (tolower(*m)) {
  418. case 'r':
  419. file->mode = 'r';
  420. #if !ZLIB_INHIBITED
  421. file->gzapi = 1; /* native or transparent */
  422. #endif
  423. break;
  424. case 'w':
  425. file->mode = 'w';
  426. break;
  427. }
  428. }
  429. if (file->memapi) {
  430. file->gzapi = 0;
  431. file->name = xstrdup("(Memory stream)");
  432. file->fileclearerr = memapi_clearerr;
  433. file->fileclose = memapi_close;
  434. file->fileeof = memapi_eof;
  435. file->fileerror = memapi_error;
  436. file->fileflush = memapi_flush;
  437. file->fileopen = memapi_open;
  438. file->fileread = memapi_read;
  439. file->fileseek = memapi_seek;
  440. file->filetell = memapi_tell;
  441. file->fileungetc = memapi_ungetc;
  442. file->filewrite = memapi_write;
  443. } else {
  444. /* Be careful to convert back to local8Bit for these c based APIS */
  445. file->name = xstrdup(qPrintable(filename));
  446. file->is_pipe = (filename == "-");
  447. /* Do we have a '.gz' extension in the filename ? */
  448. len = strlen(file->name);
  449. if ((len > 3) && (case_ignore_strcmp(&file->name[len-3], ".gz") == 0)) {
  450. #if !ZLIB_INHIBITED
  451. /* force gzipped files on output */
  452. file->gzapi = 1;
  453. #else
  454. fatal(NO_ZLIB);
  455. #endif
  456. }
  457. if (file->gzapi) {
  458. #if !ZLIB_INHIBITED
  459. file->fileclearerr = gzapi_clearerr;
  460. file->fileclose = gzapi_close;
  461. file->fileeof = gzapi_eof;
  462. file->fileerror = gzapi_error;
  463. file->fileflush = gzapi_flush;
  464. file->fileopen = gzapi_open;
  465. file->fileread = gzapi_read;
  466. file->fileseek = gzapi_seek;
  467. file->filetell = gzapi_tell;
  468. file->fileungetc = gzapi_ungetc;
  469. file->filewrite = gzapi_write;
  470. #else
  471. /* This is the only runtime test we make */
  472. fatal("%s: Zlib was not included in this build.\n", file->module);
  473. #endif
  474. } else {
  475. file->fileclearerr = stdapi_clearerr;
  476. file->fileclose = stdapi_close;
  477. file->fileeof = stdapi_eof;
  478. file->fileerror = stdapi_error;
  479. file->fileflush = stdapi_flush;
  480. file->fileopen = stdapi_open;
  481. file->fileread = stdapi_read;
  482. file->fileseek = stdapi_seek;
  483. file->filetell = stdapi_tell;
  484. file->fileungetc = stdapi_ungetc;
  485. file->filewrite = stdapi_write;
  486. }
  487. }
  488. file->fileopen(file, mode);
  489. #ifdef DEBUG_MEM
  490. file->buffsz = 1;
  491. #else
  492. file->buffsz = 256;
  493. #endif
  494. file->buff = (char*) xmalloc(file->buffsz);
  495. return file;
  496. }
  497. /*
  498. * gbfopen_be: as gbfopen, but set the BIG-ENDIAN flag
  499. */
  500. gbfile*
  501. gbfopen_be(const QString filename, const char* mode, const char* module)
  502. {
  503. gbfile* result;
  504. result = gbfopen(filename, mode, module);
  505. result->big_endian = 1;
  506. return result;
  507. }
  508. /*
  509. * gbfclose: (as fclose)
  510. */
  511. void
  512. gbfclose(gbfile* file)
  513. {
  514. if (!file) {
  515. return;
  516. }
  517. file->fileclose(file);
  518. xfree(file->name);
  519. xfree(file->module);
  520. xfree(file->buff);
  521. xfree(file);
  522. }
  523. /*
  524. * gbfgetc: (as fgetc)
  525. */
  526. int
  527. gbfgetc(gbfile* file)
  528. {
  529. unsigned char c;
  530. /* errors are caught in gbfread */
  531. if (gbfread(&c, 1, 1, file) == 0) {
  532. return EOF;
  533. } else {
  534. return (unsigned int)c;
  535. }
  536. }
  537. /*
  538. * gbfgets: (as fgets)
  539. */
  540. QString
  541. gbfgets(char* buf, int len, gbfile* file)
  542. {
  543. char* result = buf;
  544. while (--len > 0) {
  545. int c = gbfgetc(file);
  546. if (c == EOF) {
  547. break;
  548. }
  549. *(unsigned char*)buf = (unsigned char)c;
  550. buf++;
  551. if (c == '\r') {
  552. c = gbfgetc(file);
  553. if ((c != '\n') && (c != EOF)) {
  554. gbfungetc(c, file);
  555. }
  556. break;
  557. } else if (c == '\n') {
  558. break;
  559. }
  560. }
  561. *buf = '\0';
  562. QString rv(result);
  563. return rv;
  564. }
  565. /*
  566. * gbfread: (as fread)
  567. */
  568. gbsize_t
  569. gbfread(void* buf, const gbsize_t size, const gbsize_t members, gbfile* file)
  570. {
  571. if ((size == 0) || (members == 0)) {
  572. return 0;
  573. }
  574. return file->fileread(buf, size, members, file);
  575. }
  576. // This probably makes an unnecessary alloc/copy, but keeps the above (kinda
  577. // goofy) calling signature.
  578. gbsize_t
  579. gbfread(QString& buf, const gbsize_t size,
  580. const gbsize_t members, gbfile* file)
  581. {
  582. QByteArray tmp;
  583. tmp.resize(members * size);
  584. gbsize_t retval = gbfread(tmp.data(), size, members, file);
  585. buf = QString(tmp);
  586. return retval;
  587. }
  588. /*
  589. * gbvfprintf: (as vfprintf)
  590. */
  591. int gbvfprintf(gbfile* file, const char* format, va_list ap)
  592. {
  593. int len;
  594. for (;;) {
  595. va_list args;
  596. va_copy(args, ap);
  597. len = vsnprintf(file->buff, file->buffsz, format, args);
  598. va_end(args);
  599. /* Unambiguous Success */
  600. if ((len > -1) && (len < file->buffsz)) {
  601. break;
  602. }
  603. /* First case: C99 behaviour. Len is correctly sized.
  604. * add space for null terminator. Next time through the
  605. * loop we're guaranteed success.
  606. *
  607. * Second case: SUS (and Windows) behaviour. We know it
  608. * doesn't fit, but we don't know how big it has to be.
  609. ` * double it and try again. We'll loop until we succeed.
  610. *
  611. * Since we keep the I/O buffer in the file handle, we
  612. * quickly reach a steady state on the size of these buffers.
  613. */
  614. if (len > -1) {
  615. file->buffsz = len + 1;
  616. } else {
  617. file->buffsz *= 2;
  618. }
  619. file->buff = (char*) xrealloc(file->buff, file->buffsz);
  620. }
  621. return gbfwrite(file->buff, 1, len, file);
  622. }
  623. /*
  624. * gbfprintf: (as fprintf)
  625. */
  626. int
  627. gbfprintf(gbfile* file, const char* format, ...)
  628. {
  629. va_list args;
  630. int result;
  631. va_start(args, format);
  632. result = gbvfprintf(file, format, args);
  633. va_end(args);
  634. return result;
  635. }
  636. /*
  637. * gbfputc: (as fputc)
  638. */
  639. int
  640. gbfputc(int c, gbfile* file)
  641. {
  642. unsigned char temp = (unsigned int) c;
  643. gbfwrite(&temp, 1, 1, file);
  644. return c;
  645. }
  646. /*
  647. * gbfputs: (as fputs)
  648. */
  649. // This is a depressing hack, meant to ease the pain from C strings
  650. // to QStrings, which are consitently encoded.
  651. int
  652. gbfputs(const QString& s, gbfile* file)
  653. {
  654. QByteArray qs = s.toUtf8();
  655. int rv = gbfwrite(qs.constData(), 1, qs.size(), file);
  656. return rv;
  657. }
  658. /*
  659. * gbfwrite: (as fwrite)
  660. */
  661. int
  662. gbfwrite(const void* buf, const gbsize_t size, const gbsize_t members, gbfile* file)
  663. {
  664. unsigned int result;
  665. result = file->filewrite(buf, size, members, file);
  666. if (result != members) {
  667. fatal("%s: Could not write %lld bytes to %s (result %d)!\n",
  668. file->module,
  669. (long long int)(members - result) * size,
  670. file->name,
  671. result);
  672. }
  673. return result;
  674. }
  675. /*
  676. * gbfflush: (as fflush)
  677. */
  678. int
  679. gbfflush(gbfile* file)
  680. {
  681. return file->fileflush(file);
  682. }
  683. /*
  684. * gbfclearerr: (as clearerr)
  685. */
  686. void
  687. gbfclearerr(gbfile* file)
  688. {
  689. file->fileclearerr(file);
  690. }
  691. /*
  692. * gbferror: (as ferror)
  693. */
  694. int
  695. gbferror(gbfile* file)
  696. {
  697. return file->fileerror(file);
  698. }
  699. /*
  700. * gbfrewind: (as frewind)
  701. */
  702. void
  703. gbfrewind(gbfile* file)
  704. {
  705. (void) gbfseek(file, 0, SEEK_SET);
  706. gbfclearerr(file);
  707. }
  708. /*
  709. * gbfseek: (as fseek)
  710. */
  711. int
  712. gbfseek(gbfile* file, int32_t offset, int whence)
  713. {
  714. return file->fileseek(file, offset, whence);
  715. }
  716. /*
  717. * gbftell: (as ftell)
  718. */
  719. gbsize_t
  720. gbftell(gbfile* file)
  721. {
  722. gbsize_t result = file->filetell(file);
  723. if ((signed) result == -1)
  724. fatal("%s: Could not determine position of file '%s'!\n",
  725. file->module, file->name);
  726. return result;
  727. }
  728. /*
  729. * gbfeof: (as feof)
  730. */
  731. int
  732. gbfeof(gbfile* file)
  733. {
  734. return file->fileeof(file);
  735. }
  736. /*
  737. * gbfungetc: (as fungetc)
  738. */
  739. int
  740. gbfungetc(const int c, gbfile* file)
  741. {
  742. return file->fileungetc(c, file);
  743. }
  744. /* GPSBabel 'file' enhancements */
  745. /*
  746. * gbfgetint32: read a signed 32-bit integer from input stream
  747. */
  748. int32_t
  749. gbfgetint32(gbfile* file)
  750. {
  751. char buf[4];
  752. is_fatal((gbfread(&buf, 1, sizeof(buf), file) != sizeof(buf)),
  753. "%s: Unexpected end of file (%s)!\n", file->module, file->name);
  754. if (file->big_endian) {
  755. return be_read32(buf);
  756. } else {
  757. return le_read32(buf);
  758. }
  759. }
  760. /*
  761. * gbfgetint16: read a signed 16-bit integer from input stream
  762. */
  763. int16_t
  764. gbfgetint16(gbfile* file)
  765. {
  766. char buf[2];
  767. is_fatal((gbfread(&buf, 1, sizeof(buf), file) != sizeof(buf)),
  768. "%s: Unexpected end of file (%s)!\n", file->module, file->name);
  769. if (file->big_endian) {
  770. return be_read16(buf);
  771. } else {
  772. return le_read16(buf);
  773. }
  774. }
  775. /*
  776. * gbfgetdbl: read a double value (8 byte, double precision) from input stream
  777. */
  778. double
  779. gbfgetdbl(gbfile* file)
  780. {
  781. char buf[8];
  782. is_fatal((gbfread(&buf, 1, sizeof(buf), file) != sizeof(buf)),
  783. "%s: Unexpected end of file (%s)!\n", file->module, file->name);
  784. return endian_read_double(buf, ! file->big_endian);
  785. }
  786. /*
  787. * gbfgetflt: read a float value (4 byte, single precision) from input stream
  788. */
  789. float
  790. gbfgetflt(gbfile* file)
  791. {
  792. char buf[4];
  793. is_fatal((gbfread(&buf, 1, sizeof(buf), file) != sizeof(buf)),
  794. "%s: Unexpected end of file (%s)!\n", file->module, file->name);
  795. return endian_read_float(buf, ! file->big_endian);
  796. }
  797. /*
  798. * gbfgetcstr: Reads a string from file until either a '\0' or eof.
  799. * The result is a temporary allocated entity: use it or free it!
  800. */
  801. char*
  802. gbfgetcstr_old(gbfile* file)
  803. {
  804. char* result;
  805. int len = 0;
  806. char* str = file->buff;
  807. for (;;) {
  808. int c = gbfgetc(file);
  809. if ((c == 0) || (c == EOF)) {
  810. break;
  811. }
  812. if (len == file->buffsz) {
  813. file->buffsz += 64;
  814. str = file->buff = (char*) xrealloc(file->buff, file->buffsz + 1);
  815. }
  816. str[len] = c;
  817. len++;
  818. }
  819. result = (char*) xmalloc(len + 1);
  820. if (len > 0) {
  821. memcpy(result, str, len);
  822. }
  823. result[len] = '\0';
  824. return result;
  825. }
  826. QString
  827. gbfgetcstr(gbfile* file)
  828. {
  829. char* result = gbfgetcstr_old(file);
  830. QString rv(result);
  831. xfree(result);
  832. return rv;
  833. }
  834. /*
  835. * gbfgetpstr: Reads a pascal string (first byte is length) from file.
  836. * The result is a temporary allocated entity: use it or free it!
  837. */
  838. QString
  839. gbfgetpstr(gbfile* file)
  840. {
  841. int len = gbfgetc(file);
  842. QByteArray ba;
  843. ba.resize(len);
  844. gbfread(ba.data(), 1, len, file);
  845. return QString(ba);
  846. }
  847. static char*
  848. gbfgetucs2str(gbfile* file)
  849. {
  850. int len = 0;
  851. char* result = file->buff;
  852. for (;;) {
  853. char buff[8];
  854. int clen;
  855. int c0, c1;
  856. c0 = gbfgetc(file);
  857. if ((c0 == EOF) && (len == 0)) {
  858. return NULL;
  859. }
  860. c1 = gbfgetc(file);
  861. if ((c1 == EOF) && (len == 0)) {
  862. return NULL;
  863. }
  864. if (file->big_endian) {
  865. c0 = c1 | (c0 << 8);
  866. } else {
  867. c0 = c0 | (c1 << 8);
  868. }
  869. if (c0 == '\r') {
  870. c0 = gbfgetc(file);
  871. if ((c0 == EOF) && (len == 0)) {
  872. return NULL;
  873. }
  874. c1 = gbfgetc(file);
  875. if ((c1 == EOF) && (len == 0)) {
  876. return NULL;
  877. }
  878. if (file->big_endian) {
  879. c0 = c1 | (c0 << 8);
  880. } else {
  881. c0 = c0 | (c1 << 8);
  882. }
  883. if (c0 != '\n')
  884. fatal("%s: Invalid unicode (UCS-2/%s endian) line break!\n",
  885. file->module,
  886. file->big_endian ? "Big" : "Little");
  887. break;
  888. }
  889. clen = cet_ucs4_to_utf8(buff, sizeof(buff), c0);
  890. if (clen < 1) {
  891. Warning() << "Malformed UCS character" << c0 << "found.";
  892. return NULL;
  893. }
  894. if (len+clen >= file->buffsz) {
  895. file->buffsz += 64;
  896. result = file->buff = (char*) xrealloc(file->buff, file->buffsz + 1);
  897. }
  898. memcpy(&result[len], buff, clen);
  899. len += clen;
  900. }
  901. result[len] = '\0'; // terminate resulting string
  902. return result;
  903. }
  904. /*
  905. * gbfgetstr: Reads a string from file (util any type of line-breaks or eof or error)
  906. * except xfree and free you can do all possible things with the result
  907. */
  908. char*
  909. gbfgetstr(gbfile* file)
  910. {
  911. int len = 0;
  912. char* result = file->buff;
  913. if (file->unicode) {
  914. return gbfgetucs2str(file);
  915. }
  916. for (;;) {
  917. int c = gbfgetc(file);
  918. if ((c == EOF) || (c == 0x1A)) {
  919. if (len == 0) {
  920. return NULL;
  921. }
  922. break;
  923. } else if (c == '\r') {
  924. c = gbfgetc(file);
  925. if ((c != '\n') && (c != EOF)) {
  926. gbfungetc(c, file);
  927. }
  928. break;
  929. } else if (c == '\n') {
  930. break;
  931. } else if (((c == 0xFE) || (c == 0xFF)) && (! file->unicode_checked)) {
  932. int cx;
  933. int c1 = gbfgetc(file);
  934. if (c1 != EOF) {
  935. cx = c | (c1 << 8);
  936. if (cx == 0xFEFF) {
  937. file->unicode = 1;
  938. file->big_endian = 0;
  939. return gbfgetucs2str(file);
  940. } else if (cx == 0xFFFE) {
  941. file->unicode = 1;
  942. file->big_endian = 1;
  943. return gbfgetucs2str(file);
  944. } else {
  945. gbfungetc(c1, file);
  946. }
  947. }
  948. }
  949. file->unicode_checked = 1;
  950. if ((len + 1) == file->buffsz) {
  951. file->buffsz += 64;
  952. result = file->buff = (char*) xrealloc(file->buff, file->buffsz + 1);
  953. }
  954. result[len] = (char)c;
  955. len++;
  956. }
  957. result[len] = '\0'; // terminate resulting string
  958. return result;
  959. }
  960. /*
  961. * gbfputint16: write a signed 16-bit integer value into output stream
  962. */
  963. int
  964. gbfputint16(const int16_t i, gbfile* file)
  965. {
  966. char buf[2];
  967. if (file->big_endian) {
  968. be_write16(buf, i);
  969. } else {
  970. le_write16(buf, i);
  971. }
  972. return gbfwrite(buf, 1, sizeof(buf), file);
  973. }
  974. /*
  975. * gbfputint32: write a signed 32-bit integer value into output stream
  976. */
  977. int
  978. gbfputint32(const int32_t i, gbfile* file)
  979. {
  980. char buf[4];
  981. if (file->big_endian) {
  982. be_write32(buf, i);
  983. } else {
  984. le_write32(buf, i);
  985. }
  986. return gbfwrite(buf, 1, sizeof(buf), file);
  987. }
  988. /*
  989. * gbfputdbl: write a double value (8 byte, double precision) into output stream
  990. */
  991. int
  992. gbfputdbl(const double d, gbfile* file)
  993. {
  994. char buf[8];
  995. endian_write_double(buf, d, ! file->big_endian);
  996. return gbfwrite(buf, 1, sizeof(buf), file);
  997. }
  998. /*
  999. * gbfputflt: write a float value (4 byte, single precision) into output stream
  1000. */
  1001. int
  1002. gbfputflt(const float f, gbfile* file)
  1003. {
  1004. char buf[4];
  1005. endian_write_float(buf, f, ! file->big_endian);
  1006. return gbfwrite(buf, 1, sizeof(buf), file);
  1007. }
  1008. /*
  1009. * gbfputcstr: write a NULL terminated string into a stream (!) including NULL
  1010. * return the number of written characters
  1011. */
  1012. int
  1013. gbfputcstr(const QString& s, gbfile* file)
  1014. {
  1015. QByteArray qs = s.toUtf8();
  1016. int rv = gbfwrite(qs.constData(), 1, qs.size(), file);
  1017. gbfputc(0, file);
  1018. return rv;
  1019. }
  1020. /*
  1021. * gbfputcstr: write a pascal string into a stream
  1022. * return the number of written characters
  1023. */
  1024. int
  1025. gbfputpstr(const QString& s, gbfile* file)
  1026. {
  1027. QString out(s);
  1028. // Pascal strings can be a max of 255 bytes.
  1029. out.truncate(255);
  1030. gbfputc(out.size(), file);
  1031. QByteArray qs = s.toUtf8();
  1032. int rv = gbfwrite(qs.constData(), 1, qs.size(), file);
  1033. return rv;
  1034. }
  1035. /* Much more higher level functions */
  1036. gbsize_t
  1037. gbfcopyfrom(gbfile* file, gbfile* src, gbsize_t count)
  1038. {
  1039. char buf[1024];
  1040. gbsize_t copied = 0;
  1041. while (count) {
  1042. gbsize_t n = gbfread(buf, 1, (count < sizeof(buf)) ? count : sizeof(buf), src);
  1043. if (n > 0) {
  1044. gbfwrite(buf, 1, n, file);
  1045. count -= n;
  1046. copied += n;
  1047. } else {
  1048. break;
  1049. }
  1050. }
  1051. return copied;
  1052. }
  1053. /* Thats all, sorry. */