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 //}