1. -- 
  2. -- Copyright (c) 2012 Kevin Wellwood 
  3. -- All rights reserved. 
  4. -- 
  5. -- This source code is distributed under the Modified BSD License. For terms and 
  6. -- conditions, see license.txt. 
  7. -- 
  8.  
  9. with Allegro.Files;                     use Allegro.Files; 
  10. with Interfaces;                        use Interfaces; 
  11. with Streams.Buffers;                   use Streams.Buffers; 
  12. with System;                            use System; 
  13.  
  14. private with Ada.Strings.Unbounded; 
  15. private with Ada.Real_Time; 
  16. private with Streams; 
  17.  
  18. package Resources is 
  19.  
  20.     -- A protected state object useful for asynchronously loading resources 
  21.     protected type Async_Operation is 
  22.  
  23.         -- Notifies the object that the operation is complete. This will unblock 
  24.         -- all threads blocked on the Wait entry. 
  25.         procedure Complete; 
  26.  
  27.         -- Checks the state of the operation without waiting for completion. 
  28.         function Is_Complete return Boolean; 
  29.  
  30.         -- Blocks the caller until the operation is complete. 
  31.         entry Wait; 
  32.  
  33.     private 
  34.         c : Boolean := False;    -- complete? 
  35.     end Async_Operation; 
  36.     type A_Async_Operation is access all Async_Operation; 
  37.  
  38.     -- Deletes the Async_Operation. 
  39.     procedure Delete( op : in out A_Async_Operation ); 
  40.     pragma Postcondition( op = null ); 
  41.  
  42.     ---------------------------------------------------------------------------- 
  43.  
  44.     -- Notifies the application that resource loading is beginning. If loading 
  45.     -- was not in progress then a Loading_Event(loading => True) will be queued. 
  46.     procedure Loading_Begins; 
  47.  
  48.     -- Notifies the application that resource loading has ended. If loading was 
  49.     -- was in progress then a Loading_Event(loading => False) will be queued. 
  50.     procedure Loading_Ends; 
  51.  
  52.     ---------------------------------------------------------------------------- 
  53.  
  54.     -- A Resource_File represents a resource file loaded in memory. The contents 
  55.     -- of the file can be accessed via various methods. Once a Resource_File is 
  56.     -- closed, its backing data should no longer be relied upon. If the file 
  57.     -- data is required after the Resource_File must be closed, a copy of the 
  58.     -- contents should be made. 
  59.     -- 
  60.     -- Resource files are cached to avoid the cost of searching and reading from 
  61.     -- disk each time file is needed but the details of the cache and how/when 
  62.     -- it is purged are private. 
  63.     type Resource_File is tagged limited private; 
  64.     type A_Resource_File is access all Resource_File'Class; 
  65.  
  66.     -- Returns the address of the resource file's data. The length of the data 
  67.     -- can be determined by calling Size. 
  68.     function Get_Address( this : not null access Resource_File'Class ) return Address; 
  69.  
  70.     -- Returns the filename of the resource. 
  71.     function Get_Filename( this : not null access Resource_File'Class ) return String; 
  72.  
  73.     -- Returns an identifying string comprised of the original filepath and 
  74.     -- group name used to find the resource. 
  75.     function Get_Id( this : not null access Resource_File'Class ) return String; 
  76.  
  77.     -- Returns a packfile reference to the resource. Be sure to close the 
  78.     -- packfile before unloading the resource. 
  79.     function Get_Packfile( this : not null access Resource_File'Class ) return A_Packfile; 
  80.  
  81.     -- Returns a new read-only stream backed by the resource contents. Be sure 
  82.     -- to close the stream before unloading the resource. 
  83.     procedure Get_Stream( this : not null access Resource_File'Class; 
  84.                           strm : out A_Buffer_Stream ); 
  85.  
  86.     -- Returns the size of the file in bytes; 
  87.     function Size(this : not null access Resource_File'Class ) return Unsigned_32; 
  88.  
  89.     ---------------------------------------------------------------------------- 
  90.  
  91.     -- Searches for and loads a resource file, returning a reference to it. The 
  92.     -- search order for resources files is as follows: 
  93.     -- 
  94.     -- 1. filepath  (If filepath is an absolute file path) 
  95.     -- 2. working_dir/filename 
  96.     -- 3. working_dir/group.zip/filename 
  97.     -- 4. media_dir/filename 
  98.     -- 5. media_dir/group.zip/filename 
  99.     -- 
  100.     -- (Where 'filename' is the filename taken from 'filepath'.) 
  101.     -- 
  102.     -- NULL will be returned if the file is not found or can't otherwise be 
  103.     -- accessed. Resource files are reference counted, so you must call 
  104.     -- Unload_Resource when finished with the Resource_File. If 'cache' is True, 
  105.     -- the resource will be kept in memory even after no references remain. This 
  106.     -- is useful for keeping a resource cached in memory for the life of the 
  107.     -- application. 
  108.     function Load_Resource( filepath : String; 
  109.                             group    : String; 
  110.                             cache    : Boolean ) return A_Resource_File; 
  111.     pragma Precondition( filepath'Length > 0 ); 
  112.  
  113.     -- Loads a resource into memory in the same way as Load_Resource except the 
  114.     -- reference will not be returned and the internal reference count will begin 
  115.     -- at zero. Use this to prefetch resources from disk. No load errors are 
  116.     -- reported by this procedure. 
  117.     procedure Preload_Resource( filepath : String; group : String ); 
  118.  
  119.     -- Unloads a resource file. Resource files are reference counted so be sure 
  120.     -- to call this when finished with a Resource_File. 
  121.     procedure Unload_Resource( resource : in out A_Resource_File ); 
  122.     pragma Postcondition( resource = null ); 
  123.  
  124.     -- Returns the location where a file can be written to overwrite an 
  125.     -- existing resource if possible or override an existing resource that is 
  126.     -- in an archive. 
  127.     -- 
  128.     -- The specified file will searched for with the same algorithm as 
  129.     -- Load_Resource. If the resource file is found and it's not in an archive, 
  130.     -- its absolute path will be returned. If the file was found in an archive 
  131.     -- or couldn't be found at all, then the returned path will point to a file 
  132.     -- of the same name in the executable directory. 
  133.     function Write_Path( filepath : String; group : String ) return String; 
  134.     pragma Precondition( filepath'Length > 0 ); 
  135.     pragma Postcondition( Write_Path'Result'Length > 0 ); 
  136.  
  137.     ---------------------------------------------------------------------------- 
  138.  
  139.     RESOURCE_ERROR, 
  140.     RESOURCE_FORMAT_ERROR : exception; 
  141.  
  142. private 
  143.  
  144.     use Ada.Real_Time; 
  145.     use Ada.Strings.Unbounded; 
  146.     use Streams; 
  147.  
  148.     type Resource_File is tagged limited 
  149.         record 
  150.             refs     : Natural := 1; 
  151.             keep     : Boolean := False;      -- keep in cache 
  152.             lastUse  : Time := Clock; 
  153.             filepath : Unbounded_String; 
  154.             group    : Unbounded_String; 
  155.             data     : A_SEA; 
  156.         end record; 
  157.  
  158. end Resources;