GLS.ApplicationFileIO.pas 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/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 GLScene.inc}
  11. uses
  12. Winapi.Windows,
  13. System.Classes,
  14. System.SysUtils,
  15. GLS.BaseClasses,
  16. GLS.Strings,
  17. GLS.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. TAFIOCreateFileStream = function(const fileName: string; mode: Word): TStream;
  27. TAFIOFileStreamExists = function(const fileName: string): Boolean;
  28. TAFIOFileStreamEvent = procedure(const fileName: String; mode: Word;
  29. var Stream: TStream) of object;
  30. TAFIOFileStreamExistsEvent = 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: TAFIOFileStreamEvent;
  40. FOnFileStreamExists: TAFIOFileStreamExistsEvent;
  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: TAFIOFileStreamEvent read FOnFileStream
  50. write FOnFileStream;
  51. // Event that allows you to specify if a stream for the file exists.
  52. property OnFileStreamExists: TAFIOFileStreamExistsEvent
  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: TAFIOCreateFileStream = nil;
  95. vAFIOFileStreamExists: TAFIOFileStreamExists = nil;
  96. // ---------------------------------------------------------------------
  97. implementation
  98. // ---------------------------------------------------------------------
  99. var
  100. vAFIO: TGLApplicationFileIO = nil;
  101. function ApplicationFileIODefined: Boolean;
  102. begin
  103. Result := (Assigned(vAFIOCreateFileStream) and Assigned(vAFIOFileStreamExists)
  104. ) or Assigned(vAFIO);
  105. end;
  106. function FileStreamExists(const fileName: string): Boolean;
  107. begin
  108. if Assigned(vAFIOFileStreamExists) then
  109. Result := vAFIOFileStreamExists(fileName)
  110. else
  111. begin
  112. if Assigned(vAFIO) and Assigned(vAFIO.FOnFileStreamExists) then
  113. Result := vAFIO.FOnFileStreamExists(fileName)
  114. else
  115. Result := FileExists(fileName);
  116. end;
  117. end;
  118. function CreateResourceStream(const ResName: string; ResType: PChar)
  119. : TGLResourceStream;
  120. var
  121. InfoBlock: HRSRC;
  122. begin
  123. Result := nil;
  124. InfoBlock := FindResource(HInstance, PChar(ResName), ResType);
  125. if InfoBlock <> 0 then
  126. Result := TResourceStream.Create(HInstance, ResName, ResType)
  127. else
  128. GLSLogger.LogError
  129. (Format('Can''t create stream of application resource "%s"', [ResName]));
  130. end;
  131. // ------------------
  132. // ------------------ TGLApplicationFileIO ------------------
  133. // ------------------
  134. constructor TGLApplicationFileIO.Create(AOwner: TComponent);
  135. begin
  136. inherited Create(AOwner);
  137. vAFIO := Self;
  138. end;
  139. destructor TGLApplicationFileIO.Destroy;
  140. begin
  141. vAFIO := nil;
  142. inherited Destroy;
  143. end;
  144. // ------------------
  145. // ------------------ TGLDataFile ------------------
  146. // ------------------
  147. class function TGLDataFile.Capabilities: TGLDataFileCapabilities;
  148. begin
  149. Result := [dfcRead];
  150. end;
  151. function TGLDataFile.CreateCopy(AOwner: TPersistent): TGLDataFile;
  152. begin
  153. if Self <> nil then
  154. Result := TGLDataFileClass(Self.ClassType).Create(AOwner)
  155. else
  156. Result := nil;
  157. end;
  158. procedure TGLDataFile.LoadFromFile(const fileName: string);
  159. var
  160. fs: TStream;
  161. begin
  162. ResourceName := ExtractFileName(fileName);
  163. fs := TFileStream.Create(fileName, fmOpenRead + fmShareDenyNone);
  164. try
  165. LoadFromStream(fs);
  166. finally
  167. fs.Free;
  168. end;
  169. end;
  170. procedure TGLDataFile.SaveToFile(const fileName: string);
  171. var
  172. fs: TStream;
  173. begin
  174. ResourceName := ExtractFileName(fileName);
  175. fs := TFileStream.Create(fileName, fmCreate);
  176. try
  177. SaveToStream(fs);
  178. finally
  179. fs.Free;
  180. end;
  181. end;
  182. procedure TGLDataFile.LoadFromStream(Stream: TStream);
  183. begin
  184. Assert(False, 'Import for ' + ClassName + ' to ' + Stream.ClassName +
  185. ' not available.');
  186. end;
  187. procedure TGLDataFile.SaveToStream(Stream: TStream);
  188. begin
  189. Assert(False, 'Export for ' + ClassName + ' to ' + Stream.ClassName +
  190. ' not available.');
  191. end;
  192. procedure TGLDataFile.Initialize;
  193. begin
  194. end;
  195. procedure TGLDataFile.SetResourceName(const AName: string);
  196. begin
  197. FResourceName := AName;
  198. end;
  199. function StrToGLSResType(const AStrRes: string): TGLApplicationResource;
  200. begin
  201. if AStrRes = '[SAMPLERS]' then
  202. begin
  203. Result := aresSampler;
  204. end
  205. else if AStrRes = '[TEXTURES]' then
  206. begin
  207. Result := aresTexture;
  208. end
  209. else if AStrRes = '[MATERIALS]' then
  210. begin
  211. Result := aresMaterial;
  212. end
  213. else if AStrRes = '[STATIC MESHES]' then
  214. begin
  215. Result := aresMesh;
  216. end
  217. else if AStrRes = '[SPLASH]' then
  218. begin
  219. Result := aresSplash;
  220. end
  221. else if AStrRes = '[FONTS]' then
  222. begin
  223. Result := aresFont;
  224. end
  225. else
  226. Result := aresNone;
  227. end;
  228. end.