GXS.ApplicationFileIO.pas 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. //
  2. // The graphics engine GXScene https://github.com/glscene
  3. //
  4. unit GXS.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. GXS.BaseClasses,
  16. Stage.Strings;
  17. const
  18. RC_DDS_Type = RT_RCDATA;
  19. RC_JPG_Type = RT_RCDATA;
  20. RC_XML_Type = RT_RCDATA;
  21. RC_String_Type = RT_RCDATA;
  22. type
  23. TgxApplicationResource = (aresNone, aresSplash, aresTexture, aresMaterial,
  24. aresSampler, aresFont, aresMesh);
  25. TgxAFIOCreateFileStream = function(const fileName: String; mode: Word): TStream;
  26. TgxAFIOFileStreamExists = function(const fileName: String): Boolean;
  27. TgxAFIOFileStreamEvent = procedure(const fileName: String; mode: Word;
  28. var Stream: TStream) of object;
  29. TgxAFIOFileStreamExistsEvent = function(const fileName: String): Boolean of object;
  30. (* Allows specifying a custom behaviour for TFileStream.Create.
  31. The component should be considered a helper only, you can directly specify
  32. a function via the vAFIOCreateFileStream variable.
  33. If multiple ApplicationFileIO components exist in the application,
  34. the last one created will be the active one. *)
  35. TgxApplicationFileIO = class(TComponent)
  36. private
  37. FOnFileStream: TgxAFIOFileStreamEvent;
  38. FOnFileStreamExists: TgxAFIOFileStreamExistsEvent;
  39. public
  40. constructor Create(AOwner: TComponent); override;
  41. destructor Destroy; override;
  42. published
  43. (* Event that allows you to specify a stream for the file.
  44. Destruction of the stream is at the discretion of the code that
  45. invoked TFileStream.Create. Return nil to let the default mechanism
  46. take place (ie. attempt a regular file system access). *)
  47. property OnFileStream: TgxAFIOFileStreamEvent read FOnFileStream write FOnFileStream;
  48. // Event that allows you to specify if a stream for the file exists.
  49. property OnFileStreamExists: TgxAFIOFileStreamExistsEvent
  50. read FOnFileStreamExists write FOnFileStreamExists;
  51. end;
  52. TgxDataFileCapability = (dfcRead, dfcWrite);
  53. TDataFileCapabilities = set of TgxDataFileCapability;
  54. (* Abstract base class for data file formats interfaces.
  55. This class declares base file-related behaviours, ie. ability to load/save
  56. from a file or a stream.
  57. It is highly recommended to overload ONLY the stream based methods, as the
  58. file-based one just call these, and stream-based behaviours allow for more
  59. enhancement (such as other I/O abilities, compression, cacheing, etc.)
  60. to this class, without the need to rewrite subclasses. *)
  61. TgxDataFile = class(TgxUpdateAbleObject)
  62. private
  63. FOwner : TPersistent;
  64. FResourceName: string;
  65. protected
  66. function GetOwner : TPersistent;
  67. procedure SetResourceName(const AName: string);
  68. public
  69. constructor Create(AOwner: TPersistent); virtual;
  70. destructor Destroy; override;
  71. // Describes what the TgxDataFile is capable of. Default value is [dfcRead].
  72. class function Capabilities: TDataFileCapabilities; virtual;
  73. (* Duplicates Self and returns a copy.
  74. Subclasses should override this method to duplicate their data. *)
  75. function CreateCopy(AOwner: TPersistent): TgxDataFile; virtual;
  76. procedure LoadFromFile(const fileName: string); virtual;
  77. procedure SaveToFile(const fileName: string); virtual;
  78. procedure LoadFromStream(Stream: TStream); virtual;
  79. procedure SaveToStream(Stream: TStream); virtual;
  80. (* Optionnal resource name.
  81. When using LoadFromFile/SaveToFile, the filename is placed in it,
  82. when using the Stream variants, the caller may place the resource
  83. name in it for parser use. *)
  84. property ResourceName: string read FResourceName write SetResourceName;
  85. end;
  86. TgxDataFileClass = class of TgxDataFile;
  87. TgxResourceStream = TResourceStream;
  88. // Returns true if an ApplicationFileIO has been defined
  89. function ApplicationFileIODefined: Boolean;
  90. // Queries is a file stream corresponding to the fileName exists.
  91. function FileStreamExists(const fileName: string): Boolean;
  92. function CreateResourceStream(const ResName: string; ResType: PChar): TgxResourceStream;
  93. function StrToResType(const AStrRes: string): TgxApplicationResource;
  94. var
  95. vGXAFIOCreateFileStream: TgxAFIOCreateFileStream = nil;
  96. vGXAFIOFileStreamExists: TgxAFIOFileStreamExists = nil;
  97. implementation // ------------------------------------------------------------
  98. var
  99. vAFIO: TgxApplicationFileIO = nil;
  100. function ApplicationFileIODefined: Boolean;
  101. begin
  102. Result := (Assigned(vGxAFIOCreateFileStream) and Assigned(vGxAFIOFileStreamExists)) or Assigned(vAFIO);
  103. end;
  104. function FileStreamExists(const fileName: string): Boolean;
  105. begin
  106. if Assigned(vGxAFIOFileStreamExists) then
  107. Result := vGxAFIOFileStreamExists(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. : TgxResourceStream;
  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. raise Exception.Create('Can''t create stream of application resource "%ResName"');
  127. end;
  128. function StrToResType(const AStrRes: string): TgxApplicationResource;
  129. begin
  130. if AStrRes = '[SAMPLERS]' then
  131. Result := aresSampler
  132. else if AStrRes = '[TEXTURES]' then
  133. Result := aresTexture
  134. else if AStrRes = '[MATERIALS]' then
  135. Result := aresMaterial
  136. else if AStrRes = '[STATIC MESHES]' then
  137. Result := aresMesh
  138. else if AStrRes = '[SPLASH]' then
  139. Result := aresSplash
  140. else if AStrRes = '[FONTS]' then
  141. Result := aresFont
  142. else
  143. Result := aresNone;
  144. end;
  145. // ------------------
  146. // ------------------ TgxApplicationFileIO ------------------
  147. // ------------------
  148. constructor TgxApplicationFileIO.Create(AOwner: TComponent);
  149. begin
  150. inherited Create(AOwner);
  151. vAFIO := Self;
  152. end;
  153. destructor TgxApplicationFileIO.Destroy;
  154. begin
  155. vAFIO := nil;
  156. inherited Destroy;
  157. end;
  158. // ------------------
  159. // ------------------ TgxDataFile ------------------
  160. // ------------------
  161. constructor TgxDataFile.Create(AOwner: TPersistent);
  162. begin
  163. inherited Create(AOwner);
  164. FOwner := AOwner;
  165. end;
  166. destructor TgxDataFile.Destroy;
  167. begin
  168. inherited;
  169. end;
  170. class function TgxDataFile.Capabilities : TDataFileCapabilities;
  171. begin
  172. Result := [dfcRead];
  173. end;
  174. function TgxDataFile.CreateCopy(AOwner: TPersistent): TgxDataFile;
  175. begin
  176. if Self <> nil then
  177. Result := TgxDataFileClass(Self.ClassType).Create(AOwner)
  178. else
  179. Result := nil;
  180. end;
  181. procedure TgxDataFile.LoadFromFile(const fileName: string);
  182. var
  183. fs: TStream;
  184. begin
  185. ResourceName := ExtractFileName(fileName);
  186. fs := TFileStream.Create(fileName, fmOpenRead + fmShareDenyNone);
  187. try
  188. LoadFromStream(fs);
  189. finally
  190. fs.Free;
  191. end;
  192. end;
  193. procedure TgxDataFile.SaveToFile(const fileName: string);
  194. var
  195. fs: TStream;
  196. begin
  197. ResourceName := ExtractFileName(fileName);
  198. fs := TFileStream.Create(fileName, fmCreate);
  199. try
  200. SaveToStream(fs);
  201. finally
  202. fs.Free;
  203. end;
  204. end;
  205. function TgxDataFile.GetOwner : TPersistent;
  206. begin
  207. Result:=FOwner;
  208. end;
  209. procedure TgxDataFile.LoadFromStream(Stream: TStream);
  210. begin
  211. Assert(False, 'Import for ' + ClassName + ' to ' + Stream.ClassName +
  212. ' not available.');
  213. end;
  214. procedure TgxDataFile.SaveToStream(Stream: TStream);
  215. begin
  216. Assert(False, 'Export for ' + ClassName + ' to ' + Stream.ClassName +
  217. ' not available.');
  218. end;
  219. procedure TgxDataFile.SetResourceName(const AName: string);
  220. begin
  221. FResourceName := AName;
  222. end;
  223. end.