GLS.ApplicationFileIO.pas 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. //
  2. // The graphics engine GLScene
  3. //
  4. unit GLS.ApplicationFileIO;
  5. (*
  6. Components and functions that abstract file I/O access for an application.
  7. Allows re-routing file reads to reads from a single archive file f.i.
  8. *)
  9. interface
  10. {$I Stage.Defines.inc}
  11. uses
  12. Winapi.Windows,
  13. System.Classes,
  14. System.SysUtils,
  15. GLS.BaseClasses,
  16. Stage.Strings,
  17. Stage.Logger;
  18. const
  19. GLS_RC_DDS_Type = RT_RCDATA;
  20. GLS_RC_JPG_Type = RT_RCDATA;
  21. GLS_RC_XML_Type = RT_RCDATA;
  22. GLS_RC_String_Type = RT_RCDATA;
  23. type
  24. TGLApplicationResource = (aresNone, aresSplash, aresTexture, aresMaterial,
  25. aresSampler, aresFont, aresMesh);
  26. TGLAFIOCreateFileStream = function(const fileName: string; mode: Word): TStream;
  27. TGLAFIOFileStreamExists = function(const fileName: string): Boolean;
  28. TGLAFIOFileStreamEvent = procedure(const fileName: String; mode: Word;
  29. var Stream: TStream) of object;
  30. TGLAFIOFileStreamExistsEvent = function(const fileName: string)
  31. : Boolean of object;
  32. (* Allows specifying a custom behaviour for CreateFileStream.
  33. The component should be considered a helper only, you can directly specify
  34. a function via the vAFIOCreateFileStream variable.
  35. If multiple ApplicationFileIO components exist in the application,
  36. the last one created will be the active one. *)
  37. TGLApplicationFileIO = class(TComponent)
  38. private
  39. FOnFileStream: TGLAFIOFileStreamEvent;
  40. FOnFileStreamExists: TGLAFIOFileStreamExistsEvent;
  41. public
  42. constructor Create(AOwner: TComponent); override;
  43. destructor Destroy; override;
  44. published
  45. (* Event that allows you to specify a stream for the file.
  46. Destruction of the stream is at the discretion of the code that
  47. invoked CreateFileStream. Return nil to let the default mechanism
  48. take place (ie. attempt a regular file system access). *)
  49. property OnFileStream: TGLAFIOFileStreamEvent read FOnFileStream
  50. write FOnFileStream;
  51. // Event that allows you to specify if a stream for the file exists.
  52. property OnFileStreamExists: TGLAFIOFileStreamExistsEvent
  53. read FOnFileStreamExists write FOnFileStreamExists;
  54. end;
  55. TGLDataFileCapability = (dfcRead, dfcWrite);
  56. TGLDataFileCapabilities = set of TGLDataFileCapability;
  57. (* Abstract base class for data file formats interfaces.
  58. This class declares base file-related behaviours, ie. ability to load/save
  59. from a file or a stream.
  60. It is highly recommended to overload ONLY the stream based methods, as the
  61. file-based one just call these, and stream-based behaviours allow for more
  62. enhancement (such as other I/O abilities, compression, cacheing, etc.)
  63. to this class, without the need to rewrite subclasses. *)
  64. TGLDataFile = class(TGLUpdateAbleObject)
  65. private
  66. FResourceName: string;
  67. procedure SetResourceName(const AName: string);
  68. public
  69. // Describes what the TGLDataFile is capable of. Default value is [dfcRead].
  70. class function Capabilities: TGLDataFileCapabilities; virtual;
  71. // Duplicates Self and returns a copy. Subclasses should override this method to duplicate their data.
  72. function CreateCopy(AOwner: TPersistent): TGLDataFile; virtual;
  73. procedure LoadFromFile(const fileName: string); virtual;
  74. procedure SaveToFile(const fileName: string); virtual;
  75. procedure LoadFromStream(Stream: TStream); virtual;
  76. procedure SaveToStream(Stream: TStream); virtual;
  77. procedure Initialize; virtual;
  78. (* Optionnal resource name.
  79. When using LoadFromFile/SaveToFile, the filename is placed in it,
  80. when using the Stream variants, the caller may place the resource
  81. name in it for parser use. *)
  82. property ResourceName: string read FResourceName write SetResourceName;
  83. end;
  84. TGLDataFileClass = class of TGLDataFile;
  85. TGLResourceStream = TResourceStream;
  86. // Returns true if an ApplicationFileIO has been defined
  87. function ApplicationFileIODefined: Boolean;
  88. // Queries is a file stream corresponding to the fileName exists.
  89. function FileStreamExists(const fileName: string): Boolean;
  90. function CreateResourceStream(const ResName: string; ResType: PChar)
  91. : TGLResourceStream;
  92. function StrToGLSResType(const AStrRes: string): TGLApplicationResource;
  93. var
  94. vAFIOCreateFileStream: TGLAFIOCreateFileStream = nil;
  95. vAFIOFileStreamExists: TGLAFIOFileStreamExists = nil;
  96. implementation // ------------------------------------------------------------
  97. var
  98. vAFIO: TGLApplicationFileIO = nil;
  99. function ApplicationFileIODefined: Boolean;
  100. begin
  101. Result := (Assigned(vAFIOCreateFileStream) and Assigned(vAFIOFileStreamExists)
  102. ) or Assigned(vAFIO);
  103. end;
  104. function FileStreamExists(const fileName: string): Boolean;
  105. begin
  106. if Assigned(vAFIOFileStreamExists) then
  107. Result := vAFIOFileStreamExists(fileName)
  108. else
  109. begin
  110. if Assigned(vAFIO) and Assigned(vAFIO.FOnFileStreamExists) then
  111. Result := vAFIO.FOnFileStreamExists(fileName)
  112. else
  113. Result := FileExists(fileName);
  114. end;
  115. end;
  116. function CreateResourceStream(const ResName: string; ResType: PChar)
  117. : TGLResourceStream;
  118. var
  119. InfoBlock: HRSRC;
  120. begin
  121. Result := nil;
  122. InfoBlock := FindResource(HInstance, PChar(ResName), ResType);
  123. if InfoBlock <> 0 then
  124. Result := TResourceStream.Create(HInstance, ResName, ResType)
  125. else
  126. GLSLogger.LogError
  127. (Format('Can''t create stream of application resource "%s"', [ResName]));
  128. end;
  129. // ------------------
  130. // ------------------ TGLApplicationFileIO ------------------
  131. // ------------------
  132. constructor TGLApplicationFileIO.Create(AOwner: TComponent);
  133. begin
  134. inherited Create(AOwner);
  135. vAFIO := Self;
  136. end;
  137. destructor TGLApplicationFileIO.Destroy;
  138. begin
  139. vAFIO := nil;
  140. inherited Destroy;
  141. end;
  142. // ------------------
  143. // ------------------ TGLDataFile ------------------
  144. // ------------------
  145. class function TGLDataFile.Capabilities: TGLDataFileCapabilities;
  146. begin
  147. Result := [dfcRead];
  148. end;
  149. function TGLDataFile.CreateCopy(AOwner: TPersistent): TGLDataFile;
  150. begin
  151. if Self <> nil then
  152. Result := TGLDataFileClass(Self.ClassType).Create(AOwner)
  153. else
  154. Result := nil;
  155. end;
  156. procedure TGLDataFile.LoadFromFile(const fileName: string);
  157. var
  158. fs: TStream;
  159. begin
  160. ResourceName := ExtractFileName(fileName);
  161. fs := TFileStream.Create(fileName, fmOpenRead + fmShareDenyNone);
  162. try
  163. LoadFromStream(fs);
  164. finally
  165. fs.Free;
  166. end;
  167. end;
  168. procedure TGLDataFile.SaveToFile(const fileName: string);
  169. var
  170. fs: TStream;
  171. begin
  172. ResourceName := ExtractFileName(fileName);
  173. fs := TFileStream.Create(fileName, fmCreate);
  174. try
  175. SaveToStream(fs);
  176. finally
  177. fs.Free;
  178. end;
  179. end;
  180. procedure TGLDataFile.LoadFromStream(Stream: TStream);
  181. begin
  182. Assert(False, 'Import for ' + ClassName + ' to ' + Stream.ClassName +
  183. ' not available.');
  184. end;
  185. procedure TGLDataFile.SaveToStream(Stream: TStream);
  186. begin
  187. Assert(False, 'Export for ' + ClassName + ' to ' + Stream.ClassName +
  188. ' not available.');
  189. end;
  190. procedure TGLDataFile.Initialize;
  191. begin
  192. end;
  193. procedure TGLDataFile.SetResourceName(const AName: string);
  194. begin
  195. FResourceName := AName;
  196. end;
  197. function StrToGLSResType(const AStrRes: string): TGLApplicationResource;
  198. begin
  199. if AStrRes = '[SAMPLERS]' then
  200. begin
  201. Result := aresSampler;
  202. end
  203. else if AStrRes = '[TEXTURES]' then
  204. begin
  205. Result := aresTexture;
  206. end
  207. else if AStrRes = '[MATERIALS]' then
  208. begin
  209. Result := aresMaterial;
  210. end
  211. else if AStrRes = '[STATIC MESHES]' then
  212. begin
  213. Result := aresMesh;
  214. end
  215. else if AStrRes = '[SPLASH]' then
  216. begin
  217. Result := aresSplash;
  218. end
  219. else if AStrRes = '[FONTS]' then
  220. begin
  221. Result := aresFont;
  222. end
  223. else
  224. Result := aresNone;
  225. end;
  226. //----------------------------------------------------------------------------
  227. end.