/*
    ####             #    #     # #
    #   #            #    #       #          The FreeWare C library for
    #   #  ##   ###  #  # #     # ###             RISC OS machines
    #   # #  # #     # #  #     # #  #   ___________________________________
    #   # ####  ###  ##   #     # #  #
    #   # #        # # #  #     # #  #    Please refer to the accompanying
    ####   ### ####  #  # ##### # ###    documentation for conditions of use
    ________________________________________________________________________

    File:    File.h
    Author:  Copyright  1993, 1994 Jason Williams, Tim Browse, 
                                    Julian Smith, Sergio Monesi,
                                    Jason Howat.
    Version: 1.09 (12 Dec 1995)
    Purpose: Low level file operations, much faster than stdio equivalents,
             and more convenient when interacting with other code that uses
             RISC OS file handles to refer to files.
             Also sundry useful macros and functions to make file
             handling a bit easier.
    Mods:    1.02 (22 Jul 1995) JS Added Desk_File_AllocLoad0().
             1.03 (01 Aug 1995) SM Added Desk_File_ReadExtent().
    
             1.04 (31 Aug 1995) JH A few new filetypes.
             
             1.05 (20 Sep 1995) JS Added Desk_File_CheckError and 
                                   Desk_File_XCheckError
             1.06 (29 Sep 1995) JS Added Desk_File_SaveMemory
             1.07 (31 Oct 1995) BS Changed Desk_File_SetType to be an assembler 
                                   veneer returning (Desk_os_error*)
                                   Added Desk_File_SetLoad, Desk_File_SetExec, Desk_File_CreateDirectory
             1.08 (19 Nov 1995) JS Added Desk_File_AllocLoad
             1.09 (12 Dec 1995) JS Added Desk_File_EnsureDirectory, Desk_File_EnsureParentDirectory
             1.10 (10 Jun 1996) JS Added Desk_File_SaveMemory2 - saves with filetype.
                                
*/


#ifndef __Desk_File_h
#define __Desk_File_h

#ifdef __cplusplus
	extern "C" {
#endif

#ifndef __Desk_Core_h
	#include "Desk.Core.h"
#endif

#ifndef __Desk_SWI_h
	#include "Desk.SWI.h"
#endif

#ifndef __Desk_Error2_h
	#include "Desk.Error2.h"
#endif

/*
extern void	Desk_file_lasterror;
Removed - Desk doesn't need this.
*/
/*
 *  IMPORTANT NOTE
 *  Desk_file_lasterror is used to provide a more convenient SWI veneer for certain
 *  file operations (Open, reading, etc, return handles/values directly,
 *  rather than you having to provide the address of a variable for the
 *  returned value, leaving no convenient way of returning errors!)
 *
 *  Thus, Desk_file_lasterror is set by the file operations:
 *    Open, Close, EOF, Read8/32/Bytes, Write8/32/Bytes, Seek, ReturnPos
 *
 *  However, note that it is just a pointer to the error returned by the SWI
 *  call, so it MUST be used immediately after the call, or else it may be
 *  invalid or possibly even dangerously corrupted
 *  If for example, you wish to close the file before reporting the error,
 *  you must first copy the error into your own Desk_os_error block.
 *
 *  If no error occurred on the last file op, Desk_file_lasterror will be NULL.
 *  Most of the above functions also return values (filehandle = NULL etc)
 *  that will indicate when an error may have occurred, at which time you
 *  can interrogate Desk_file_lasterror to work out what the error was.
 *
 *  Note also that all of the above calls which do not have a specific
 *  return value (Close, Write*, Seek) return the Desk_os_error pointer directly
 *  as well as setting Desk_file_lasterror, for convenience.
 */


extern void	Desk_File_Delete( const char *filename);
/*
 *  Attempts to delete the named file. Use carefully!
 */


extern int Desk_File_Size( const char *filename);
/*
 *  Reads the size (in bytes) of the file. A return value of 0 indicates
 *  either the file is 0 bytes long, or an error occurred (which usually
 *  means that the file doesn't exist)
 */


extern Desk_bool Desk_File_Exists( const char *filename);
/*
 *  This returns Desk_bool_TRUE if the file exists.
 *  (It attempts to open the file for reading - it returns Desk_bool_TRUE if successful)
 */



typedef int Desk_file_position;
typedef int Desk_file_handle;

#define Desk_file_READERROR (-1)


typedef enum
{
  Desk_file_READ   = 0x40,          /* Open the file for reading                 */
  Desk_file_WRITE  = 0x80,          /* CREATE/WIPE the file, open it for writing */
  Desk_file_APPEND = 0xC0           /* Open for appending to existing file. NOTE
                                * that I don't have the PRMs so I can't tell
                                * you where this puts the initial file pointer
                                */
} Desk_file_access;
/*
 *  These are used when opening files. NOTE that they correspond directly
 *  to Desk_OS_File opening flags (Desk_OS_File register 0 entry value)
 */


extern Desk_file_handle Desk_File_Open( const char *filename, Desk_file_access access);
/*
 *  Opens the given file for reading or writing (see Desk_file_access's above)
 *  Returns the file handle, or NULL if it failed
 *  (if NULL, you can check Desk_file_lasterror for the reason)
 *
 *  NOTE that the OS will return a NULL file handle if we try to open a
 *  non existent file, but does NOT flag this as an error (i.e. Desk_File_Open
 *  returns NULL, but Desk_file_lasterror is ALSO NULL). You must therefore
 *  check Desk_file_lasterror before blindly trying to use it to report an error.
 */


extern void	Desk_File_Close(Desk_file_handle handle);
/*
 *  Closes an open file stream, using the handle returned by Desk_File_Open
 *  After a close, the Desk_file_handle is no longer valid, so do not try
 *  to use it.
 */


extern Desk_bool Desk_File_EOF(Desk_file_handle handle);
/*
 *  Returns Desk_bool_TRUE if the end of the file has been reached
 */


extern void	Desk_File_Seek(Desk_file_handle handle, Desk_file_position position);
/*
 *  Seeks the file pointer to the given position (an offset in terms of
 *  bytes offset from the start of the file). Subsequent read/write
 *  operations will read from or write to that part of the file.
 */


extern Desk_file_position Desk_File_ReturnPos(Desk_file_handle handle);
/*
 *  Returns the current file pointer position.
 *  This is a value which, when passed to Desk_File_Seek, will return you to the
 *  same position you were at when you called Desk_File_ReturnPos
 */


extern int Desk_File_ReadExtent(Desk_file_handle handle);
/*
 *  Returns the current file extent (or -1 if an error occurrs)
 */


extern void	Desk_File_WriteBytes(Desk_file_handle handle,
                                 const void *buffer, int numbytes);
/*
 *  This writes a chunk of data to the current position in a file opened
 *  for writing. 'numbytes' bytes will be written from the given buffer.
 *  It is important to check for errors from this call as Disc Full errors
 *  are a common occurrence.
 */


extern int Desk_File_ReadBytes(Desk_file_handle handle, void *buffer, int numbytes);
/*
 *  Reads the given number of bytes of data from the given file, into the
 *  given buffer. Returns the number of bytes NOT successfully read.
 *  (i.e. if you hit EOF during the read, the return value will be non-zero)
 */


extern void	Desk_File_Write8(Desk_file_handle handle, int byte);
/*
 *  Writes an 8-bit value (a byte/char) to the given output file.
 */

#define Desk_File_WriteByte Desk_File_Write8
#define Desk_File_WriteChar Desk_File_Write8


extern int Desk_File_Read8(Desk_file_handle handle);
 /*
  *  Reads an 8-bit value (a byte/char) from the given input file.
  If this is first attempt to read beyond end of file, Desk_file_READERROR
  *  will be returned. Subsequent attempts will result in an Error2 error being generated.
  (See PRM 2-60, this behaviour mirrors OS_BGet).
  *
  *  VERY IMPORTANT NOTE!
  *  DO NOT use Desk_File_Read8() in a line like the following:
  *    shortvalue = Desk_File_Read8(infile) | (Desk_File_Read8(infile) << 8);
  *
  *  The problem here is that the C compiler is allowed to evaluate the 2
  *  functions in any order it sees fit, so may read the two bytes in the
  *  incorrect order. You MUST therefore do such an operation with code
  *  in the following form if you are to sure it will work:
  *    shortvalue = Desk_File_Read8(infile);
  *    shortvalue |= Desk_File_Read8(infile) << 8;
  */

#define Desk_File_ReadByte Desk_File_Read8
#define Desk_File_ReadChar Desk_File_Read8


extern void	Desk_File_Write32(Desk_file_handle handle, int word);
 /*
  *  Writes an 32-bit value (a word/int/long) to the given output file.
  */

#define Desk_File_WriteWord Desk_File_Write32
#define Desk_File_WriteInt  Desk_File_Write32
#define Desk_File_WriteLong Desk_File_Write32


extern int Desk_File_Read32(Desk_file_handle handle);
 /*
  *  Reads a 32-bit value (a word/int/long) from the given input file.
  */

#define Desk_File_ReadWord Desk_File_Read32
#define Desk_File_ReadInt  Desk_File_Read32
#define Desk_File_ReadLong Desk_File_Read32


extern int Desk_File_Read32R(Desk_file_handle handle);
 /*
  *  Identical to Desk_File_Read32, but reverses the byte ordering as it reads
  *  (converts from little endian to big endian format). This is very useful
  *  for reading textual tags from files, as they can then be compared to
  *  integer constants of the form 'aTag' rather than having to reverse the
  *  byte order manually (i.e. using the tag 'gaTa' which is less human
  *  readable)
  */

#define Desk_File_ReadWordR Desk_File_Read32R
#define Desk_File_ReadIntR  Desk_File_Read32R
#define Desk_File_ReadLongR Desk_File_Read32R


extern void	Desk_File_Write32R(Desk_file_handle handle, int word);
 /*
  *  Same as Write32, but reverses the byte order before writing. See
  *  Read32r for more details about why you'd want to do this.
  */

#define Desk_File_WriteWordR Desk_File_Write32R
#define Desk_File_WriteIntR  Desk_File_Write32R
#define Desk_File_WriteLongR Desk_File_Write32R


extern void	Desk_File_SetType( const char *filename, int type);
/*
Inputs:   filename - name of file to change the type of.
      	  type     - the number of the filetype to set.
Returns:  pointer to Desk_os_error if an error occurred, or NULL.
Purpose:  Change the filetype of a named file.
      	  This is an assembler veneer to the standard RISC OS SWI
      	  service (Desk_OS_File 18).
*/



extern void	Desk_File_SetLoad( const char *filename, int load);
/*
Sets load address of the specified file.

Assembler veneer onto Desk_OS_File 2.
 */

extern void	Desk_File_SetExec( const char *filename, int exec);
/*
Sets execute address of the specified file.

Assembler veneer onto Desk_OS_File 3.
 */

extern void	Desk_File_CreateDirectory( const char *dirname);
/*
Creates the specified directory.

Assembler veneer onto Desk_OS_File 8.
 */



extern int Desk_File_GetType( const char *filename);
/*
Inputs:   filename - name of the file to be examined.
Returns:  Filetype of the named file.
Purpose:  Obtain the filetype of the specified file.
*/

/*
#define Desk_File_GetLength(filename, Desk_size_ptr) \
  Desk_SWI2(2, 5, Desk_SWI_OS_File, 5, (filename), NULL, NULL, NULL, NULL, (Desk_size_ptr))
*/
int	Desk_File_GetLength( const char* filename);
/*
Inputs:   filename - name of the file to be examined.
Returns:  Size of file.
Purpose:  Obtain the size (in bytes) of the named file.
*/


extern Desk_bool Desk_File_IsDirectory( const char *pathname);
/*
Inputs:   pathname - name of object to check
Returns:  Desk_bool_TRUE if the named object is a directory, Desk_bool_FALSE if not, or an
      	  error occured.
Purpose:  Determine if a filing system object is a directory.
*/


/*
 * Macro to extract the filetype from the values returned from RISC OS
 * routines.
 */


extern void	Desk_File_LoadTo( const char *filename, void *address, int *size );
/*
Inputs:   filename - Filename of file to be loaded
          address  - Address at which the file is to be loaded
          size     - NULL, or place to recieve the size of the file on exit
Outputs:  size, if non-NULL, will contain the file size on exit
Returns:  NULL, or an error
Purpose:  Loads the given file at the given address. Be very careful
          to ensure that there is enough safe memory at this address
          to accomodate the file.
*/


extern void Desk_File_Date( const char *filename, char *fivebytedate);
/*
Inputs:   filename     - Filename of file to be loaded
Outputs:  fivebytedata - will contain the date stamp
Returns:  -
Purpose:  Reads the datestamp of a file into a five byte block
*/



extern char*	Desk_File_AllocLoad( const char* filename, int* lengthptr);
/*
This allocates space for the file, and loads it. The length of the file
is put into 'lengthptr', if it isn't NULL.

Returns a pointer to the loaded file, or NULL if an error occurred.
*/



extern char*	Desk_File_AllocLoad0( const char *filename);
/*
This allocates space for the file, loads it, and appends a '\0'. The
intention is to allow text-files to be loaded and dealt with as strings.

Returns a pointer to the loaded file, or NULL if an error occurred.
*/


extern int Desk_File_printf(Desk_file_handle file, const char *format, ...);
/*
Inputs:   file   - output stream
          format - a printf style format string
          ...    - extra parameters as described in the format string
Outputs:  -
Returns:  The number of characters written (-ve for error)
Purpose:  Equivalent of fprintf(), but uses RISC OS file handles instead
          of FILE pointer to reference the file.
Notes:    This uses a 512 character buffer to compose the string to be
          output; if your string overflows this, your program will crash.
*/


extern int Desk_File_ReadExtent(Desk_file_handle handle);
/*
Returns the current file extent (or -1 if an error occurrs)
*/





void	Desk_File_SaveMemory2( const char* filename, void* buffer, int size, int filetype);
/*
Saves memory to a filename, with a filetype.
Treat like:
void	Desk_File_SaveMemory( char *filename, void *buffer, Desk_size_t size, int filetype);
 */



#define Desk_File_SaveMemory( filename, buffer, size)	Desk_File_SaveMemory2( filename, buffer, size, 0xfff)
/*
Saves memory to a filename.
Treat like:
void	Desk_File_SaveMemory( char *filename, void *buffer, size_t size);
 */


void	Desk_File_EnsureDirectory( const char* path);
/*
Ensures that the specified directory exists - any required parent
directories are also created.
 */


void	Desk_File_EnsureParentDirectory( const char* filename);
/*
Uses Desk_File_EnsureDirectory to ensure that the parent of 'filename'
exists.
 */





#define Desk_FILETYPE(x) (((x) & 0xFFF00) >> 8)


/*
 * #defines for some common filetypes.
 */

#define Desk_filetype_AIM  	    0x004
#define Desk_filetype_CLEAR 	    0x690
#define Desk_filetype_DEGAS 	    0x691
#define Desk_filetype_IMG  	    0x692
#define Desk_filetype_AMIGAIFF   0x693
#define Desk_filetype_MACPAINT   0x694
#define Desk_filetype_GIF  	    0x695
#define Desk_filetype_PCX  	    0x697
#define Desk_filetype_QRT  	    0x698
#define Desk_filetype_MTV  	    0x699
#define Desk_filetype_CADSOFT    0x69A
#define Desk_filetype_IRLAM 	    0x69B
#define Desk_filetype_BMP  	    0x69C
#define Desk_filetype_TARGA 	    0x69D
#define Desk_filetype_PBMPlus    0x69E
#define Desk_filetype_ZVDA 	    0x69F
#define Desk_filetype_MSX2       0x6A0
#define Desk_filetype_RLE        0x6A1
#define Desk_filetype_COLORIX    0x6A2
#define Desk_filetype_FITS       0x6A3
#define Desk_filetype_HAWKV9     0x6A4
#define Desk_filetype_REPLAY     0xAE7
#define Desk_filetype_ALARMS     0xAE9
#define Desk_filetype_DRAWFILE   0xAFF
#define Desk_filetype_BBCROM     0xBBC
#define Desk_filetype_AUDIOWRK   0xBD6
#define Desk_filetype_RENDPIC    0xD58
#define Desk_filetype_ARCHIVE    0xDDC
#define Desk_filetype_PROART     0xDE2
#define Desk_filetype_PICTURE    0xDFA
#define Desk_filetype_PRNTDEFN   0xFC6
#define Desk_filetype_DOSDISC    0xFC8
#define Desk_filetype_SUNRASTR   0xFC9
#define Desk_filetype_DEVICE     0xFCC
#define Desk_filetype_CACHE      0xFCF
#define Desk_filetype_PCEMCONF   0xFD0
#define Desk_filetype_DEBIMAGE   0xFD3
#define Desk_filetype_TASKEXEC   0xFD6
#define Desk_filetype_TASKOBEY   0xFD7
#define Desk_filetype_MAKEFILE   0xFE1
#define Desk_filetype_DOS  	    0xFE4
#define Desk_filetype_DESKTOP    0xFEA
#define Desk_filetype_OBEY 	    0xFEB
#define Desk_filetype_TEMPLATE   0xFEC
#define Desk_filetype_PALETTE    0xFED
#define Desk_filetype_TIFF 	    0xFF0
#define Desk_filetype_CONFIG     0xFF2
#define Desk_filetype_PRINTOUT   0xFF4
#define Desk_filetype_POSCRIPT   0xFF5
#define Desk_filetype_FONT 	    0xFF6
#define Desk_filetype_BBCFONT    0xFF7
#define Desk_filetype_ABSOLUTE   0xFF8
#define Desk_filetype_SPRITE     0xFF9
#define Desk_filetype_MODULE     0xFFA
#define Desk_filetype_BASIC 	    0xFFB
#define Desk_filetype_UTILITY    0xFFC
#define Desk_filetype_DATA 	    0xFFD
#define Desk_filetype_COMMAND    0xFFE
#define Desk_filetype_TEXT 	    0xFFF
#define Desk_filetype_HTML	0xFAF



#ifdef __cplusplus
}
#endif

#endif
