AppEasy Core SDK
1.5.0
Cross platform mobile and desktop app and game development SDK - The easy way to make apps
|
00001 // 00002 // 00003 // AppEasy SDK - Cross Platform Multi-purpose Game and App Engine 00004 // 00005 // Developed by Matthew Hopwood of Pocketeers Limited - www.pocketeers.co.uk 00006 // 00007 // For updates, tutorials and more details check out www.appeasymobile.com 00008 // 00009 // This code is provided free of charge and without any warranty whatsoever. You must ensure that this whole notice is present in all files and derivatives, so the reader knows its origin. 00010 // If you use this SDK in your product then please ensure that you credit AppEasy's usage appropriately. Please see www.appeasymobile.com for licensing details and support 00011 // 00012 // 00013 00014 #if !defined(_CZ_FILE_H_) 00015 #define _CZ_FILE_H_ 00016 00017 #include "IzPlatformFile.h" 00018 #include "CzString.h" 00019 #include "CzHttp.h" 00020 #include "CzDataIO.h" 00021 #include "CzXoml.h" 00022 #include "CzXomlVariables.h" 00023 #include "CzEvents.h" 00024 00025 00026 00027 class CzScript; 00028 00029 /** 00030 @addtogroup Core 00031 @{ 00032 */ 00033 00034 /** 00035 @struct CzFilePathComponents 00036 00037 @brief file path components. 00038 00039 */ 00040 00041 struct CzFilePathComponents 00042 { 00043 CzString Folder; ///< Folder name 00044 CzString Filename; ///< Name of file 00045 CzString Extension; ///< File extension 00046 }; 00047 00048 /** 00049 @class CzFile 00050 00051 @brief CzFile respresents a file. 00052 00053 <h1>Introduction</h1> 00054 AppEasy encapsulates the file system neatly into a single class called CzFile. This class enables the following features: 00055 - Auto file close / cleanup when the file object goes out of scope 00056 - Reading and writing of local files 00057 - Reading and writing of memory based files 00058 - Blocking and none blocking reading of files from an external source such as a web site / server 00059 - File name splitting 00060 - File type retrieval 00061 00062 <h1>Loading a Local File</h1> 00063 Loading a local file is very simple, as is shown in the following example: 00064 00065 @code 00066 // Here we declare a string, open a file then read some data into it 00067 CzString data; 00068 CzFile file; 00069 if (file.Open("\\my_data.txt", "rb")) 00070 { 00071 int len = file.getFileSize(); 00072 data.allocString(len); 00073 data.setLength(len); 00074 file.Read((void*)data.c_str(), len); 00075 } 00076 @endcode 00077 00078 <h1>Saving a Local File</h1> 00079 Saving a local file is also a very simple, as is shown in the following example: 00080 00081 @code 00082 // Here we declare a string, open a file then write the string to it 00083 CzString data("Hello storage, how you doing?"); 00084 CzFile file; 00085 if (file.Open("\\my_data.txt", "wb")) 00086 { 00087 file.Write((void*)data.c_str(), data.GetLength()); 00088 } 00089 @endcode 00090 00091 <h1>Loading a Memory Based File</h1> 00092 Loading a memory file is just as easy as opening a local file, as is shown in the following example: 00093 00094 @code 00095 // Here we declare a string, open a file then read some data into it from memory 00096 CzString data; 00097 CzFile file; 00098 if (file.Open(my_data_in_memory, my_data_length)) 00099 { 00100 int len = file.getFileSize(); 00101 data.allocString(len); 00102 data.setLength(len); 00103 file.Read((void*)data.c_str(), len); 00104 } 00105 @endcode 00106 00107 <h1>Loading a Remote File</h1> 00108 The format of loading a file for remote is the same as local file loading 00109 00110 @code 00111 // Here we declare a string, open a remote file then read some data into it 00112 CzString data; 00113 CzFile file; 00114 if (file.Open("http://www.myserver.com/my_data.txt", NULL, true)) 00115 { 00116 int len = file.getFileSize(); 00117 data.allocString(len); 00118 data.setLength(len); 00119 file.Read((void*)data.c_str(), len); 00120 } 00121 @endcode 00122 00123 With a few differences. The first differenece is the very noticable filename change to that of a web address. The second more subtle difference is the inlusion of a 3rd parameter to 00124 Open() which tells the method to block until the complete file has been downoaded or an error occurs. 00125 00126 With modern games / apps the user expects action on the screen most of the time, so sitting loading your assets from a server with no viusal update would not be a great idea, ruling 00127 blocking remote file loading out for anything more than a few files. A better alternative is to use asynchonrous file downloading that is none blocking, allowing the game loop to 00128 proceed whilst your assets load. 00129 00130 Loading a remote file using a none blocking method can be achieved as shown below: 00131 00132 @code 00133 int32 WebFileRetrievedCallback(void* caller, void* data) 00134 { 00135 CzFile* file = (CzFile*)caller; 00136 00137 // file->getContent() and file->getContentLength() contain the data and data size 00138 00139 delete file; 00140 00141 return 0; 00142 } 00143 // Initiate a none blocking file download 00144 CzFile* image_file = new CzFile(); 00145 image_file->setFileAvailableCallback(WebFileRetrievedCallback, NULL); 00146 image_file->Open("http://www.battleballz.com/bb_icon.gif", NULL, false); 00147 @endcode 00148 00149 Examining the above code we can see that we set up a callback so that we get notified when our file has been downloaded. Next we initiate the file download but this time passing "false" 00150 as our blocking parameter to ensure that the download does not block the main thread. 00151 00152 If you don't fancy setting up a callback, you can poll the CzFile instead to see if the file has been retrieved using: 00153 00154 @code 00155 bool CzFile::isFileAvailable() 00156 @endcode 00157 00158 <h1>Other Useful File Tools</h1> 00159 CzFile also contains a few additional useful tool type methods: 00160 00161 @code 00162 static void GetComponents(const char* file_path, CzFilePathComponents& components); // Splits a path into its separate drive, path, name and extension components 00163 static bool GetFileType(const char* file_path, CzString& type); // Returns the file type of the supplied file name 00164 static bool isHttp(const char* file_path, int path_len); // Checks a file name to see if it uses the http protocol 00165 static bool isFile(const char* file_path, int path_len); // Returns true if the path is a file (simple check for for an extension, will not work with url's) 00166 static bool FileExists(const char* file_path); // Returns true if the file exists 00167 static bool DeleteFile(const char* file_path); // Deletes a file 00168 @endcode 00169 00170 00171 @todo 00172 - Add none blocking file I/O 00173 - Add timeout check to blocking http download 00174 - Add methods for reading and writing common types 00175 - Add support for directory creation / removal 00176 - Add support directory / file discovery 00177 00178 */ 00179 00180 class CzFile 00181 { 00182 public: 00183 00184 protected: 00185 // Properties 00186 CzFileHandle File; ///< File handle 00187 CzString Filename; ///< Name of file 00188 bool FileAvailable; ///< True when file is available 00189 CzCallback FileAvailableCallback; ///< Callback to be called when file is available 00190 void* FileAvailableCallbackData; ///< Callback data to be passed back with callback 00191 eCzFileError Error; ///< Contains error code if any if file not received 00192 public: 00193 CzFileHandle getFileHandle() { return File; } 00194 void setFilename(const char* filename) { Filename.setString(filename); } 00195 CzString& getFilename() { return Filename; } 00196 void setFileAvailable(bool available) { FileAvailable = available; } 00197 bool isFileAvailable() { return FileAvailable; } 00198 void setFileAvailableCallback(CzCallback callback, void *data) { FileAvailableCallback = callback; FileAvailableCallbackData = data; } 00199 int getFileSize(); 00200 eCzFileError getError() const { return Error; } 00201 void* getContent(); 00202 int getContentLength() const; 00203 // Properties end 00204 00205 protected: 00206 bool InMemory; 00207 CzHttpRequest* Request; 00208 void NotifyAvailable(); 00209 00210 public: 00211 CzFile() : File(NULL), Error(CzFileErrorNone), Request(NULL), FileAvailableCallback(NULL), FileAvailableCallbackData(NULL) { } 00212 CzFile(const char* filename) : File(NULL), Error(CzFileErrorNone), Request(NULL), FileAvailableCallback(NULL), FileAvailableCallbackData(NULL) 00213 { 00214 Filename.setString(filename); 00215 } 00216 virtual ~CzFile() 00217 { 00218 SAFE_DELETE(Request) 00219 Close(); 00220 } 00221 bool Open(const char* filename = NULL, const char* mode = NULL, bool blocking = false); // Open file for read or write 00222 bool Open(void* memory_buffer, int memory_buffer_len); // Open file for read or write from a memory buffer 00223 bool Invalid(); // Releases file 00224 bool Download(); // Download file from an external location 00225 00226 bool Read(void* buffer, int len); 00227 bool Write(void* buffer, int len); 00228 bool Seek(int offset, eCzFileSeekOrigin origin); 00229 void Close(); 00230 00231 // Utility 00232 static void GetComponents(const char* file_path, CzFilePathComponents& components); 00233 static bool GetFileType(const char* file_path, CzString& type); 00234 static bool isHttp(const char* file_path, int path_len); 00235 static bool isFile(const char* file_path, int path_len); 00236 static bool FileExists(const char* file_path); 00237 static bool DeleteFile(const char* file_path); 00238 00239 // Internal 00240 void FileReceived(CzHttpRequest* request, int error); // Called by the http callback internally when the file is received 00241 00242 }; 00243 00244 /** 00245 @class CzDataFile 00246 00247 @brief A XOML data file. 00248 00249 CzDataFile is the XOML representation of a file (a file holder) and enables files to be created and loaded using the File XOML tag. 00250 00251 Its often useful to be able to load files into an app and do something with the data that they contain. Files in XOML are just like any other resource and can be declared inside a scene 00252 in which case they become local to the scene or declared outside a scene in which case they become global. They can also be loaded from local storage or from a web server, Files can also 00253 convert their data after loading from an number of different formats. We will begin by taking a look at the properties that are available for the Files tag: 00254 - Name (string) - Name of this file resource 00255 - Tag (string) - Resource tag (used to group resources together) (optional) 00256 - Location (filename) - Name of the file including extension (can include web addresses) 00257 - Preload (boolean) - If set to true then the file will be loaded immediately. By setting to false the file will be loaded when it is first used or can be loaded by an action later (default is true). 00258 - Blocking (boolean) - Web based files take time to download from the web so its useful to allow execution of the app to continue whilst it downloads. To prevent the file download from blocking the app set Blocking="false" (default is to block). 00259 - Condition (variable) - A condition variable that must evaluate to true for this resource to be loaded (this is an optional feature and can be used to conditionally load resources based on certain conditions such as screen size or device type etc..) (optional) 00260 - FileType (string) – Type of file (does not affect how the file is loaded) (optional) 00261 - Variable (variable) – Name of the variable that the contents of the file should be written into once loaded (optional) 00262 - Script (script) - Name of the script that the contents of the file should be written into once loaded. This is used only to load a script resource with script (optional) 00263 - Converter (type) – How to convert the loaded data to text (html, hex, urlencoded). This is useful if you have data in a common web format such as url-encoded. Passing urlencoded will cause the data to be converted from url-encoded to plain text format (optional) 00264 - OnLoaded (actions list) - Actions list to call when the file is loaded 00265 - OnError (actions list) - Actions list to call when an error occurs 00266 00267 The Files example has been provided to show how to load a file and reload its contents. Lets take a look at the XOML for this example: 00268 00269 @code 00270 <!-- Create a variable to load a file into --> 00271 <Variable Name="FileContents" Type="string" /> 00272 00273 <!-- Declare a file --> 00274 <File Name="File1" Location="file1.txt" FileType="txt" Variable="FileContents" 00275 Preload="true" /> 00276 00277 <!-- Create a scene --> 00278 <Scene Name="Scene1" Current="true" > 00279 00280 <!-- Create a label to display our files contents --> 00281 <Label Font="serif" Size="200, 200" TextColour="255, 255, 128, 255" 00282 Background="Button1Brush" BackgroundColour="255, 80, 80, 255" 00283 Binding="[Text]FileContents" /> 00284 00285 <!-- Create a group of buttons to load 3 different files --> 00286 <Label Font="serif" Size="80, 50" Position="-100, 100" Text="Load File1" 00287 Background="Button1Brush" BackgroundColour="80, 80, 255, 255" OnTapped="Load"> 00288 <Actions Name="Load"> 00289 <Action Method="LoadFile" Param1="File1" Param2="true" Param3="file1.txt" /> 00290 </Actions> 00291 </Label> 00292 <Label Font="serif" Size="80, 50" Position="0, 100" Text="Load File2" 00293 Background="Button1Brush" BackgroundColour="80, 80, 255, 255" OnTapped="Load"> 00294 <Actions Name="Load"> 00295 <Action Method="LoadFile" Param1="File1" Param2="true" Param3="file2.txt" /> 00296 </Actions> 00297 </Label> 00298 <Label Font="serif" Size="80, 50" Position="100, 100" Text="Load File3" 00299 Background="Button1Brush" BackgroundColour="80, 80, 255, 255" OnTapped="Load"> 00300 <Actions Name="Load"> 00301 <Action Method="LoadFile" Param1="File1" Param2="true" Param3="file3.txt" /> 00302 </Actions> 00303 </Label> 00304 00305 </Scene> 00306 @endcode 00307 00308 We begin this example by creating a variable called FileContents that we will later load our files contents into. Next we create a File that loads the contents of file1.txt and 00309 writes it to the FileContents variable. Next we create a label that will sho the files contents due to the binding to the FileContents variable. Lastly we create 3 label buttons 00310 that each call the LoadFile action when tapped. Each of the LoadFile actions load different files into the FileContents variable. 00311 00312 00313 */ 00314 00315 class CzDataFile : public IzXomlResource 00316 { 00317 public: 00318 enum eDataFile_State 00319 { 00320 State_Invalid, 00321 State_Loaded, 00322 }; 00323 00324 enum eDataFile_Converter 00325 { 00326 Converter_None, 00327 Converter_FromHTML, 00328 Converter_FromHex, 00329 Converter_FromURLEncoded, 00330 }; 00331 00332 // Proprties 00333 protected: 00334 eDataFile_State State; ///< State of file 00335 CzString Filename; ///< Name of file 00336 CzString FileType; ///< Type of file (has not affect on how file is loaded) 00337 CzXomlVariable* TargetVariable; ///< The file will be loaded into this variable if it is set 00338 CzScript* TargetScript; ///< The file will be loaded into this script if it is set 00339 CzDataInput* DataInput; ///< Input stream 00340 eDataFile_Converter Converter; ///< Conversion method used on input data 00341 CzEventManager* EventsManager; ///< List of events that the file handles 00342 public: 00343 eDataFile_State getState() const { return State; } 00344 CzString& getFilename() { return Filename; } 00345 CzDataInput* getDataInput() { if (Load()) return DataInput; return NULL; } 00346 void setFileType(const char* type) { FileType = type; } 00347 CzString& getFileType() { return FileType; } 00348 void setTargetVariable(const char* var); 00349 CzXomlVariable* getTargetVariable() { return TargetVariable; } 00350 void setConverter(eDataFile_Converter method) { Converter = method; } 00351 eDataFile_Converter getConverter() const { return Converter; } 00352 CzEventManager* getEventsManager() { return EventsManager; } 00353 // Properties end 00354 00355 protected: 00356 CzFile* File; // File object 00357 public: 00358 00359 CzDataFile() : IzXomlResource(), File(NULL), State(State_Invalid), DataInput(NULL), TargetVariable(NULL), Converter(Converter_None), TargetScript(NULL), EventsManager(NULL) { setClassType("file"); } 00360 virtual ~CzDataFile(); 00361 00362 bool Init(const char* filename, bool preload, bool blocking); 00363 bool Load(bool blocking = true); // Force load the file 00364 00365 // Implementation of IzXomlResource interface 00366 int LoadFromXoml(IzXomlResource* parent, bool load_children, CzXmlNode* node); 00367 00368 // Event handlers 00369 virtual void ProcessEventActions(unsigned int event_name); 00370 virtual void NotifyLoaded(); 00371 virtual void NotifyError(); 00372 00373 // Internal 00374 void FinishLoad(); // Called back when aysnc loading is completed 00375 }; 00376 00377 /** 00378 @class CzDataFileCreator 00379 00380 @brief Creates an instance of a file object. 00381 00382 Enables a file to be created from XOML. 00383 00384 */ 00385 00386 class CzDataFileCreator : public IzXomlClassCreator 00387 { 00388 public: 00389 CzDataFileCreator() 00390 { 00391 setClassName("file"); 00392 } 00393 IzXomlResource* CreateInstance(IzXomlResource* parent) { return new CzDataFile(); } 00394 }; 00395 00396 /// @} 00397 00398 #endif // _CZ_FILE_H_