buf_file.cc 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /********************************************************************** <BR>
  2. This file is part of Crack dot Com's free source code release of
  3. Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
  4. information about compiling & licensing issues visit this URL</a>
  5. <PRE> If that doesn't help, contact Jonathan Clark at
  6. golgotha_source@usa.net (Subject should have "GOLG" in it)
  7. ***********************************************************************/
  8. #include "file/buf_file.hh"
  9. #include "memory/malloc.hh"
  10. #include "error/error.hh"
  11. #include <memory.h>
  12. w32 i4_buffered_file_class::read(void *buffer, w32 size)
  13. {
  14. w32 total_read=0;
  15. while (size)
  16. {
  17. if (offset>=buf_start && offset<buf_end)
  18. {
  19. w32 copy_size;
  20. if (buf_end-offset<size)
  21. copy_size=buf_end-offset;
  22. else copy_size=size;
  23. memcpy(buffer,((w8 *)buf)+offset-buf_start,copy_size);
  24. size-=copy_size;
  25. buffer=(void *)(((w8 *)buffer)+copy_size);
  26. offset+=copy_size;
  27. total_read+=copy_size;
  28. } else if (offset==buf_end) // sequentially read more into the buffer
  29. {
  30. buf_start=offset;
  31. buf_end=offset+from->read(buf,buf_size);
  32. if (buf_end==buf_start)
  33. return total_read;
  34. } else // need to seek from file to a new spot
  35. {
  36. from->seek(offset);
  37. buf_start=buf_end=offset;
  38. }
  39. }
  40. return total_read;
  41. }
  42. w32 i4_buffered_file_class::write(const void *buffer, w32 size)
  43. {
  44. w32 total_write=0;
  45. while (size)
  46. {
  47. write_file=i4_T;
  48. if (offset>=buf_start && offset<=buf_end)
  49. {
  50. w32 copy_size;
  51. if (offset+size<buf_start+buf_size)
  52. copy_size=size;
  53. else
  54. copy_size=buf_start+buf_size-offset;
  55. memcpy(((w8 *)buf)+offset-buf_start,buffer,copy_size);
  56. size-=copy_size;
  57. buffer=(void *)(((w8 *)buffer)+copy_size);
  58. offset+=copy_size;
  59. total_write+=copy_size;
  60. if (offset>buf_end)
  61. {
  62. buf_end=offset;
  63. if (buf_end-buf_start==buf_size)
  64. {
  65. from->write(buf, buf_end-buf_start);
  66. buf_start=buf_end;
  67. }
  68. }
  69. }
  70. else if (buf_end!=buf_start) // flush the buffer
  71. {
  72. from->write(buf, buf_end-buf_start);
  73. buf_start=buf_end;
  74. } else
  75. {
  76. from->seek(offset);
  77. buf_start=buf_end=offset;
  78. }
  79. }
  80. return total_write;
  81. }
  82. w32 i4_buffered_file_class::seek (w32 offset)
  83. {
  84. i4_buffered_file_class::offset=offset;
  85. return offset;
  86. }
  87. w32 i4_buffered_file_class::size ()
  88. {
  89. return from->size();
  90. }
  91. w32 i4_buffered_file_class::tell ()
  92. {
  93. return offset;
  94. }
  95. i4_buffered_file_class::~i4_buffered_file_class()
  96. {
  97. if (write_file && buf_start!=buf_end)
  98. from->write(buf, buf_end-buf_start);
  99. delete from;
  100. i4_free(buf);
  101. }
  102. i4_buffered_file_class::i4_buffered_file_class(i4_file_class *from,
  103. w32 buffer_size,
  104. w32 current_offset)
  105. : from(from), buf_size(buffer_size), offset(current_offset)
  106. {
  107. write_file=i4_F;
  108. buf=i4_malloc(buf_size,"file buffer");
  109. buf_start=buf_end=0;
  110. }
  111. struct callback_context
  112. {
  113. i4_bool in_use;
  114. w32 prev_read;
  115. void *prev_context;
  116. i4_file_class::async_callback prev_callback;
  117. i4_buffered_file_class *bfile;
  118. } ;
  119. // Maximum number async reads going on at the same time
  120. enum { MAX_ASYNC_READS = 4 };
  121. static callback_context contexts[MAX_ASYNC_READS];
  122. static w32 t_callbacks_used=0;
  123. void i4_async_buf_read_callback(w32 count, void *context)
  124. {
  125. callback_context *c=(callback_context *)context;
  126. c->bfile->offset+=count;
  127. i4_file_class::async_callback call=c->prev_callback;
  128. count += c->prev_read;
  129. void *ctext=c->prev_context;
  130. c->in_use=i4_F;
  131. t_callbacks_used--;
  132. call(count, ctext);
  133. }
  134. i4_bool i4_buffered_file_class::async_read (void *buffer, w32 size,
  135. async_callback call,
  136. void *context)
  137. {
  138. if (!(offset>=buf_start && offset<buf_end))
  139. {
  140. from->seek(offset);
  141. buf_start=buf_end=0;
  142. }
  143. if (t_callbacks_used>=MAX_ASYNC_READS)
  144. return i4_file_class::async_read(buffer, size, call, context);
  145. else
  146. {
  147. w32 avail_size;
  148. if (offset>=buf_start && offset<buf_end)
  149. avail_size=buf_end-offset;
  150. else
  151. avail_size=0;
  152. if (avail_size < size)
  153. {
  154. callback_context *c=0;
  155. for (w32 i=0; !c && i<MAX_ASYNC_READS; i++)
  156. if (!contexts[i].in_use)
  157. {
  158. c=contexts+i;
  159. c->in_use=i4_T;
  160. }
  161. if (c==0)
  162. i4_error("didn't find a free context");
  163. t_callbacks_used++;
  164. if (avail_size)
  165. c->prev_read=read(buffer,avail_size);
  166. else
  167. c->prev_read=0;
  168. c->prev_context=context;
  169. c->prev_callback=call;
  170. c->bfile=this;
  171. return from->async_read((w8 *)buffer + avail_size, size-avail_size,
  172. i4_async_buf_read_callback, c);
  173. }
  174. else
  175. {
  176. call(read(buffer,avail_size), context);
  177. return i4_T;
  178. }
  179. }
  180. }
  181. //{{{ Emacs Locals
  182. // Local Variables:
  183. // folded-file: t
  184. // End:
  185. //}}}