1 module pxtone.descriptor;
2 // '11/08/12 pxFile.h
3 // '16/01/22 pxFile.h
4 // '16/04/27 pxtnFile. (int)
5 // '16/09/09 pxtnDescriptor.
6 
7 import pxtone.error;
8 import pxtone.pxtn;
9 
10 import std.exception;
11 import std.stdio;
12 import std.traits;
13 
14 enum pxSCE = false;
15 
16 enum pxtnSEEK {
17 	set = 0,
18 	cur,
19 	end,
20 	num
21 }
22 
23 struct pxtnDescriptor {
24 private:
25 	ubyte[] _p_desc;
26 	File file;
27 	bool _b_file;
28 	bool _b_read;
29 	int _size;
30 	int _cur;
31 
32 	bool isOpen() nothrow @safe {
33 		return (_p_desc != null) || file.isOpen;
34 	}
35 public:
36 
37 	void set_file_r(ref File fd) @safe {
38 		enforce(fd.isOpen, new PxtoneException("File must be opened for reading"));
39 
40 		fd.seek(0, SEEK_END);
41 		ulong sz = fd.tell;
42 		fd.seek(0, SEEK_SET);
43 		file = fd;
44 
45 		_size = cast(int) sz;
46 
47 		_b_file = true;
48 		_b_read = true;
49 		_cur = 0;
50 	}
51 
52 	void set_file_w(ref File fd) @safe {
53 		file = fd;
54 		_size = 0;
55 		_b_file = true;
56 		_b_read = false;
57 		_cur = 0;
58 	}
59 
60 	void set_memory_r(ubyte[] buf) @safe {
61 		enforce(buf.length >= 1, new PxtoneException("No data to read in buffer"));
62 		_p_desc = buf;
63 		_b_file = false;
64 		_b_read = true;
65 		_cur = 0;
66 	}
67 
68 	void seek(pxtnSEEK mode, int val) @safe {
69 		if (_b_file) {
70 			int[pxtnSEEK.num] seek_tbl = [SEEK_SET, SEEK_CUR, SEEK_END];
71 			file.seek(val, seek_tbl[mode]);
72 		} else {
73 			switch (mode) {
74 			case pxtnSEEK.set:
75 				enforce(val < _p_desc.length, "Unexpected end of data");
76 				enforce(val >= 0, "Cannot seek to negative position");
77 				_cur = val;
78 				break;
79 			case pxtnSEEK.cur:
80 				enforce(_cur + val < _p_desc.length, "Unexpected end of data");
81 				enforce(_cur + val >= 0, "Cannot seek to negative position");
82 				_cur += val;
83 				break;
84 			case pxtnSEEK.end:
85 				enforce(_p_desc.length + val < _p_desc.length, "Unexpected end of data");
86 				enforce(_p_desc.length + val >= 0, "Cannot seek to negative position");
87 				_cur = cast(int)_p_desc.length + val;
88 				break;
89 			default:
90 				break;
91 			}
92 		}
93 	}
94 
95 	void w_asfile(T)(const T p) @safe if (!is(T : U[], U)) {
96 		union RawAccess {
97 			T t;
98 			ubyte[T.sizeof] bytes;
99 		}
100 		w_asfile(RawAccess(p).bytes);
101 	}
102 	void w_asfile(T)(scope const(T)[] p) @safe {
103 		enforce(isOpen && _b_file && !_b_read, new PxtoneException("File must be opened for writing"));
104 
105 		file.trustedWrite(p);
106 		_size += p.length * T.sizeof;
107 	}
108 
109 	void r(T)(T[] p) @safe {
110 		enforce(isOpen, new PxtoneException("File must be opened for reading"));
111 		enforce(_b_read, new PxtoneException("File must be opened for reading"));
112 
113 		if (_b_file) {
114 			file.trustedRead(p);
115 		} else {
116 			for (int i = 0; i < p.length; i++) {
117 				enforce(_cur + T.sizeof < _p_desc.length, new PxtoneException("Unexpected end of buffer"));
118 				p[i] = (cast(T[])_p_desc[_cur .. _cur + T.sizeof])[0];
119 				_cur += T.sizeof;
120 			}
121 		}
122 	}
123 	void r(T)(ref T p) @safe if (!is(T : U[], U)) {
124 		enforce(isOpen, new PxtoneException("File must be opened for reading"));
125 		enforce(_b_read, new PxtoneException("File must be opened for reading"));
126 
127 		if (_b_file) {
128 			p = file.trustedRead!T();
129 		} else {
130 			enforce(_cur + T.sizeof < _p_desc.length, new PxtoneException("Unexpected end of buffer"));
131 			p = (cast(T[])_p_desc[_cur .. _cur + T.sizeof])[0];
132 			_cur += T.sizeof;
133 		}
134 	}
135 
136 	// ..uint
137 	void v_w_asfile(int val) @safe {
138 		int dummy;
139 		v_w_asfile(val, dummy);
140 	}
141 	void v_w_asfile(int val, ref int p_add) @safe {
142 		enforce(isOpen && _b_file && !_b_read, new PxtoneException("File must be opened for writing"));
143 
144 		ubyte[5] a = 0;
145 		ubyte[5] b = 0;
146 		uint us = cast(uint) val;
147 		int bytes = 0;
148 
149 		(cast(uint[])(a[0 .. uint.sizeof]))[0] = us;
150 		a[4] = 0;
151 
152 		// 1byte(7bit)
153 		if (us < 0x00000080) {
154 			bytes = 1;
155 			b[0] = a[0];
156 		}  // 2byte(14bit)
157 		else if (us < 0x00004000) {
158 			bytes = 2;
159 			b[0] = ((a[0] << 0) & 0x7F) | 0x80;
160 			b[1] = (a[0] >> 7) | ((a[1] << 1) & 0x7F);
161 		}  // 3byte(21bit)
162 		else if (us < 0x00200000) {
163 			bytes = 3;
164 			b[0] = ((a[0] << 0) & 0x7F) | 0x80;
165 			b[1] = (a[0] >> 7) | ((a[1] << 1) & 0x7F) | 0x80;
166 			b[2] = (a[1] >> 6) | ((a[2] << 2) & 0x7F);
167 		}  // 4byte(28bit)
168 		else if (us < 0x10000000) {
169 			bytes = 4;
170 			b[0] = ((a[0] << 0) & 0x7F) | 0x80;
171 			b[1] = (a[0] >> 7) | ((a[1] << 1) & 0x7F) | 0x80;
172 			b[2] = (a[1] >> 6) | ((a[2] << 2) & 0x7F) | 0x80;
173 			b[3] = (a[2] >> 5) | ((a[3] << 3) & 0x7F);
174 		}  // 5byte(32bit)
175 		else {
176 			bytes = 5;
177 			b[0] = ((a[0] << 0) & 0x7F) | 0x80;
178 			b[1] = (a[0] >> 7) | ((a[1] << 1) & 0x7F) | 0x80;
179 			b[2] = (a[1] >> 6) | ((a[2] << 2) & 0x7F) | 0x80;
180 			b[3] = (a[2] >> 5) | ((a[3] << 3) & 0x7F) | 0x80;
181 			b[4] = (a[3] >> 4) | ((a[4] << 4) & 0x7F);
182 		}
183 		file.trustedWrite(b[0 .. bytes]);
184 		p_add += bytes;
185 		_size += bytes;
186 	}
187 	// 可変長読み込み(int  までを保証)
188 	void v_r(ref int p) @safe {
189 		enforce(isOpen && _b_read, new PxtoneException("File must be opened for reading"));
190 
191 		int i;
192 		ubyte[5] a = 0;
193 		ubyte[5] b = 0;
194 
195 		for (i = 0; i < 5; i++) {
196 			r(a[i]);
197 			if (!(a[i] & 0x80)) {
198 				break;
199 			}
200 		}
201 		switch (i) {
202 		case 0:
203 			b[0] = (a[0] & 0x7F) >> 0;
204 			break;
205 		case 1:
206 			b[0] = cast(ubyte)(((a[0] & 0x7F) >> 0) | (a[1] << 7));
207 			b[1] = (a[1] & 0x7F) >> 1;
208 			break;
209 		case 2:
210 			b[0] = cast(ubyte)(((a[0] & 0x7F) >> 0) | (a[1] << 7));
211 			b[1] = cast(ubyte)(((a[1] & 0x7F) >> 1) | (a[2] << 6));
212 			b[2] = (a[2] & 0x7F) >> 2;
213 			break;
214 		case 3:
215 			b[0] = cast(ubyte)(((a[0] & 0x7F) >> 0) | (a[1] << 7));
216 			b[1] = cast(ubyte)(((a[1] & 0x7F) >> 1) | (a[2] << 6));
217 			b[2] = cast(ubyte)(((a[2] & 0x7F) >> 2) | (a[3] << 5));
218 			b[3] = (a[3] & 0x7F) >> 3;
219 			break;
220 		case 4:
221 			b[0] = cast(ubyte)(((a[0] & 0x7F) >> 0) | (a[1] << 7));
222 			b[1] = cast(ubyte)(((a[1] & 0x7F) >> 1) | (a[2] << 6));
223 			b[2] = cast(ubyte)(((a[2] & 0x7F) >> 2) | (a[3] << 5));
224 			b[3] = cast(ubyte)(((a[3] & 0x7F) >> 3) | (a[4] << 4));
225 			b[4] = (a[4] & 0x7F) >> 4;
226 			break;
227 		case 5:
228 			throw new PxtoneException("Integer too large");
229 		default:
230 			break;
231 		}
232 
233 		p = (cast(int[]) b[0 .. 4])[0];
234 	}
235 
236 	int get_size_bytes() const nothrow @safe {
237 		return _b_file ? _size : cast(int)_p_desc.length;
238 	}
239 }
240 
241 int pxtnDescriptor_v_chk(int val) nothrow @safe {
242 	uint us;
243 
244 	us = cast(uint) val;
245 	if (us < 0x80) {
246 		return 1; // 1byte( 7bit)
247 	}
248 	if (us < 0x4000) {
249 		return 2; // 2byte(14bit)
250 	}
251 	if (us < 0x200000) {
252 		return 3; // 3byte(21bit)
253 	}
254 	if (us < 0x10000000) {
255 		return 4; // 4byte(28bit)
256 	}
257 	//	if( value < 0x800000000 ) return 5;	// 5byte(35bit)
258 	if (us <= 0xffffffff) {
259 		return 5;
260 	}
261 
262 	return 6;
263 }
264 
265 T trustedRead(T)(File file) @safe if (!hasIndirections!T) {
266 	T[1] p;
267 	file.trustedRead(p);
268 	return p[0];
269 }
270 
271 void trustedRead(T)(File file, T[] arr) @trusted if (!hasIndirections!T) {
272 	file.rawRead(arr);
273 }
274 
275 void trustedWrite(T)(File file, T val) @safe if (!hasIndirections!T) {
276 	T[1] p = [val];
277 	file.trustedWrite(p);
278 }
279 
280 void trustedWrite(T)(File file, T[] arr) @trusted if (!hasIndirections!T) {
281 	file.rawWrite(arr);
282 }