ustdio.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. // © 2016 and later: Unicode, Inc. and others.
  2. // License & terms of use: http://www.unicode.org/copyright.html
  3. /*
  4. ******************************************************************************
  5. *
  6. * Copyright (C) 1998-2016, International Business Machines
  7. * Corporation and others. All Rights Reserved.
  8. *
  9. ******************************************************************************
  10. *
  11. * File ustdio.c
  12. *
  13. * Modification History:
  14. *
  15. * Date Name Description
  16. * 11/18/98 stephen Creation.
  17. * 03/12/99 stephen Modified for new C API.
  18. * 07/19/99 stephen Fixed read() and gets()
  19. ******************************************************************************
  20. */
  21. #include "unicode/ustdio.h"
  22. #if !UCONFIG_NO_CONVERSION
  23. #include "unicode/putil.h"
  24. #include "cmemory.h"
  25. #include "cstring.h"
  26. #include "ufile.h"
  27. #include "ufmt_cmn.h"
  28. #include "unicode/ucnv.h"
  29. #include "unicode/ustring.h"
  30. #include <string.h>
  31. #define DELIM_LF 0x000A
  32. #define DELIM_VT 0x000B
  33. #define DELIM_FF 0x000C
  34. #define DELIM_CR 0x000D
  35. #define DELIM_NEL 0x0085
  36. #define DELIM_LS 0x2028
  37. #define DELIM_PS 0x2029
  38. /* TODO: is this correct for all codepages? Should we just use \n and let the converter handle it? */
  39. #if U_PLATFORM_USES_ONLY_WIN32_API
  40. static const char16_t DELIMITERS [] = { DELIM_CR, DELIM_LF, 0x0000 };
  41. static const uint32_t DELIMITERS_LEN = 2;
  42. /* TODO: Default newline writing should be detected based upon the converter being used. */
  43. #else
  44. static const char16_t DELIMITERS [] = { DELIM_LF, 0x0000 };
  45. static const uint32_t DELIMITERS_LEN = 1;
  46. #endif
  47. #define IS_FIRST_STRING_DELIMITER(c1) \
  48. (UBool)((DELIM_LF <= (c1) && (c1) <= DELIM_CR) \
  49. || (c1) == DELIM_NEL \
  50. || (c1) == DELIM_LS \
  51. || (c1) == DELIM_PS)
  52. #define CAN_HAVE_COMBINED_STRING_DELIMITER(c1) (UBool)((c1) == DELIM_CR)
  53. #define IS_COMBINED_STRING_DELIMITER(c1, c2) \
  54. (UBool)((c1) == DELIM_CR && (c2) == DELIM_LF)
  55. #if !UCONFIG_NO_TRANSLITERATION
  56. U_CAPI UTransliterator* U_EXPORT2
  57. u_fsettransliterator(UFILE *file, UFileDirection direction,
  58. UTransliterator *adopt, UErrorCode *status)
  59. {
  60. UTransliterator *old = nullptr;
  61. if(U_FAILURE(*status))
  62. {
  63. return adopt;
  64. }
  65. if(!file)
  66. {
  67. *status = U_ILLEGAL_ARGUMENT_ERROR;
  68. return adopt;
  69. }
  70. if(direction & U_READ)
  71. {
  72. /** TODO: implement */
  73. *status = U_UNSUPPORTED_ERROR;
  74. return adopt;
  75. }
  76. if(adopt == nullptr) /* they are clearing it */
  77. {
  78. if(file->fTranslit != nullptr)
  79. {
  80. /* TODO: Check side */
  81. old = file->fTranslit->translit;
  82. uprv_free(file->fTranslit->buffer);
  83. file->fTranslit->buffer=nullptr;
  84. uprv_free(file->fTranslit);
  85. file->fTranslit=nullptr;
  86. }
  87. }
  88. else
  89. {
  90. if(file->fTranslit == nullptr)
  91. {
  92. file->fTranslit = (UFILETranslitBuffer*) uprv_malloc(sizeof(UFILETranslitBuffer));
  93. if(!file->fTranslit)
  94. {
  95. *status = U_MEMORY_ALLOCATION_ERROR;
  96. return adopt;
  97. }
  98. file->fTranslit->capacity = 0;
  99. file->fTranslit->length = 0;
  100. file->fTranslit->pos = 0;
  101. file->fTranslit->buffer = nullptr;
  102. }
  103. else
  104. {
  105. old = file->fTranslit->translit;
  106. ufile_flush_translit(file);
  107. }
  108. file->fTranslit->translit = adopt;
  109. }
  110. return old;
  111. }
  112. static const char16_t * u_file_translit(UFILE *f, const char16_t *src, int32_t *count, UBool flush)
  113. {
  114. int32_t newlen;
  115. int32_t junkCount = 0;
  116. int32_t textLength;
  117. int32_t textLimit;
  118. UTransPosition pos;
  119. UErrorCode status = U_ZERO_ERROR;
  120. if(count == nullptr)
  121. {
  122. count = &junkCount;
  123. }
  124. if ((!f)||(!f->fTranslit)||(!f->fTranslit->translit))
  125. {
  126. /* fast path */
  127. return src;
  128. }
  129. /* First: slide over everything */
  130. if(f->fTranslit->length > f->fTranslit->pos)
  131. {
  132. memmove(f->fTranslit->buffer, f->fTranslit->buffer + f->fTranslit->pos,
  133. (f->fTranslit->length - f->fTranslit->pos)*sizeof(char16_t));
  134. }
  135. f->fTranslit->length -= f->fTranslit->pos; /* always */
  136. f->fTranslit->pos = 0;
  137. /* Calculate new buffer size needed */
  138. newlen = (*count + f->fTranslit->length) * 4;
  139. if(newlen > f->fTranslit->capacity)
  140. {
  141. if(f->fTranslit->buffer == nullptr)
  142. {
  143. f->fTranslit->buffer = (char16_t*)uprv_malloc(newlen * sizeof(char16_t));
  144. }
  145. else
  146. {
  147. f->fTranslit->buffer = (char16_t*)uprv_realloc(f->fTranslit->buffer, newlen * sizeof(char16_t));
  148. }
  149. /* Check for malloc/realloc failure. */
  150. if (f->fTranslit->buffer == nullptr) {
  151. return nullptr;
  152. }
  153. f->fTranslit->capacity = newlen;
  154. }
  155. /* Now, copy any data over */
  156. u_strncpy(f->fTranslit->buffer + f->fTranslit->length,
  157. src,
  158. *count);
  159. f->fTranslit->length += *count;
  160. /* Now, translit in place as much as we can */
  161. if(flush == false)
  162. {
  163. textLength = f->fTranslit->length;
  164. pos.contextStart = 0;
  165. pos.contextLimit = textLength;
  166. pos.start = 0;
  167. pos.limit = textLength;
  168. utrans_transIncrementalUChars(f->fTranslit->translit,
  169. f->fTranslit->buffer, /* because we shifted */
  170. &textLength,
  171. f->fTranslit->capacity,
  172. &pos,
  173. &status);
  174. /* now: start/limit point to the transliterated text */
  175. /* Transliterated is [buffer..pos.start) */
  176. *count = pos.start;
  177. f->fTranslit->pos = pos.start;
  178. f->fTranslit->length = pos.limit;
  179. return f->fTranslit->buffer;
  180. }
  181. else
  182. {
  183. textLength = f->fTranslit->length;
  184. textLimit = f->fTranslit->length;
  185. utrans_transUChars(f->fTranslit->translit,
  186. f->fTranslit->buffer,
  187. &textLength,
  188. f->fTranslit->capacity,
  189. 0,
  190. &textLimit,
  191. &status);
  192. /* out: converted len */
  193. *count = textLimit;
  194. /* Set pointers to 0 */
  195. f->fTranslit->pos = 0;
  196. f->fTranslit->length = 0;
  197. return f->fTranslit->buffer;
  198. }
  199. }
  200. #endif
  201. void
  202. ufile_flush_translit(UFILE *f)
  203. {
  204. #if !UCONFIG_NO_TRANSLITERATION
  205. if((!f)||(!f->fTranslit))
  206. return;
  207. #endif
  208. u_file_write_flush(nullptr, 0, f, false, true);
  209. }
  210. void
  211. ufile_flush_io(UFILE *f)
  212. {
  213. if((!f) || (!f->fFile)) {
  214. return; /* skip if no file */
  215. }
  216. u_file_write_flush(nullptr, 0, f, true, false);
  217. }
  218. void
  219. ufile_close_translit(UFILE *f)
  220. {
  221. #if !UCONFIG_NO_TRANSLITERATION
  222. if((!f)||(!f->fTranslit))
  223. return;
  224. #endif
  225. ufile_flush_translit(f);
  226. #if !UCONFIG_NO_TRANSLITERATION
  227. if(f->fTranslit->translit)
  228. utrans_close(f->fTranslit->translit);
  229. if(f->fTranslit->buffer)
  230. {
  231. uprv_free(f->fTranslit->buffer);
  232. }
  233. uprv_free(f->fTranslit);
  234. f->fTranslit = nullptr;
  235. #endif
  236. }
  237. /* Input/output */
  238. U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
  239. u_fputs(const char16_t *s,
  240. UFILE *f)
  241. {
  242. int32_t count = u_file_write(s, u_strlen(s), f);
  243. count += u_file_write(DELIMITERS, DELIMITERS_LEN, f);
  244. return count;
  245. }
  246. U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
  247. u_fputc(UChar32 uc,
  248. UFILE *f)
  249. {
  250. char16_t buf[2];
  251. int32_t idx = 0;
  252. UBool isError = false;
  253. U16_APPEND(buf, idx, UPRV_LENGTHOF(buf), uc, isError);
  254. if (isError) {
  255. return U_EOF;
  256. }
  257. return u_file_write(buf, idx, f) == idx ? uc : U_EOF;
  258. }
  259. U_CFUNC int32_t U_EXPORT2
  260. u_file_write_flush(const char16_t *chars,
  261. int32_t count,
  262. UFILE *f,
  263. UBool flushIO,
  264. UBool flushTranslit)
  265. {
  266. /* Set up conversion parameters */
  267. UErrorCode status = U_ZERO_ERROR;
  268. const char16_t *mySource = chars;
  269. const char16_t *mySourceBegin;
  270. const char16_t *mySourceEnd;
  271. char charBuffer[UFILE_CHARBUFFER_SIZE];
  272. char *myTarget = charBuffer;
  273. int32_t written = 0;
  274. int32_t numConverted = 0;
  275. if (count < 0) {
  276. count = u_strlen(chars);
  277. }
  278. #if !UCONFIG_NO_TRANSLITERATION
  279. if((f->fTranslit) && (f->fTranslit->translit))
  280. {
  281. /* Do the transliteration */
  282. mySource = u_file_translit(f, chars, &count, flushTranslit);
  283. }
  284. #endif
  285. /* Write to a string. */
  286. if (!f->fFile) {
  287. int32_t charsLeft = (int32_t)(f->str.fLimit - f->str.fPos);
  288. if (flushIO && charsLeft > count) {
  289. count++;
  290. }
  291. written = ufmt_min(count, charsLeft);
  292. u_strncpy(f->str.fPos, mySource, written);
  293. f->str.fPos += written;
  294. return written;
  295. }
  296. mySourceEnd = mySource + count;
  297. /* Perform the conversion in a loop */
  298. do {
  299. mySourceBegin = mySource; /* beginning location for this loop */
  300. status = U_ZERO_ERROR;
  301. if(f->fConverter != nullptr) { /* We have a valid converter */
  302. ucnv_fromUnicode(f->fConverter,
  303. &myTarget,
  304. charBuffer + UFILE_CHARBUFFER_SIZE,
  305. &mySource,
  306. mySourceEnd,
  307. nullptr,
  308. flushIO,
  309. &status);
  310. } else { /*weiv: do the invariant conversion */
  311. int32_t convertChars = (int32_t) (mySourceEnd - mySource);
  312. if (convertChars > UFILE_CHARBUFFER_SIZE) {
  313. convertChars = UFILE_CHARBUFFER_SIZE;
  314. status = U_BUFFER_OVERFLOW_ERROR;
  315. }
  316. u_UCharsToChars(mySource, myTarget, convertChars);
  317. mySource += convertChars;
  318. myTarget += convertChars;
  319. }
  320. numConverted = (int32_t)(myTarget - charBuffer);
  321. if (numConverted > 0) {
  322. /* write the converted bytes */
  323. fwrite(charBuffer,
  324. sizeof(char),
  325. numConverted,
  326. f->fFile);
  327. written += (int32_t) (mySource - mySourceBegin);
  328. }
  329. myTarget = charBuffer;
  330. }
  331. while(status == U_BUFFER_OVERFLOW_ERROR);
  332. /* return # of chars written */
  333. return written;
  334. }
  335. U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
  336. u_file_write( const char16_t *chars,
  337. int32_t count,
  338. UFILE *f)
  339. {
  340. return u_file_write_flush(chars,count,f,false,false);
  341. }
  342. /* private function used for buffering input */
  343. void
  344. ufile_fill_uchar_buffer(UFILE *f)
  345. {
  346. UErrorCode status;
  347. const char *mySource;
  348. const char *mySourceEnd;
  349. char16_t *myTarget;
  350. int32_t bufferSize;
  351. int32_t maxCPBytes;
  352. int32_t bytesRead;
  353. int32_t availLength;
  354. int32_t dataSize;
  355. char charBuffer[UFILE_CHARBUFFER_SIZE];
  356. u_localized_string *str;
  357. if (f->fFile == nullptr) {
  358. /* There is nothing to do. It's a string. */
  359. return;
  360. }
  361. str = &f->str;
  362. dataSize = (int32_t)(str->fLimit - str->fPos);
  363. if (f->fFileno == 0 && dataSize > 0) {
  364. /* Don't read from stdin too many times. There is still some data. */
  365. return;
  366. }
  367. /* shift the buffer if it isn't empty */
  368. if(dataSize != 0) {
  369. u_memmove(f->fUCBuffer, str->fPos, dataSize); /* not accessing beyond memory */
  370. }
  371. /* record how much buffer space is available */
  372. availLength = UFILE_UCHARBUFFER_SIZE - dataSize;
  373. /* Determine the # of codepage bytes needed to fill our char16_t buffer */
  374. /* weiv: if converter is nullptr, we use invariant converter with charwidth = 1)*/
  375. maxCPBytes = availLength / (f->fConverter!=nullptr?(2*ucnv_getMinCharSize(f->fConverter)):1);
  376. /* Read in the data to convert */
  377. if (f->fFileno == 0) {
  378. /* Special case. Read from stdin one line at a time. */
  379. char *retStr = fgets(charBuffer, ufmt_min(maxCPBytes, UFILE_CHARBUFFER_SIZE), f->fFile);
  380. bytesRead = (int32_t)(retStr ? uprv_strlen(charBuffer) : 0);
  381. }
  382. else {
  383. /* A normal file */
  384. bytesRead = (int32_t)fread(charBuffer,
  385. sizeof(char),
  386. ufmt_min(maxCPBytes, UFILE_CHARBUFFER_SIZE),
  387. f->fFile);
  388. }
  389. /* Set up conversion parameters */
  390. status = U_ZERO_ERROR;
  391. mySource = charBuffer;
  392. mySourceEnd = charBuffer + bytesRead;
  393. myTarget = f->fUCBuffer + dataSize;
  394. bufferSize = UFILE_UCHARBUFFER_SIZE;
  395. if(f->fConverter != nullptr) { /* We have a valid converter */
  396. /* Perform the conversion */
  397. ucnv_toUnicode(f->fConverter,
  398. &myTarget,
  399. f->fUCBuffer + bufferSize,
  400. &mySource,
  401. mySourceEnd,
  402. nullptr,
  403. (UBool)(feof(f->fFile) != 0),
  404. &status);
  405. } else { /*weiv: do the invariant conversion */
  406. u_charsToUChars(mySource, myTarget, bytesRead);
  407. myTarget += bytesRead;
  408. }
  409. /* update the pointers into our array */
  410. str->fPos = str->fBuffer;
  411. str->fLimit = myTarget;
  412. }
  413. U_CAPI char16_t* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
  414. u_fgets(char16_t *s,
  415. int32_t n,
  416. UFILE *f)
  417. {
  418. int32_t dataSize;
  419. int32_t count;
  420. char16_t *alias;
  421. const char16_t *limit;
  422. char16_t *sItr;
  423. char16_t currDelim = 0;
  424. u_localized_string *str;
  425. if (n <= 0) {
  426. /* Caller screwed up. We need to write the null terminatior. */
  427. return nullptr;
  428. }
  429. /* fill the buffer if needed */
  430. str = &f->str;
  431. if (str->fPos >= str->fLimit) {
  432. ufile_fill_uchar_buffer(f);
  433. }
  434. /* subtract 1 from n to compensate for the terminator */
  435. --n;
  436. /* determine the amount of data in the buffer */
  437. dataSize = (int32_t)(str->fLimit - str->fPos);
  438. /* if 0 characters were left, return 0 */
  439. if (dataSize == 0)
  440. return nullptr;
  441. /* otherwise, iteratively fill the buffer and copy */
  442. count = 0;
  443. sItr = s;
  444. currDelim = 0;
  445. while (dataSize > 0 && count < n) {
  446. alias = str->fPos;
  447. /* Find how much to copy */
  448. if (dataSize < (n - count)) {
  449. limit = str->fLimit;
  450. }
  451. else {
  452. limit = alias + (n - count);
  453. }
  454. if (!currDelim) {
  455. /* Copy UChars until we find the first occurrence of a delimiter character */
  456. while (alias < limit && !IS_FIRST_STRING_DELIMITER(*alias)) {
  457. count++;
  458. *(sItr++) = *(alias++);
  459. }
  460. /* Preserve the newline */
  461. if (alias < limit && IS_FIRST_STRING_DELIMITER(*alias)) {
  462. if (CAN_HAVE_COMBINED_STRING_DELIMITER(*alias)) {
  463. currDelim = *alias;
  464. }
  465. else {
  466. currDelim = 1; /* This isn't a newline, but it's used to say
  467. that we should break later. We've checked all
  468. possible newline combinations even across buffer
  469. boundaries. */
  470. }
  471. count++;
  472. *(sItr++) = *(alias++);
  473. }
  474. }
  475. /* If we have a CRLF combination, preserve that too. */
  476. if (alias < limit) {
  477. if (currDelim && IS_COMBINED_STRING_DELIMITER(currDelim, *alias)) {
  478. count++;
  479. *(sItr++) = *(alias++);
  480. }
  481. currDelim = 1; /* This isn't a newline, but it's used to say
  482. that we should break later. We've checked all
  483. possible newline combinations even across buffer
  484. boundaries. */
  485. }
  486. /* update the current buffer position */
  487. str->fPos = alias;
  488. /* if we found a delimiter */
  489. if (currDelim == 1) {
  490. /* break out */
  491. break;
  492. }
  493. /* refill the buffer */
  494. ufile_fill_uchar_buffer(f);
  495. /* determine the amount of data in the buffer */
  496. dataSize = (int32_t)(str->fLimit - str->fPos);
  497. }
  498. /* add the terminator and return s */
  499. *sItr = 0x0000;
  500. return s;
  501. }
  502. U_CFUNC UBool U_EXPORT2
  503. ufile_getch(UFILE *f, char16_t *ch)
  504. {
  505. UBool isValidChar = false;
  506. *ch = U_EOF;
  507. /* if we have an available character in the buffer, return it */
  508. if(f->str.fPos < f->str.fLimit){
  509. *ch = *(f->str.fPos)++;
  510. isValidChar = true;
  511. }
  512. else {
  513. /* otherwise, fill the buffer and return the next character */
  514. if(f->str.fPos >= f->str.fLimit) {
  515. ufile_fill_uchar_buffer(f);
  516. }
  517. if(f->str.fPos < f->str.fLimit) {
  518. *ch = *(f->str.fPos)++;
  519. isValidChar = true;
  520. }
  521. }
  522. return isValidChar;
  523. }
  524. U_CAPI char16_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
  525. u_fgetc(UFILE *f)
  526. {
  527. char16_t ch;
  528. ufile_getch(f, &ch);
  529. return ch;
  530. }
  531. U_CFUNC UBool U_EXPORT2
  532. ufile_getch32(UFILE *f, UChar32 *c32)
  533. {
  534. UBool isValidChar = false;
  535. u_localized_string *str;
  536. *c32 = U_EOF;
  537. /* Fill the buffer if it is empty */
  538. str = &f->str;
  539. if (str->fPos + 1 >= str->fLimit) {
  540. ufile_fill_uchar_buffer(f);
  541. }
  542. /* Get the next character in the buffer */
  543. if (str->fPos < str->fLimit) {
  544. *c32 = *(str->fPos)++;
  545. if (U_IS_LEAD(*c32)) {
  546. if (str->fPos < str->fLimit) {
  547. char16_t c16 = *(str->fPos)++;
  548. *c32 = U16_GET_SUPPLEMENTARY(*c32, c16);
  549. isValidChar = true;
  550. }
  551. else {
  552. *c32 = U_EOF;
  553. }
  554. }
  555. else {
  556. isValidChar = true;
  557. }
  558. }
  559. return isValidChar;
  560. }
  561. U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
  562. u_fgetcx(UFILE *f)
  563. {
  564. UChar32 ch;
  565. ufile_getch32(f, &ch);
  566. return ch;
  567. }
  568. U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
  569. u_fungetc(UChar32 ch,
  570. UFILE *f)
  571. {
  572. u_localized_string *str;
  573. str = &f->str;
  574. /* if we're at the beginning of the buffer, sorry! */
  575. if (str->fPos == str->fBuffer
  576. || (U_IS_LEAD(ch) && (str->fPos - 1) == str->fBuffer))
  577. {
  578. ch = U_EOF;
  579. }
  580. else {
  581. /* otherwise, put the character back */
  582. /* Remember, read them back on in the reverse order. */
  583. if (U_IS_LEAD(ch)) {
  584. if (*--(str->fPos) != U16_TRAIL(ch)
  585. || *--(str->fPos) != U16_LEAD(ch))
  586. {
  587. ch = U_EOF;
  588. }
  589. }
  590. else if (*--(str->fPos) != ch) {
  591. ch = U_EOF;
  592. }
  593. }
  594. return ch;
  595. }
  596. U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
  597. u_file_read( char16_t *chars,
  598. int32_t count,
  599. UFILE *f)
  600. {
  601. int32_t dataSize;
  602. int32_t read = 0;
  603. u_localized_string *str = &f->str;
  604. do {
  605. /* determine the amount of data in the buffer */
  606. dataSize = (int32_t)(str->fLimit - str->fPos);
  607. if (dataSize <= 0) {
  608. /* fill the buffer */
  609. ufile_fill_uchar_buffer(f);
  610. dataSize = (int32_t)(str->fLimit - str->fPos);
  611. }
  612. /* Make sure that we don't read too much */
  613. if (dataSize > (count - read)) {
  614. dataSize = count - read;
  615. }
  616. /* copy the current data in the buffer */
  617. memcpy(chars + read, str->fPos, dataSize * sizeof(char16_t));
  618. /* update number of items read */
  619. read += dataSize;
  620. /* update the current buffer position */
  621. str->fPos += dataSize;
  622. }
  623. while (dataSize != 0 && read < count);
  624. return read;
  625. }
  626. #endif