/io/file.d

http://github.com/wilkie/djehuty · D · 411 lines · 246 code · 114 blank · 51 comment · 33 complexity · 8090ebef17428743b5967b857476b18e MD5 · raw file

  1. /*
  2. * file.d
  3. *
  4. * This file contains the magic behind File.
  5. *
  6. * Author: Dave Wilkinson
  7. *
  8. */
  9. module io.file;
  10. import djehuty;
  11. import platform.vars.file;
  12. import scaffold.file;
  13. import io.directory;
  14. // Section: Core/Streams
  15. // Description: This class wraps common file operations within the context of a Stream.
  16. class File : Stream {
  17. // Description: Will open the file located at the _path at filename. The internal pointer will point to the beginning of the file.
  18. // filename: The file to open.
  19. this(string filename) {
  20. _name = filename.dup;
  21. _pos = null;
  22. _curpos = 0;
  23. bool r = FileCreate(_pfvars, _name);
  24. if (!r) {
  25. throw new IOException.CreationFailure(filename);
  26. }
  27. _length = 0;
  28. _inited = true;
  29. }
  30. // Description: Will create a closed File class. You must open a file to use it as a stream.
  31. this() {
  32. }
  33. ~this() {
  34. close();
  35. }
  36. // Description: Will open the file located at the _path at filename. The internal pointer will point to the beginning of the file.
  37. // filename: The file to open.
  38. // Returns: Will return an instance to the opened file.
  39. static File open(string filename) {
  40. File foo = new File;
  41. foo._name = filename.dup;
  42. foo._pos = null;
  43. foo._curpos = 0;
  44. bool r = FileOpen(foo._pfvars, foo._name);
  45. if (!r) {
  46. return null;
  47. }
  48. FileGetSize(foo._pfvars, foo._length);
  49. foo._inited = true;
  50. return foo;
  51. }
  52. static File create(string filename) {
  53. return new File(filename);
  54. }
  55. // Methods //
  56. // Inherited Functionality
  57. alias Stream.write write;
  58. alias Stream.append append;
  59. alias Stream.read read;
  60. // Core Functionality
  61. // Description: Will close the file. This is also done upon deconstruction of the class, for instance when it is garbage collected.
  62. void close() {
  63. if (_inited) {
  64. FileClose(_pfvars);
  65. _inited = false;
  66. _name = null;
  67. }
  68. }
  69. // read
  70. override bool read(void* buffer, uint len) {
  71. if (_curpos + len > _length) {
  72. return false;
  73. }
  74. FileRead(_pfvars, cast(ubyte*)buffer, len);
  75. _curpos += len;
  76. return true;
  77. }
  78. override bool read(Stream stream, uint len) {
  79. if (_curpos + len > _length) {
  80. return false;
  81. }
  82. stream.write(this, len);
  83. return true;
  84. }
  85. override ulong readAny(void* buffer, uint len) {
  86. if (_curpos + len > _length) {
  87. len = cast(uint)(_length - _curpos);
  88. }
  89. if (len == 0) { return 0; }
  90. FileRead(_pfvars, cast(ubyte*)buffer, len);
  91. return len;
  92. }
  93. override ulong readAny(Stream stream, uint len) {
  94. if (_curpos + len > _length) {
  95. len = cast(uint)(_length - _curpos);
  96. }
  97. if (len == 0) { return 0; }
  98. stream.write(this, len);
  99. _curpos += len;
  100. return len;
  101. }
  102. // Console.put
  103. override bool write(ubyte* bytes, uint len) {
  104. if (len <= 0) { return false;}
  105. //if (_curpos + len > _length)
  106. //{
  107. // TODO: throw permission exception
  108. // return false;
  109. //}
  110. FileWrite(_pfvars, bytes, len);
  111. _curpos += len;
  112. if (_curpos > _length) { _length = _curpos; }
  113. return true;
  114. }
  115. override bool write(Stream stream, uint len) {
  116. if (len <= 0) { return false;}
  117. ubyte buffer[] = new ubyte[len];
  118. stream.read(&buffer[0], len);
  119. //if (_curpos + len > _length)
  120. //{
  121. // TODO: throw permission exception
  122. // return false;
  123. //}
  124. FileWrite(_pfvars, &buffer[0], len);
  125. _curpos += len;
  126. if (_curpos > _length) { _length = _curpos; }
  127. return true;
  128. }
  129. // append
  130. override bool append(ubyte* bytes, uint len) {
  131. if (len <= 0) { return false;}
  132. FileAppend(_pfvars, bytes, len);
  133. _length += len;
  134. return true;
  135. }
  136. override bool append(Stream stream, uint len) {
  137. if (len <= 0) { return false;}
  138. ubyte buffer[] = new ubyte[len];
  139. stream.read(&buffer[0], len);
  140. FileAppend(_pfvars, &buffer[0], len);
  141. _length += len;
  142. return true;
  143. }
  144. override ulong remaining() {
  145. //Console.put("rem: ", _curpos, " ", _length, " ", _length - _curpos);
  146. return _length - _curpos;
  147. }
  148. // rewind
  149. override void rewind() {
  150. // set to start
  151. _curpos = 0;
  152. FileRewindAll(_pfvars);
  153. }
  154. override bool rewind(ulong amount) {
  155. if (_curpos - amount < 0) {
  156. return false;
  157. }
  158. _curpos -= amount;
  159. FileRewind(_pfvars, amount);
  160. return true;
  161. }
  162. override ulong rewindAny(ulong amount) {
  163. if (_curpos - amount < 0) {
  164. amount = _curpos;
  165. }
  166. _curpos -= amount;
  167. FileRewind(_pfvars, amount);
  168. return amount;
  169. }
  170. // skip
  171. override void skip() {
  172. _curpos = _length;
  173. FileSkipAll(_pfvars);
  174. }
  175. override bool skip(ulong amount) {
  176. if (_curpos + amount > _length) {
  177. return false;
  178. }
  179. _curpos += amount;
  180. FileSkip(_pfvars, amount);
  181. return true;
  182. }
  183. override ulong skipAny(ulong amount) {
  184. if (_curpos + amount > _length) {
  185. amount = _length - _curpos;
  186. }
  187. if (amount <= 0) { return 0; }
  188. _curpos += amount;
  189. FileSkip(_pfvars, amount);
  190. return amount;
  191. }
  192. // Description: Will return the string representing the filename currently open, or null for when there is no open file.
  193. // Returns: The string representing the filename of this class.
  194. string name() {
  195. if (_inited) {
  196. return _name.dup;
  197. }
  198. return null;
  199. }
  200. override bool duplicate(ulong distanceBehind, uint amount) {
  201. if (amount <= 0) { return false; }
  202. if (_curpos - distanceBehind < 0) { return false; }
  203. // need to store bytes...could be an overlapping array copy!
  204. ubyte bytes[] = new ubyte[amount];
  205. read(bytes.ptr, amount);
  206. return true;
  207. }
  208. override bool duplicateFromEnd(ulong distanceBehind, uint amount) {
  209. if (amount <= 0) { return false; }
  210. if (_length - distanceBehind < 0) { return false; }
  211. ubyte bytes[] = new ubyte[amount];
  212. ulong pos = _curpos;
  213. skip();
  214. rewind(distanceBehind);
  215. read(bytes.ptr, amount);
  216. append(bytes.ptr, amount);
  217. rewind();
  218. skip(pos);
  219. return true;
  220. }
  221. // File logic
  222. Directory path() {
  223. if (_inited) {
  224. return _path;
  225. }
  226. return null;
  227. }
  228. void move(Directory destination) {
  229. if (FileMove(_pfvars, _path.path ~ "/" ~ _name, destination.path ~ "/" ~ _name)) {
  230. _path = destination;
  231. }
  232. }
  233. void move(string destination) {
  234. if (FileMove(_pfvars, _path.path ~ "/" ~ _name, destination ~ "/" ~ _name)) {
  235. _path = Directory.open(destination);
  236. }
  237. }
  238. File copy(Directory destination) {
  239. File ret;
  240. if (FileCopy(_pfvars, _path.path ~ "/" ~ _name, destination.path ~ "/" ~ _name)) {
  241. ret = File.open(destination.path ~ "/" ~ _name);
  242. }
  243. return ret;
  244. }
  245. File copy(string destination) {
  246. File ret;
  247. if (FileCopy(_pfvars, _path.path ~ "/" ~ _name, destination ~ "/" ~ _name)) {
  248. ret = File.open(destination ~ "/" ~ _name);
  249. }
  250. return ret;
  251. }
  252. void destroy() {
  253. }
  254. override char[] toString() {
  255. return _path.path ~ "/" ~ _name;
  256. }
  257. int opApply(int delegate(ref string) loopFunc) {
  258. string nextLine;
  259. int ret;
  260. while(readLine(nextLine)) {
  261. ret = loopFunc(nextLine);
  262. if (ret) { break; }
  263. }
  264. return ret;
  265. }
  266. protected:
  267. bool _inited = false;
  268. FilePlatformVars _pfvars;
  269. Directory _path;
  270. string _name;
  271. }
  272. // Section: Core/Streams
  273. // Description: This class wraps common file operations within the context of a Stream. The permissions of this object will not allow writes.
  274. class FileReader : File {
  275. // Description: Will open the file located at the _path at filename. The internal pointer will point to the beginning of the file.
  276. // filename: The file to open.
  277. this(string filename) {
  278. super(filename);
  279. }
  280. // Description: Will create a closed File class. You must open a file to use it as a stream.
  281. this() {
  282. super();
  283. }
  284. }
  285. // Section: Core/Streams
  286. // Description: This class wraps common file operations within the context of a Stream. The permissions of this object will not allow reads.
  287. class FileWriter : File {
  288. // Description: Will open the file located at the _path at filename. The internal pointer will point to the beginning of the file.
  289. // filename: The file to open.
  290. this(string filename) {
  291. super(filename);
  292. }
  293. // Description: Will create a closed File class. You must open a file to use it as a stream.
  294. this() {
  295. super();
  296. }
  297. }