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