1/******************************************************************************
2
3 @File         PVRTResourceFile.cpp
4
5 @Title        PVRTResourceFile.cpp
6
7 @Version
8
9 @Copyright    Copyright (c) Imagination Technologies Limited.
10
11 @Platform     ANSI compatible
12
13 @Description  Simple resource file wrapper
14
15******************************************************************************/
16
17#include "PVRTResourceFile.h"
18#include <stdio.h>
19#include <string.h>
20
21#include "PVRTResourceFile.h"
22#include "PVRTString.h"
23#include "PVRTMemoryFileSystem.h"
24
25CPVRTString CPVRTResourceFile::s_ReadPath;
26
27static void* LoadFileFunc(const char* pFilename, char** pData, size_t &size)
28{
29	size = 0;
30
31	FILE* pFile = fopen(pFilename, "rb");
32
33	if (pFile)
34	{
35		// Get the file size
36		fseek(pFile, 0, SEEK_END);
37		size = ftell(pFile);
38		fseek(pFile, 0, SEEK_SET);
39
40		// read the data
41		char* pTmp = new char[size];
42		size_t BytesRead = fread(pTmp, 1, size, pFile);
43
44		if (BytesRead != size)
45		{
46			delete [] pTmp;
47			pTmp = NULL;
48			size = 0;
49		}
50		else
51			*pData = pTmp;
52
53		fclose(pFile);
54		return pTmp;
55	}
56
57	return 0;
58}
59
60static bool ReleaseFileFunc(void* handle)
61{
62	if(handle)
63	{
64		delete[] (char*) handle;
65		return true;
66	}
67
68	return false;
69}
70
71PFNLoadFileFunc CPVRTResourceFile::s_pLoadFileFunc = &LoadFileFunc;
72PFNReleaseFileFunc CPVRTResourceFile::s_pReleaseFileFunc = &ReleaseFileFunc;
73
74/*!***************************************************************************
75@Function			SetReadPath
76@Input				pszReadPath The path where you would like to read from
77@Description		Sets the read path
78*****************************************************************************/
79void CPVRTResourceFile::SetReadPath(const char* const pszReadPath)
80{
81	s_ReadPath = (pszReadPath) ? pszReadPath : "";
82}
83
84/*!***************************************************************************
85@Function			GetReadPath
86@Returns			The currently set read path
87@Description		Returns the currently set read path
88*****************************************************************************/
89CPVRTString CPVRTResourceFile::GetReadPath()
90{
91	return CPVRTString(s_ReadPath);
92}
93
94/*!***************************************************************************
95@Function			SetLoadReleaseFunctions
96@Input				pLoadFileFunc Function to use for opening a file
97@Input				pReleaseFileFunc Function to release any data allocated by the load function
98@Description		This function is used to override the CPVRTResource file loading functions. If
99                    you pass NULL in as the load function CPVRTResource will use the default functions.
100*****************************************************************************/
101void CPVRTResourceFile::SetLoadReleaseFunctions(void* pLoadFileFunc, void* pReleaseFileFunc)
102{
103	if(pLoadFileFunc)
104	{
105		s_pLoadFileFunc = (PFNLoadFileFunc) pLoadFileFunc;
106		s_pReleaseFileFunc = (PFNReleaseFileFunc) pReleaseFileFunc;
107	}
108	else
109	{
110		s_pLoadFileFunc = &LoadFileFunc;
111		s_pReleaseFileFunc = &ReleaseFileFunc;
112	}
113}
114
115/*!***************************************************************************
116@Function			CPVRTResourceFile
117@Input				pszFilename Name of the file you would like to open
118@Description		Constructor
119*****************************************************************************/
120CPVRTResourceFile::CPVRTResourceFile(const char* const pszFilename) :
121	m_bOpen(false),
122	m_bMemoryFile(false),
123	m_Size(0),
124	m_pData(0),
125	m_Handle(0)
126{
127	CPVRTString Path(s_ReadPath);
128	Path += pszFilename;
129
130	m_Handle = s_pLoadFileFunc(Path.c_str(), (char**) &m_pData, m_Size);
131	m_bOpen = (m_pData && m_Size) != 0;
132
133	if (!m_bOpen)
134	{
135		m_bOpen = m_bMemoryFile = CPVRTMemoryFileSystem::GetFile(pszFilename, (const void**)(&m_pData), &m_Size);
136	}
137}
138
139/*!***************************************************************************
140@Function			CPVRTResourceFile
141@Input				pData A pointer to the data you would like to use
142@Input				i32Size The size of the data
143@Description		Constructor
144*****************************************************************************/
145CPVRTResourceFile::CPVRTResourceFile(const char* pData, size_t i32Size) :
146	m_bOpen(true),
147	m_bMemoryFile(true),
148	m_Size(i32Size),
149	m_pData(pData),
150	m_Handle(0)
151{
152}
153
154/*!***************************************************************************
155@Function			~CPVRTResourceFile
156@Description		Destructor
157*****************************************************************************/
158CPVRTResourceFile::~CPVRTResourceFile()
159{
160	Close();
161}
162
163/*!***************************************************************************
164@Function			IsOpen
165@Returns			true if the file is open
166@Description		Is the file open
167*****************************************************************************/
168bool CPVRTResourceFile::IsOpen() const
169{
170	return m_bOpen;
171}
172
173/*!***************************************************************************
174@Function			IsMemoryFile
175@Returns			true if the file was opened from memory
176@Description		Was the file opened from memory
177*****************************************************************************/
178bool CPVRTResourceFile::IsMemoryFile() const
179{
180	return m_bMemoryFile;
181}
182
183/*!***************************************************************************
184@Function			Size
185@Returns			The size of the opened file
186@Description		Returns the size of the opened file
187*****************************************************************************/
188size_t CPVRTResourceFile::Size() const
189{
190	return m_Size;
191}
192
193/*!***************************************************************************
194@Function			DataPtr
195@Returns			A pointer to the file data
196@Description		Returns a pointer to the file data
197*****************************************************************************/
198const void* CPVRTResourceFile::DataPtr() const
199{
200	return m_pData;
201}
202
203/*!***************************************************************************
204@Function			Close
205@Description		Closes the file
206*****************************************************************************/
207void CPVRTResourceFile::Close()
208{
209	if (m_bOpen)
210	{
211		if (!m_bMemoryFile && s_pReleaseFileFunc)
212		{
213			s_pReleaseFileFunc(m_Handle);
214		}
215
216		m_bMemoryFile = false;
217		m_bOpen = false;
218		m_pData = 0;
219		m_Size = 0;
220	}
221}
222
223/****************************************************************************
224** class CPVRTMemoryFileSystem
225****************************************************************************/
226CPVRTMemoryFileSystem::CAtExit CPVRTMemoryFileSystem::s_AtExit;
227CPVRTMemoryFileSystem::SFileInfo* CPVRTMemoryFileSystem::s_pFileInfo = 0;
228int CPVRTMemoryFileSystem::s_i32Capacity = 0;
229int CPVRTMemoryFileSystem::s_i32NumFiles = 0;
230
231/*!***************************************************************************
232@Function		Destructor
233@Description	Destructor of CAtExit class. Workaround for platforms that
234		        don't support the atexit() function. This deletes any memory
235				file system data.
236*****************************************************************************/
237CPVRTMemoryFileSystem::CAtExit::~CAtExit()
238{
239	for (int i = 0; i < CPVRTMemoryFileSystem::s_i32NumFiles; ++i)
240	{
241		if (CPVRTMemoryFileSystem::s_pFileInfo[i].bAllocated)
242		{
243			delete [] (char*)CPVRTMemoryFileSystem::s_pFileInfo[i].pszFilename;
244			delete [] (char*)CPVRTMemoryFileSystem::s_pFileInfo[i].pBuffer;
245		}
246	}
247	delete [] CPVRTMemoryFileSystem::s_pFileInfo;
248}
249
250CPVRTMemoryFileSystem::CPVRTMemoryFileSystem(const char* pszFilename, const void* pBuffer, size_t Size, bool bCopy)
251{
252	RegisterMemoryFile(pszFilename, pBuffer, Size, bCopy);
253}
254
255/*!***************************************************************************
256@Function		RegisterMemoryFile
257@Input			pszFilename		Name of file to register
258@Input			pBuffer			Pointer to file data
259@Input			Size			File size
260@Input			bCopy			Name and data should be copied?
261@Description	Registers a block of memory as a file that can be looked up
262				by name.
263*****************************************************************************/
264void CPVRTMemoryFileSystem::RegisterMemoryFile(const char* pszFilename, const void* pBuffer, size_t Size, bool bCopy)
265{
266	if (s_i32NumFiles == s_i32Capacity)
267	{
268		SFileInfo* pFileInfo = new SFileInfo[s_i32Capacity + 10];
269		memcpy(pFileInfo, s_pFileInfo, sizeof(SFileInfo) * s_i32Capacity);
270		delete [] s_pFileInfo;
271		s_pFileInfo = pFileInfo;
272		s_i32Capacity += 10;
273	}
274
275	s_pFileInfo[s_i32NumFiles].pszFilename = pszFilename;
276	s_pFileInfo[s_i32NumFiles].pBuffer = pBuffer;
277	if (bCopy)
278	{
279		char* pszNewFilename = new char[strlen(pszFilename) + 1];
280		strcpy(pszNewFilename, pszFilename);
281		s_pFileInfo[s_i32NumFiles].pszFilename = pszNewFilename;
282
283		void* pszNewBuffer = new char[Size];
284		memcpy(pszNewBuffer, pBuffer, Size);
285		s_pFileInfo[s_i32NumFiles].pBuffer = pszNewBuffer;
286	}
287	s_pFileInfo[s_i32NumFiles].Size = Size;
288	s_pFileInfo[s_i32NumFiles].bAllocated = bCopy;
289	++s_i32NumFiles;
290}
291
292/*!***************************************************************************
293@Function		GetFile
294@Input			pszFilename		Name of file to open
295@Output			ppBuffer		Pointer to file data
296@Output			pSize			File size
297@Return			true if the file was found in memory, false otherwise
298@Description	Looks up a file in the memory file system by name. Returns a
299				pointer to the file data as well as its size on success.
300*****************************************************************************/
301bool CPVRTMemoryFileSystem::GetFile(const char* pszFilename, const void** ppBuffer, size_t* pSize)
302{
303	for (int i = 0; i < s_i32NumFiles; ++i)
304	{
305		if (strcmp(s_pFileInfo[i].pszFilename, pszFilename) == 0)
306		{
307			if (ppBuffer) *ppBuffer = s_pFileInfo[i].pBuffer;
308			if (pSize) *pSize = s_pFileInfo[i].Size;
309			return true;
310		}
311	}
312	return false;
313}
314
315/*!***************************************************************************
316@Function		GetNumFiles
317@Return			The number of registered files
318@Description	Getter for the number of registered files
319*****************************************************************************/
320int CPVRTMemoryFileSystem::GetNumFiles()
321{
322	return s_i32NumFiles;
323}
324
325/*!***************************************************************************
326@Function		GetFilename
327@Input			i32Index		Index of file
328@Return			A pointer to the filename of the requested file
329@Description	Looks up a file in the memory file system by name. Returns a
330				pointer to the file data as well as its size on success.
331*****************************************************************************/
332const char* CPVRTMemoryFileSystem::GetFilename(int i32Index)
333{
334	if (i32Index < 0 || i32Index > s_i32NumFiles) return 0;
335
336	return s_pFileInfo[i32Index].pszFilename;
337}
338
339
340/*****************************************************************************
341 End of file (PVRTResourceFile.cpp)
342*****************************************************************************/
343