/*
    ####             #    #     # #
    #   #            #    #       #          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.04 (31 Aug 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:    22 Jul 1995 - JS - Added File_AllocLoad0().
             01 Aug 1995 - Sergio Monesi - Added File_ReadExtent()
    
    Mods:    31 Aug 1995 - JH - a few new filetypes.
*/


#ifndef __dl_file_h
#define __dl_file_h

#ifdef __cplusplus
extern "C" {
#endif

#ifndef __dl_core_h
#include "Core.h"
#endif

#ifndef __dl_swi_h
#include "SWI.h"
#endif


extern os_error *file_lasterror;
/*
 *  IMPORTANT NOTE
 *  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, 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 os_error block.
 *
 *  If no error occurred on the last file op, 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 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 os_error pointer directly
 *  as well as setting file_lasterror, for convenience.
 */


extern os_error *File_Delete(char *filename);
/*
 *  Attempts to delete the named file. Use carefully!
 */


extern int File_Size(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 BOOL File_Exists(char *filename);
/*
 *  This returns TRUE if the file exists.
 *  (It attempts to open the file for reading - it returns TRUE if successful)
 */



typedef int file_position;
typedef int file_handle;

#define file_READERROR (-1)


typedef enum
{
  file_READ   = 0x40,          /* Open the file for reading                 */
  file_WRITE  = 0x80,          /* CREATE/WIPE the file, open it for writing */
  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
                                */
} file_access;
/*
 *  These are used when opening files. NOTE that they correspond directly
 *  to OS_File opening flags (OS_File register 0 entry value)
 */


extern file_handle File_Open(char *filename, file_access access);
/*
 *  Opens the given file for reading or writing (see file_access's above)
 *  Returns the file handle, or NULL if it failed
 *  (if NULL, you can check 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. File_Open
 *  returns NULL, but file_lasterror is ALSO NULL). You must therefore
 *  check file_lasterror before blindly trying to use it to report an error.
 */


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


extern BOOL File_EOF(file_handle handle);
/*
 *  Returns TRUE if the end of the file has been reached
 */


extern os_error *File_Seek(file_handle handle, 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 file_position File_ReturnPos(file_handle handle);
/*
 *  Returns the current file pointer position.
 *  This is a value which, when passed to File_Seek, will return you to the
 *  same position you were at when you called File_ReturnPos
 */


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


extern os_error *File_WriteBytes(file_handle handle,
                                 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 File_ReadBytes(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 os_error *File_Write8(file_handle handle, int byte);
/*
 *  Writes an 8-bit value (a byte/char) to the given output file.
 */

#define File_WriteByte File_Write8
#define File_WriteChar File_Write8


extern int File_Read8(file_handle handle);
 /*
  *  Reads an 8-bit value (a byte/char) from the given input file.
  *  If an error (typically EOF) occurs during the read, file_READERROR
  *  will be returned.
  *
  *  VERY IMPORTANT NOTE!
  *  DO NOT use File_Read8() in a line like the following:
  *    shortvalue = File_Read8(infile) | (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 = File_Read8(infile);
  *    shortvalue |= File_Read8(infile) << 8;
  */

#define File_ReadByte File_Read8
#define File_ReadChar File_Read8


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

#define File_WriteWord File_Write32
#define File_WriteInt  File_Write32
#define File_WriteLong File_Write32


extern int File_Read32(file_handle handle);
 /*
  *  Reads a 32-bit value (a word/int/long) from the given input file.
  *  If an error (typically EOF) occurs during the read, file_READERROR
  *  will be returned. (Note that this is a perfectly legal value to read
  *  from the file, though, so you should check file_lasterror to see if
  *  an error occurred).
  */

#define File_ReadWord File_Read32
#define File_ReadInt  File_Read32
#define File_ReadLong File_Read32


extern int File_Read32R(file_handle handle);
 /*
  *  Identical to 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 File_ReadWordR File_Read32R
#define File_ReadIntR  File_Read32R
#define File_ReadLongR File_Read32R


extern os_error *File_Write32R(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 File_WriteWordR File_Write32R
#define File_WriteIntR  File_Write32R
#define File_WriteLongR File_Write32R


extern void File_SetType(char *filename, int type);
/*
void File_SetType(char *filename, int type)

Inputs:   filename - name of file to change the type of.
      	  type     - the number of the filetype to set.
Returns:  -
Purpose:  Change the filetype of a named file.
      	  This is actually a macro veneer to a standard RISC OS SWI
      	  service (OS_File).
*/


extern int File_GetType(char *filename);
/*
Inputs:   filename - name of the file to be examined.
Returns:  Filetype of the named file, or -1 if an error occured.
Purpose:  Obtain the filetype of the specified file.
*/


#define File_GetLength(filename, size_ptr) \
  SWI(2, 5, SWI_OS_File, 5, (filename), NULL, NULL, NULL, NULL, (size_ptr))
/*
Treat like: os_error *File_GetLength(char *filename, int *size_ptr)

Inputs:   filename - name of the file to be examined.
Outputs:  size_ptr - pointer to an integer variable to hold the file
      	      	      	 size.
Returns:  Standard error block.
Purpose:  Obtain the size (in bytes) of the named file.
      	  This is actually a macro veneer to a standard RISC OS SWI
      	  service (OS_File).
*/


extern BOOL File_IsDirectory(char *pathname);
/*
Inputs:   pathname - name of object to check
Returns:  TRUE if the named object is a directory, 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 os_error *File_LoadTo(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 File_Date(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 *File_AllocLoad0( 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 File_printf(file_handle file, 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 File_ReadExtent(file_handle handle);
/*
Returns the current file extent (or -1 if an error occurrs)
*/



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


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

#define filetype_AIM  	    0x004
#define filetype_CLEAR 	    0x690
#define filetype_DEGAS 	    0x691
#define filetype_IMG  	    0x692
#define filetype_AMIGAIFF   0x693
#define filetype_MACPAINT   0x694
#define filetype_GIF  	    0x695
#define filetype_PCX  	    0x697
#define filetype_QRT  	    0x698
#define filetype_MTV  	    0x699
#define filetype_CADSOFT    0x69A
#define filetype_IRLAM 	    0x69B
#define filetype_BMP  	    0x69C
#define filetype_TARGA 	    0x69D
#define filetype_PBMPlus    0x69E
#define filetype_ZVDA 	    0x69F
#define filetype_MSX2       0x6A0
#define filetype_RLE        0x6A1
#define filetype_COLORIX    0x6A2
#define filetype_FITS       0x6A3
#define filetype_HAWKV9     0x6A4
#define filetype_REPLAY     0xAE7
#define filetype_ALARMS     0xAE9
#define filetype_DRAWFILE   0xAFF
#define filetype_BBCROM     0xBBC
#define filetype_AUDIOWRK   0xBD6
#define filetype_RENDPIC    0xD58
#define filetype_ARCHIVE    0xDDC
#define filetype_PROART     0xDE2
#define filetype_PICTURE    0xDFA
#define filetype_PRNTDEFN   0xFC6
#define filetype_DOSDISC    0xFC8
#define filetype_SUNRASTR   0xFC9
#define filetype_DEVICE     0xFCC
#define filetype_CACHE      0xFCF
#define filetype_PCEMCONF   0xFD0
#define filetype_DEBIMAGE   0xFD3
#define filetype_TASKEXEC   0xFD6
#define filetype_TASKOBEY   0xFD7
#define filetype_MAKEFILE   0xFE1
#define filetype_DOS  	    0xFE4
#define filetype_DESKTOP    0xFEA
#define filetype_OBEY 	    0xFEB
#define filetype_TEMPLATE   0xFEC
#define filetype_PALETTE    0xFED
#define filetype_TIFF 	    0xFF0
#define filetype_CONFIG     0xFF2
#define filetype_PRINTOUT   0xFF4
#define filetype_POSCRIPT   0xFF5
#define filetype_FONT 	    0xFF6
#define filetype_BBCFONT    0xFF7
#define filetype_ABSOLUTE   0xFF8
#define filetype_SPRITE     0xFF9
#define filetype_MODULE     0xFFA
#define filetype_BASIC 	    0xFFB
#define filetype_UTILITY    0xFFC
#define filetype_DATA 	    0xFFD
#define filetype_COMMAND    0xFFE
#define filetype_TEXT 	    0xFFF

#ifdef __cplusplus
}
#endif

#endif
