1 /*
2  * HLLib
3  * Copyright (C) 2006-2010 Ryan Gregg
4 
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later
9  * version.
10  */
11 
12 #include "HLLib.h"
13 #include "MappingStream.h"
14 
15 using namespace HLLib;
16 using namespace HLLib::Streams;
17 
CMappingStream(Mapping::CMapping & Mapping,hlULongLong uiMappingOffset,hlULongLong uiMappingSize,hlULongLong uiViewSize)18 CMappingStream::CMappingStream(Mapping::CMapping &Mapping, hlULongLong uiMappingOffset, hlULongLong uiMappingSize, hlULongLong uiViewSize) : bOpened(hlFalse), uiMode(HL_MODE_INVALID), Mapping(Mapping), uiMappingOffset(uiMappingOffset), uiMappingSize(uiMappingSize), uiViewSize(uiViewSize), pView(0), uiPointer(0), uiLength(0)
19 {
20 	if(this->uiViewSize == 0)
21 	{
22 		switch(this->Mapping.GetType())
23 		{
24 		case HL_MAPPING_FILE:
25 			if(this->Mapping.GetMode() & HL_MODE_QUICK_FILEMAPPING)
26 			{
27 		case HL_MAPPING_MEMORY:
28 				this->uiViewSize = this->uiMappingSize;
29 				break;
30 			}
31 		default:
32 			this->uiViewSize = HL_DEFAULT_VIEW_SIZE;
33 			break;
34 		}
35 	}
36 }
37 
~CMappingStream()38 CMappingStream::~CMappingStream()
39 {
40 	this->Close();
41 }
42 
GetType() const43 HLStreamType CMappingStream::GetType() const
44 {
45 	return HL_STREAM_MAPPING;
46 }
47 
GetMapping() const48 const Mapping::CMapping &CMappingStream::GetMapping() const
49 {
50 	return this->Mapping;
51 }
52 
GetFileName() const53 const hlChar *CMappingStream::GetFileName() const
54 {
55 	return "";
56 }
57 
GetOpened() const58 hlBool CMappingStream::GetOpened() const
59 {
60 	return this->bOpened;
61 }
62 
GetMode() const63 hlUInt CMappingStream::GetMode() const
64 {
65 	return this->uiMode;
66 }
67 
Open(hlUInt uiMode)68 hlBool CMappingStream::Open(hlUInt uiMode)
69 {
70 	this->Close();
71 
72 	if((uiMode & (HL_MODE_READ | HL_MODE_WRITE)) == 0)
73 	{
74 		LastError.SetErrorMessageFormated("Invalid open mode (%#.8x).", uiMode);
75 		return hlFalse;
76 	}
77 
78 	if((uiMode & HL_MODE_READ) != 0 && (this->Mapping.GetMode() & HL_MODE_READ) == 0)
79 	{
80 		LastError.SetErrorMessage("Mapping does not have read permissions.");
81 		return hlFalse;
82 	}
83 
84 	if((uiMode & HL_MODE_WRITE) != 0 && (this->Mapping.GetMode() & HL_MODE_WRITE) == 0)
85 	{
86 		LastError.SetErrorMessage("Mapping does not have write permissions.");
87 		return hlFalse;
88 	}
89 
90 	this->uiPointer = 0;
91 	this->uiLength = (uiMode & HL_MODE_READ) ? this->uiMappingSize : 0;
92 
93 	this->bOpened = hlTrue;
94 	this->uiMode = uiMode;
95 
96 	return hlTrue;
97 }
98 
Close()99 hlVoid CMappingStream::Close()
100 {
101 	this->bOpened = hlFalse;
102 	this->uiMode = HL_MODE_INVALID;
103 
104 	this->Mapping.Unmap(this->pView);
105 
106 	this->uiPointer = 0;
107 	this->uiLength = 0;
108 }
109 
GetStreamSize() const110 hlULongLong CMappingStream::GetStreamSize() const
111 {
112 	return this->uiLength;
113 }
114 
GetStreamPointer() const115 hlULongLong CMappingStream::GetStreamPointer() const
116 {
117 	return this->uiPointer;
118 }
119 
Seek(hlLongLong iOffset,HLSeekMode eSeekMode)120 hlULongLong CMappingStream::Seek(hlLongLong iOffset, HLSeekMode eSeekMode)
121 {
122 	if(!this->bOpened)
123 	{
124 		return 0;
125 	}
126 
127 	switch(eSeekMode)
128 	{
129 		case HL_SEEK_BEGINNING:
130 			this->uiPointer = 0;
131 			break;
132 		case HL_SEEK_CURRENT:
133 
134 			break;
135 		case HL_SEEK_END:
136 			this->uiPointer = this->uiLength;
137 			break;
138 	}
139 
140 	hlLongLong iPointer = static_cast<hlLongLong>(this->uiPointer) + iOffset;
141 
142 	if(iPointer < 0)
143 	{
144 		iPointer = 0;
145 	}
146 	else if(iPointer > static_cast<hlLongLong>(this->uiLength))
147 	{
148 		iPointer = static_cast<hlLongLong>(this->uiLength);
149 	}
150 
151 	this->uiPointer = static_cast<hlULongLong>(iPointer);
152 
153 	return this->uiPointer;
154 }
155 
Read(hlChar & cChar)156 hlBool CMappingStream::Read(hlChar &cChar)
157 {
158 	if(!this->bOpened)
159 	{
160 		return 0;
161 	}
162 
163 	if((this->uiMode & HL_MODE_READ) == 0)
164 	{
165 		LastError.SetErrorMessage("Stream not in read mode.");
166 		return 0;
167 	}
168 
169 	if(this->uiPointer < this->uiLength)
170 	{
171 		if(!this->Map(this->uiPointer))
172 		{
173 			return 0;
174 		}
175 
176 		hlULongLong uiViewPointer = this->uiPointer - (this->pView->GetAllocationOffset() + this->pView->GetOffset() - this->uiMappingOffset);
177 		hlULongLong uiViewBytes = this->pView->GetLength() - uiViewPointer;
178 
179 		if(uiViewBytes >= 1)
180 		{
181 			cChar = *(static_cast<const hlChar *>(this->pView->GetView()) + uiViewPointer);
182 			this->uiPointer++;
183 			return 1;
184 		}
185 	}
186 
187 	return 0;
188 }
189 
Read(hlVoid * lpData,hlUInt uiBytes)190 hlUInt CMappingStream::Read(hlVoid *lpData, hlUInt uiBytes)
191 {
192 	if(!this->bOpened)
193 	{
194 		return 0;
195 	}
196 
197 	if((this->uiMode & HL_MODE_READ) == 0)
198 	{
199 		LastError.SetErrorMessage("Stream not in read mode.");
200 		return 0;
201 	}
202 
203 	if(this->uiPointer == this->uiLength)
204 	{
205 		return 0;
206 	}
207 	else
208 	{
209 		hlULongLong uiOffset = 0;
210 		while(uiBytes && this->uiPointer < this->uiLength)
211 		{
212 			if(!this->Map(this->uiPointer))
213 			{
214 				break;
215 			}
216 
217 			hlULongLong uiViewPointer = this->uiPointer - (this->pView->GetAllocationOffset() + this->pView->GetOffset() - this->uiMappingOffset);
218 			hlULongLong uiViewBytes = this->pView->GetLength() - uiViewPointer;
219 
220 			if(uiViewBytes >= uiBytes)
221 			{
222 				memcpy(static_cast<hlByte *>(lpData) + uiOffset, static_cast<const hlByte *>(this->pView->GetView()) + uiViewPointer, uiBytes);
223 				this->uiPointer += static_cast<hlULongLong>(uiBytes);
224 				uiOffset += uiBytes;
225 				break;
226 			}
227 			else
228 			{
229 				memcpy(static_cast<hlByte *>(lpData) + uiOffset, static_cast<const hlByte *>(this->pView->GetView()) + uiViewPointer, static_cast<size_t>(uiViewBytes));
230 				this->uiPointer += uiViewBytes;
231 				uiOffset += uiViewBytes;
232 				uiBytes -= static_cast<hlUInt>(uiViewBytes);
233 			}
234 		}
235 
236 		return static_cast<hlUInt>(uiOffset);
237 	}
238 }
239 
Write(hlChar cChar)240 hlBool CMappingStream::Write(hlChar cChar)
241 {
242 	if(!this->bOpened)
243 	{
244 		return 0;
245 	}
246 
247 	if((this->uiMode & HL_MODE_WRITE) == 0)
248 	{
249 		LastError.SetErrorMessage("Stream not in write mode.");
250 		return 0;
251 	}
252 
253 	if(this->uiPointer < this->uiMappingSize)
254 	{
255 		if(!this->Map(this->uiPointer))
256 		{
257 			return 0;
258 		}
259 
260 		hlULongLong uiViewPointer = this->uiPointer - (this->pView->GetAllocationOffset() + this->pView->GetOffset() - this->uiMappingOffset);
261 		hlULongLong uiViewBytes = this->pView->GetLength() - uiViewPointer;
262 
263 		if(uiViewBytes >= 1)
264 		{
265 			*(static_cast<hlChar *>(const_cast<hlVoid *>(this->pView->GetView())) + uiViewPointer) = cChar;
266 			this->uiPointer++;
267 
268 			if(this->uiPointer > this->uiLength)
269 			{
270 				this->uiLength = this->uiPointer;
271 			}
272 
273 			return 1;
274 		}
275 	}
276 
277 	return 0;
278 }
279 
Write(const hlVoid * lpData,hlUInt uiBytes)280 hlUInt CMappingStream::Write(const hlVoid *lpData, hlUInt uiBytes)
281 {
282 	if(!this->bOpened)
283 	{
284 		return 0;
285 	}
286 
287 	if((this->uiMode & HL_MODE_WRITE) == 0)
288 	{
289 		LastError.SetErrorMessage("Stream not in write mode.");
290 		return 0;
291 	}
292 
293 	if(this->uiPointer == this->uiMappingSize)
294 	{
295 		return 0;
296 	}
297 	else
298 	{
299 		hlULongLong uiOffset = 0;
300 		while(uiBytes && this->uiPointer < this->uiMappingSize)
301 		{
302 			if(!this->Map(this->uiPointer))
303 			{
304 				break;
305 			}
306 
307 			hlULongLong uiViewPointer = this->uiPointer - (this->pView->GetAllocationOffset() + this->pView->GetOffset() - this->uiMappingOffset);
308 			hlULongLong uiViewBytes = this->pView->GetLength() - uiViewPointer;
309 
310 			if(uiViewBytes >= uiBytes)
311 			{
312 				memcpy(static_cast<hlByte *>(const_cast<hlVoid *>(this->pView->GetView())) + uiViewPointer, static_cast<const hlByte *>(lpData) + uiOffset, uiBytes);
313 				this->uiPointer += static_cast<hlULongLong>(uiBytes);
314 				uiOffset += uiBytes;
315 				break;
316 			}
317 			else
318 			{
319 				memcpy(static_cast<hlByte *>(const_cast<hlVoid *>(this->pView->GetView())) + uiViewPointer, static_cast<const hlByte *>(lpData) + uiOffset, static_cast<size_t>(uiViewBytes));
320 				this->uiPointer += uiViewBytes;
321 				uiOffset += uiViewBytes;
322 				uiBytes -= static_cast<hlUInt>(uiViewBytes);
323 			}
324 		}
325 
326 		if(this->uiPointer > this->uiLength)
327 		{
328 			this->uiLength = this->uiPointer;
329 		}
330 
331 		return static_cast<hlUInt>(uiOffset);
332 	}
333 }
334 
Map(hlULongLong uiPointer)335 hlBool CMappingStream::Map(hlULongLong uiPointer)
336 {
337 	uiPointer = (uiPointer / this->uiViewSize) * this->uiViewSize;
338 
339 	if(this->pView)
340 	{
341 		if(this->pView->GetAllocationOffset() - this->uiMappingOffset == uiPointer)
342 		{
343 			return hlTrue;
344 		}
345 	}
346 
347 	hlULongLong uiLength = uiPointer + this->uiViewSize > this->uiMappingSize ? this->uiMappingSize - uiPointer : this->uiViewSize;
348 
349 	return this->Mapping.Map(this->pView, this->uiMappingOffset + uiPointer, uiLength);
350 }
351