1 /*
2  * DSFML - The Simple and Fast Multimedia Library for D
3  *
4  * Copyright (c) 2013 - 2017 Jeremy DeHaan (dehaan.jeremiah@gmail.com)
5  *
6  * This software is provided 'as-is', without any express or implied warranty.
7  * In no event will the authors be held liable for any damages arising from the
8  * use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not claim
15  * that you wrote the original software. If you use this software in a product,
16  * an acknowledgment in the product documentation would be appreciated but is
17  * not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  * misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source distribution
23  */
24 
25 /**
26 * This class allows users to define their own file input sources from which
27 * DSFML can load resources.
28 *
29 * DSFML resource classes like $(TEXTURE_LINK) and $(SOUNDBUFFER_LINK) provide
30 * `loadFromFile` and `loadFromMemory` functions, which read data from
31 * conventional sources. However, if you have data coming from a different source
32 * (over a network, embedded, encrypted, compressed, etc) you can derive your own
33 * class from $(U InputStream) and load DSFML resources with their
34 * `loadFromStream` function.
35 *
36 * Usage example:
37 * ---
38 * // custom stream class that reads from inside a zip file
39 * class ZipStream : InputStream
40 * {
41 * public:
42 *
43 *     ZipStream(string archive);
44 *
45 *     bool open(string filename);
46 *
47 *     long read(void[] data);
48 *
49 *     long seek(long position);
50 *
51 *     long tell();
52 *
53 *     long getSize();
54 *
55 * private:
56 *
57 *     ...
58 * };
59 *
60 * // now you can load textures...
61 * auto texture = new Texture();
62 * auto stream = new ZipStream("resources.zip");
63 * stream.open("images/img.png");
64 * texture.loadFromStream(stream);
65 *
66 * // musics...
67 * auto music = new Music();
68 * auto stream = new ZipStream("resources.zip");
69 * stream.open("musics/msc.ogg");
70 * music.openFromStream(stream);
71 *
72 * // etc.
73 * ---
74 */
75 module dsfml.system.inputstream;
76 
77 /**
78 * Interface for custom file input streams.
79 */
80 interface InputStream
81 {
82 	/**
83 	 * Read data from the stream.
84 	 *
85 	 * Params:
86  	 * 	data =	Buffer where to copy the read data
87  	 * 			and sized to the amount of bytes to be read
88  	 *
89  	 * Returns: The number of bytes actually read, or -1 on error.
90 	 */
91 	long read(void[] data);
92 
93 	/**
94 	 * Change the current reading position.
95 	 * Params:
96      * 		position = The position to seek to, from the beginning
97      *
98 	 * Returns: The position actually sought to, or -1 on error.
99 	 */
100 	long seek(long position);
101 
102 	/**
103 	 * Get the current reading position in the stream.
104 	 *
105 	 * Returns: The current position, or -1 on error.
106 	 */
107 	long tell();
108 
109 	/**
110 	 * Return the size of the stream.
111 	 *
112 	 * Returns: Total number of bytes available in the stream, or -1 on error.
113 	 */
114 	long getSize();
115 }
116 
117 unittest
118 {
119 	//version(DSFML_Unittest_System)
120 	version(none) //temporarily not doing this test
121 	{
122 		import dsfml.graphics.texture;
123 		import std.stdio;
124 
125 		//File Stream ported from Laurent's example here:
126 		//http://www.sfml-dev.org/tutorials/2.0/system-stream.php
127 
128 		class FileStream:InputStream
129 		{
130 			File m_file;
131 
132 			this()
133 			{
134 				// Constructor code
135 			}
136 			bool open(string fileName)
137 			{
138 				try
139 				{
140 					m_file.open(fileName);
141 				}
142 				catch(Exception e)
143 				{
144 					writeln(e.msg);
145 				}
146 
147 				return m_file.isOpen;
148 			}
149 
150 			long read(void[] data)
151 			{
152 
153 				if(m_file.isOpen)
154 				{
155 					return m_file.rawRead(data).length;
156 				}
157 				else
158 				{
159 					return -1;
160 				}
161 			}
162 
163 			long seek(long position)
164 			{
165 				if(m_file.isOpen)
166 				{
167 					m_file.seek(position);
168 					return tell();
169 				}
170 				else
171 				{
172 					return -1;
173 				}
174 			}
175 
176 			long tell()
177 			{
178 
179 				if(m_file.isOpen)
180 				{
181 					return m_file.tell;
182 				}
183 				else
184 				{
185 					return -1;
186 				}
187 			}
188 
189 			long getSize()
190 			{
191 				if(m_file.isOpen)
192 				{
193 					long position = m_file.tell;
194 
195 					m_file.seek(0,SEEK_END);
196 
197 					long size = tell();
198 
199 					seek(position);
200 
201 					return size;
202 				}
203 				else
204 				{
205 					return -1;
206 				}
207 			}
208 		}
209 
210 
211 
212 
213 		writeln("Unit test for InputStream");
214 
215 		auto streamTexture = new Texture();
216 
217 		writeln();
218 		writeln("Using a basic file stream to load a non existant texture to confirm correct errors are found.");
219 
220 
221 		auto failStream = new FileStream();
222 		failStream.open("nonexistantTexture.png");//doesn't open the stream, but you should be checking if open returns true
223 		streamTexture.loadFromStream(failStream);//prints errors to err
224 
225 		writeln();
226 		writeln("Using a basic file stream to load a texture that exists.");
227 		auto successStream = new FileStream();
228 		successStream.open("res/TestImage.png");//using a png of Crono for now. Will replace with something that won't get me in trouble
229 		assert(streamTexture.loadFromStream(successStream));
230 
231 		writeln("Texture loaded!");
232 
233 		writeln();
234 	}
235 }