with Allegro.Files; use Allegro.Files;
with Interfaces; use Interfaces;
with Streams.Buffers; use Streams.Buffers;
with System; use System;
private with Ada.Strings.Unbounded;
private with Ada.Real_Time;
private with Streams;
package Resources is
-- A protected state object useful for asynchronously loading resources
protected type Async_Operation is
-- Notifies the object that the operation is complete. This will unblock
-- all threads blocked on the Wait entry.
procedure Complete;
-- Checks the state of the operation without waiting for completion.
function Is_Complete return Boolean;
-- Blocks the caller until the operation is complete.
entry Wait;
private
c : Boolean := False; -- complete?
end Async_Operation;
type A_Async_Operation is access all Async_Operation;
-- Deletes the Async_Operation.
procedure Delete( op : in out A_Async_Operation );
pragma Postcondition( op = null );
----------------------------------------------------------------------------
-- Notifies the application that resource loading is beginning. If loading
-- was not in progress then a Loading_Event(loading => True) will be queued.
procedure Loading_Begins;
-- Notifies the application that resource loading has ended. If loading was
-- was in progress then a Loading_Event(loading => False) will be queued.
procedure Loading_Ends;
----------------------------------------------------------------------------
-- A Resource_File represents a resource file loaded in memory. The contents
-- of the file can be accessed via various methods. Once a Resource_File is
-- closed, its backing data should no longer be relied upon. If the file
-- data is required after the Resource_File must be closed, a copy of the
-- contents should be made.
--
-- Resource files are cached to avoid the cost of searching and reading from
-- disk each time file is needed but the details of the cache and how/when
-- it is purged are private.
type Resource_File is tagged limited private;
type A_Resource_File is access all Resource_File'Class;
-- Returns the address of the resource file's data. The length of the data
-- can be determined by calling Size.
function Get_Address( this : not null access Resource_File'Class ) return Address;
-- Returns the filename of the resource.
function Get_Filename( this : not null access Resource_File'Class ) return String;
-- Returns an identifying string comprised of the original filepath and
-- group name used to find the resource.
function Get_Id( this : not null access Resource_File'Class ) return String;
-- Returns a packfile reference to the resource. Be sure to close the
-- packfile before unloading the resource.
function Get_Packfile( this : not null access Resource_File'Class ) return A_Packfile;
-- Returns a new read-only stream backed by the resource contents. Be sure
-- to close the stream before unloading the resource.
procedure Get_Stream( this : not null access Resource_File'Class;
strm : out A_Buffer_Stream );
-- Returns the size of the file in bytes;
function Size(this : not null access Resource_File'Class ) return Unsigned_32;
----------------------------------------------------------------------------
-- Searches for and loads a resource file, returning a reference to it. The
-- search order for resources files is as follows:
--
-- 1. filepath (If filepath is an absolute file path)
-- 2. working_dir/filename
-- 3. working_dir/group.zip/filename
-- 4. media_dir/filename
-- 5. media_dir/group.zip/filename
--
-- (Where 'filename' is the filename taken from 'filepath'.)
--
-- NULL will be returned if the file is not found or can't otherwise be
-- accessed. Resource files are reference counted, so you must call
-- Unload_Resource when finished with the Resource_File.
function Load_Resource( filepath : String; group : String ) return A_Resource_File;
pragma Precondition( filepath'Length > 0 );
-- Loads a resource into memory in the same way as Load_Resource except the
-- reference will not be returned and the internal reference count will begin
-- at zero. Use this to prefetch resources from disk. No load errors are
-- reported by this procedure.
procedure Preload_Resource( filepath : String; group : String );
-- Unloads a resource file. Resource files are reference counted so be sure
-- to call this when finished with a Resource_File.
procedure Unload_Resource( resource : in out A_Resource_File );
pragma Postcondition( resource = null );
-- Returns the location where a file can be written to overwrite an
-- existing resource if possible or override an existing resource that is
-- in an archive.
--
-- The specified file will searched for with the same algorithm as
-- Load_Resource. If the resource file is found and it's not in an archive,
-- its absolute path will be returned. If the file was found in an archive
-- or couldn't be found at all, then the returned path will point to a file
-- of the same name in the executable directory.
function Write_Path( filepath : String; group : String ) return String;
pragma Precondition( filepath'Length > 0 );
pragma Postcondition( Write_Path'Result'Length > 0 );
----------------------------------------------------------------------------
RESOURCE_ERROR,
RESOURCE_FORMAT_ERROR : exception;
private
use Ada.Real_Time;
use Ada.Strings.Unbounded;
use Streams;
type Resource_File is tagged limited
record
refs : Natural := 1;
lastUse : Time := Clock;
filepath : Unbounded_String;
group : Unbounded_String;
data : A_SEA;
end record;
-- Creates a Resource_File object from a raw buffer. The resource's path and
-- group must be specified here manually. 'data' is consumed.
procedure Create_Resource( this : out A_Resource_File;
filepath : String;
group : String;
data : in out A_SEA );
pragma Precondition( filepath'Length > 0 );
pragma Precondition( data /= null );
pragma Postcondition( data = null );
pragma Postcondition( this /= null );
-- Increments the reference count for the resource file.
procedure Reference( this : not null access Resource_File'Class );
-- Decrements the referece count for the resource file.
procedure Unreference( this : not null access Resource_File'Class );
end Resources;