1 /*
2  * DSFML - The Simple and Fast Multimedia Library for D
3  *
4  * Copyright (c) 2013 - 2018 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  * DSFML is based on SFML (Copyright Laurent Gomila)
26  */
27 
28 /**
29 * This interface allows users to define their own file input sources from which
30 * DSFML can load resources.
31 *
32 * DSFML resource classes like $(TEXTURE_LINK) and $(SOUNDBUFFER_LINK) provide
33 * `loadFromFile` and `loadFromMemory` functions, which read data from
34 * conventional sources. However, if you have data coming from a different source
35 * (over a network, embedded, encrypted, compressed, etc) you can derive your own
36 * class from $(U InputStream) and load DSFML resources with their
37 * `loadFromStream` function.
38 *
39 * Usage example:
40 * ---
41 * // custom stream class that reads from inside a zip file
42 * class ZipStream : InputStream
43 * {
44 * public:
45 *
46 *     ZipStream(string archive);
47 *
48 *     bool open(string filename);
49 *
50 *     long read(void[] data);
51 *
52 *     long seek(long position);
53 *
54 *     long tell();
55 *
56 *     long getSize();
57 *
58 * private:
59 *
60 *     ...
61 * };
62 *
63 * // now you can load textures...
64 * auto texture = new Texture();
65 * auto stream = new ZipStream("resources.zip");
66 * stream.open("images/img.png");
67 * texture.loadFromStream(stream);
68 *
69 * // musics...
70 * auto music = new Music();
71 * auto stream = new ZipStream("resources.zip");
72 * stream.open("musics/msc.ogg");
73 * music.openFromStream(stream);
74 *
75 * // etc.
76 * ---
77 */
78 module dsfml.system.inputstream;
79 
80 /**
81 * Interface for custom file input streams.
82 */
83 interface InputStream
84 {
85 	/**
86 	 * Read data from the stream.
87 	 *
88 	 * Params:
89  	 * 	data =	Buffer where to copy the read data
90  	 * 			and sized to the amount of bytes to be read
91  	 *
92  	 * Returns: The number of bytes actually read, or -1 on error.
93 	 */
94 	long read(void[] data);
95 
96 	/**
97 	 * Change the current reading position.
98 	 * Params:
99      * 		position = The position to seek to, from the beginning
100      *
101 	 * Returns: The position actually sought to, or -1 on error.
102 	 */
103 	long seek(long position);
104 
105 	/**
106 	 * Get the current reading position in the stream.
107 	 *
108 	 * Returns: The current position, or -1 on error.
109 	 */
110 	long tell();
111 
112 	/**
113 	 * Return the size of the stream.
114 	 *
115 	 * Returns: Total number of bytes available in the stream, or -1 on error.
116 	 */
117 	long getSize();
118 }
119 
120 unittest
121 {
122 	//version(DSFML_Unittest_System)
123 	version(none) //temporarily not doing this test
124 	{
125 		import dsfml.graphics.texture;
126 		import std.stdio;
127 
128 		//File Stream ported from Laurent's example here:
129 		//http://www.sfml-dev.org/tutorials/2.0/system-stream.php
130 
131 		class FileStream:InputStream
132 		{
133 			File m_file;
134 
135 			this()
136 			{
137 				// Constructor code
138 			}
139 			bool open(string fileName)
140 			{
141 				try
142 				{
143 					m_file.open(fileName);
144 				}
145 				catch(Exception e)
146 				{
147 					writeln(e.msg);
148 				}
149 
150 				return m_file.isOpen;
151 			}
152 
153 			long read(void[] data)
154 			{
155 
156 				if(m_file.isOpen)
157 				{
158 					return m_file.rawRead(data).length;
159 				}
160 				else
161 				{
162 					return -1;
163 				}
164 			}
165 
166 			long seek(long position)
167 			{
168 				if(m_file.isOpen)
169 				{
170 					m_file.seek(position);
171 					return tell();
172 				}
173 				else
174 				{
175 					return -1;
176 				}
177 			}
178 
179 			long tell()
180 			{
181 
182 				if(m_file.isOpen)
183 				{
184 					return m_file.tell;
185 				}
186 				else
187 				{
188 					return -1;
189 				}
190 			}
191 
192 			long getSize()
193 			{
194 				if(m_file.isOpen)
195 				{
196 					long position = m_file.tell;
197 
198 					m_file.seek(0,SEEK_END);
199 
200 					long size = tell();
201 
202 					seek(position);
203 
204 					return size;
205 				}
206 				else
207 				{
208 					return -1;
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 		auto failStream = new FileStream();
221 		failStream.open("nonexistantTexture.png");//doesn't open the stream, but you should be checking if open returns true
222 		streamTexture.loadFromStream(failStream);//prints errors to err
223 
224 		writeln();
225 		writeln("Using a basic file stream to load a texture that exists.");
226 		auto successStream = new FileStream();
227 		successStream.open("res/TestImage.png");//using a png of Crono for now. Will replace with something that won't get me in trouble
228 		assert(streamTexture.loadFromStream(successStream));
229 
230 		writeln("Texture loaded!");
231 
232 		writeln();
233 	}
234 }