AppEasy Core SDK  1.5.0
Cross platform mobile and desktop app and game development SDK - The easy way to make apps
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines
CzFile.h
Go to the documentation of this file.
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_