bio.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /* =============================================================================
  2. * PROGRAM: CODE LIBRARY
  3. * FILENAME: bio.c
  4. *
  5. * DESCRIPTION:
  6. *
  7. * Buffered I/O package.
  8. *
  9. * Allows multiple small reads and writes to be handled efficiently.
  10. * Probably not so good for large reads/writes.
  11. * Excellent for reading IFF pictures though.
  12. *
  13. * Duplicates the Amiga DOS functions and are used in exactly the same
  14. * way as their counterparts as described in the Amiga technical reference
  15. * Manual (Libraries and devices).
  16. *
  17. * =============================================================================
  18. * COPYRIGHT:
  19. *
  20. * Copyright (c) 1996, 2004, Julian Olds
  21. * All rights reserved.
  22. *
  23. * Redistribution and use in source and binary forms, with or without
  24. * modification, are permitted provided that the following conditions
  25. * are met:
  26. *
  27. * . Redistributions of source code must retain the above copyright notice,
  28. * this list of conditions and the following disclaimer.
  29. *
  30. * . Redistributions in binary form must reproduce the above copyright
  31. * notice, this list of conditions and the following disclaimer in the
  32. * documentation and/or other materials provided with the distribution.
  33. *
  34. * The name of the author may not be used to endorse or promote products
  35. * derived from this software without specific prior written permission.
  36. *
  37. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  38. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  39. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  40. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  41. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  42. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  43. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  44. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  45. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  46. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  47. * THE POSSIBILITY OF SUCH DAMAGE.
  48. *
  49. * =============================================================================
  50. * EXPORTED VARIABLES
  51. *
  52. * None
  53. *
  54. * =============================================================================
  55. * EXPORTED FUNCTIONS
  56. *
  57. * BOpen : Open a buffered I/O file.
  58. * BClose : Close a buffered I/O file.
  59. * BRead : Read from a buffered I/O file.
  60. * BSeek : Seek a position in a buffered I/O file.
  61. * BWrite : Write to a buffered I/O file.
  62. *
  63. * =============================================================================
  64. */
  65. #include "bio.h"
  66. #include <exec/memory.h>
  67. #include <functions.h>
  68. #include <stdio.h>
  69. #include <string.h>
  70. #define MIN(x, y) ((x < y) ? (x) : (y))
  71. #define BUFFER_SIZE 16384L
  72. /* =============================================================================
  73. * Exported functions
  74. */
  75. /* =============================================================================
  76. * FUNCTION: BOpen
  77. */
  78. struct BFile *BOpen(char *name, long accessMode) {
  79. BPTR dos_file;
  80. struct BFile *buffered_file;
  81. if ((dos_file = Open(name, accessMode)) == NULL)
  82. return NULL;
  83. buffered_file =
  84. (struct BFile *)AllocMem((long)sizeof(struct BFile), MEMF_CLEAR);
  85. if (buffered_file == NULL) {
  86. Close(dos_file);
  87. return NULL;
  88. }
  89. buffered_file->buffer = (UBYTE *)AllocMem(BUFFER_SIZE, MEMF_CLEAR);
  90. if (buffered_file->buffer == NULL) {
  91. FreeMem(buffered_file, (long)sizeof(struct BFile));
  92. Close(dos_file);
  93. return NULL;
  94. }
  95. buffered_file->file = dos_file;
  96. buffered_file->file_offset = 0L;
  97. buffered_file->buffer_size = -1L; /* never read anything */
  98. buffered_file->in_buffer_count = 0L;
  99. buffered_file->out_buffer_count = 0L;
  100. return buffered_file;
  101. }
  102. /* =============================================================================
  103. * FUNCTION: BClose
  104. */
  105. void BClose(struct BFile *file) {
  106. /* Flush the output buffer if necessary */
  107. if (file->out_buffer_count > 0L) {
  108. Write(file->file, file->buffer, file->out_buffer_count);
  109. file->out_buffer_count = 0L;
  110. file->in_buffer_count = 0L;
  111. file->buffer_size = -1L;
  112. }
  113. Close(file->file);
  114. FreeMem(file->buffer, BUFFER_SIZE);
  115. FreeMem(file, (long)sizeof(struct BFile));
  116. }
  117. /* =============================================================================
  118. * FUNCTION: BRead
  119. */
  120. long BRead(struct BFile *file, UBYTE *buffer, long length) {
  121. long bytes_read;
  122. long bytes_left;
  123. long bytes_to_copy;
  124. bytes_read = 0L;
  125. /* Flush the output buffer if necessary */
  126. if (file->out_buffer_count > 0L) {
  127. Write(file->file, file->buffer, file->out_buffer_count);
  128. file->out_buffer_count = 0L;
  129. file->in_buffer_count = 0L;
  130. file->buffer_size = -1L;
  131. }
  132. bytes_left = file->buffer_size - file->in_buffer_count;
  133. bytes_to_copy = MIN(bytes_left, length);
  134. if (bytes_to_copy > 0L) {
  135. memcpy(buffer, &(file->buffer[file->in_buffer_count]), bytes_to_copy);
  136. file->in_buffer_count += bytes_to_copy;
  137. bytes_read += bytes_to_copy;
  138. }
  139. bytes_to_copy = length - bytes_read;
  140. if (bytes_to_copy != 0L) {
  141. if (bytes_to_copy > BUFFER_SIZE) {
  142. bytes_read += Read(file->file, &buffer[bytes_read], bytes_to_copy);
  143. if (bytes_read < length) {
  144. file->buffer_size = 0L; /* end of file has been reached */
  145. file->in_buffer_count = 0L;
  146. } else {
  147. file->buffer_size = -1L; /* no data in buffer */
  148. file->in_buffer_count = 0L;
  149. }
  150. } else {
  151. file->buffer_size = Read(file->file, file->buffer, BUFFER_SIZE);
  152. file->in_buffer_count = 0L;
  153. bytes_to_copy = MIN(bytes_to_copy, file->buffer_size);
  154. memcpy(&buffer[bytes_read], file->buffer, bytes_to_copy);
  155. file->in_buffer_count += bytes_to_copy;
  156. bytes_read += bytes_to_copy;
  157. }
  158. }
  159. file->file_offset += bytes_read;
  160. return bytes_read;
  161. }
  162. /* =============================================================================
  163. * FUNCTION: BSeek
  164. */
  165. long BSeek(struct BFile *file, long position, long mode) {
  166. long current_pos;
  167. long new_pos;
  168. long buff_start;
  169. long buff_end;
  170. /* Flush the output buffer if necessary */
  171. if (file->out_buffer_count > 0L) {
  172. Write(file->file, file->buffer, file->out_buffer_count);
  173. file->out_buffer_count = 0L;
  174. }
  175. if (mode == OFFSET_CURRENT) {
  176. if (file->buffer_size <= 0L) {
  177. /* seek the position directly
  178. (input buffer empty -> file_offset matches physical location) */
  179. Seek(file->file, position, OFFSET_CURRENT);
  180. } else {
  181. current_pos = file->file_offset;
  182. new_pos = current_pos + position;
  183. buff_start = current_pos - file->in_buffer_count;
  184. buff_end = buff_start + file->buffer_size;
  185. if ((new_pos >= buff_start) && (new_pos < buff_end)) {
  186. /* the seek position is within the buffer */
  187. file->in_buffer_count = new_pos - buff_start;
  188. file->file_offset = new_pos;
  189. } else {
  190. Seek(file->file, new_pos, OFFSET_BEGINNING);
  191. file->file_offset = new_pos;
  192. file->buffer_size = -1L;
  193. file->in_buffer_count = 0L;
  194. }
  195. }
  196. } else {
  197. current_pos = file->file_offset;
  198. Seek(file->file, position, mode);
  199. file->file_offset = Seek(file->file, 0L, OFFSET_CURRENT);
  200. file->buffer_size = -1L;
  201. file->in_buffer_count = 0L;
  202. }
  203. return current_pos;
  204. }
  205. /* =============================================================================
  206. * FUNCTION: BWrite
  207. */
  208. long BWrite(struct BFile *file, UBYTE *buffer, long length) {
  209. long bytes_written;
  210. long bytes_left;
  211. long bytes_to_copy;
  212. file->buffer_size = -1L;
  213. file->in_buffer_count = 0L;
  214. if (length >= BUFFER_SIZE) {
  215. if (file->out_buffer_count > 0L) {
  216. Write(file->file, file->buffer, file->out_buffer_count);
  217. file->out_buffer_count = 0L;
  218. }
  219. bytes_written = Write(file->file, buffer, length);
  220. } else {
  221. bytes_left = BUFFER_SIZE - file->out_buffer_count;
  222. bytes_to_copy = MIN(bytes_left, length);
  223. memcpy(&(file->buffer[file->out_buffer_count]), buffer, bytes_to_copy);
  224. file->out_buffer_count += bytes_to_copy;
  225. bytes_written = bytes_to_copy;
  226. if (file->out_buffer_count == BUFFER_SIZE) {
  227. Write(file->file, file->buffer, BUFFER_SIZE);
  228. file->out_buffer_count = 0L;
  229. if (bytes_written < length) {
  230. bytes_to_copy = length - bytes_written;
  231. memcpy(file->buffer, &buffer[bytes_written], bytes_to_copy);
  232. file->out_buffer_count += bytes_to_copy;
  233. bytes_written += bytes_to_copy;
  234. }
  235. }
  236. }
  237. file->file_offset += bytes_written;
  238. return bytes_written;
  239. }