1 module psd.parse.io; 2 import std.bitmanip; 3 4 public import std.file; 5 public import std.stdio; 6 import std.traits; 7 8 /** 9 A stream 10 */ 11 abstract class Stream { 12 13 /** 14 Reads X amount of bytes from stream 15 16 returns empty array if EOF 17 */ 18 abstract ubyte[] read(size_t length); 19 20 /** 21 Gets the position in the stream 22 */ 23 abstract size_t tell(); 24 25 /** 26 Gets the length of the stream 27 */ 28 abstract size_t length(); 29 30 /** 31 Sets the position in the stream 32 */ 33 abstract void seek(ptrdiff_t pos); 34 35 /** 36 Skips pos amount of bytes in the stream 37 */ 38 abstract void skip(ptrdiff_t pos); 39 40 /** 41 Gets whether we're EOF 42 */ 43 final 44 bool eof() { 45 return tell() == length(); 46 } 47 48 /** 49 Peeks bytes 50 */ 51 final 52 ubyte[] peek(size_t length) { 53 ubyte[] data = read(length); 54 skip(-length); 55 return data; 56 } 57 } 58 59 /** 60 A file stream 61 */ 62 class FileStream : Stream { 63 private: 64 File file; 65 66 public: 67 /** 68 Constructs a new file stream 69 */ 70 this(ref File file) { 71 this.file = file; 72 } 73 74 override 75 ubyte[] read(size_t length) { 76 return file.rawRead(new ubyte[length]); 77 } 78 79 override 80 size_t tell() { 81 return file.tell(); 82 } 83 84 override 85 void seek(ptrdiff_t offset) { 86 file.seek(offset, SEEK_SET); 87 } 88 89 override 90 void skip(ptrdiff_t offset) { 91 if (offset < 0) { 92 import std.math : abs; 93 file.seek(file.tell()-abs(offset), SEEK_SET); 94 return; 95 } 96 file.seek(offset, SEEK_CUR); 97 } 98 99 override 100 size_t length() { 101 return file.size; 102 } 103 } 104 105 // TODO: Memory stream 106 107 /** 108 Reads file value in big endian fashion 109 */ 110 T readValue(T)(ref Stream stream) if(isNumeric!T) { 111 return bigEndianToNative!T(stream.read(T.sizeof)[0 .. T.sizeof]); 112 } 113 114 /** 115 Peeks a value 116 */ 117 T peekValue(T)(ref Stream stream) if(isNumeric!T) { 118 T value = bigEndianToNative!T(stream.peek(T.sizeof)[0 .. T.sizeof]); 119 stream.skip(-T.sizeof); 120 return value; 121 } 122 123 /** 124 Reads a string 125 */ 126 string readStr(ref Stream stream, uint length) { 127 return cast(string) stream.read(length); 128 } 129 130 /** 131 Peek oncomming string in stream 132 */ 133 string peekStr(ref Stream stream, uint length) { 134 string value = stream.readStr(length); 135 stream.skip(-cast(int)length); 136 return value; 137 } 138 139 /** 140 Reads a pascal string 141 */ 142 string readPascalStr(ref Stream stream) { 143 ubyte length = stream.read(1)[0]; 144 if (length == 0) { 145 // Special case, empty strings are 2 bytes long! 146 stream.skip(1); 147 return ""; 148 } 149 150 return stream.readStr(length); 151 } 152 153 /** 154 Reads a Unicode string, well, eventually 155 */ 156 //string readUnicodeStr(ref Stream stream) { 157 // wstring utf16str; 158 // ubyte length = stream.read(2)[0]; 159 // if (length == 0) { 160 // // Special case, empty strings are 2 bytes long! 161 // stream.skip(1); 162 // return ""; 163 // } 164 // 165 // return stream.readStr(length); 166 //}