{$MACRO ON}

(******************************************************************************
 *
 * Copyright (c) 1994-2000 Palm, Inc. or its subsidiaries.
 * All rights reserved.
 *
 * File: FileStream.h
 *
 * Release: Palm OS SDK 4.0 (63220)
 *
 * Description:
 *    Pilot File Stream equates -- File Streams were initially implemented
 *    in PalmOS v3.0 (not available in earlier versions)
 *
 * History:
 *    11/24/97 vmk      - Created by Vitaly Kruglikov
 *
 *****************************************************************************)

{$IFNDEF FPC_DOTTEDUNITS}
unit filestream;
{$ENDIF FPC_DOTTEDUNITS}

interface

{$IFDEF FPC_DOTTEDUNITS}
uses PalmApi.Palmos, PalmApi.Coretraps, PalmApi.Errorbase;
{$ELSE FPC_DOTTEDUNITS}
uses palmos, coretraps, errorbase;
{$ENDIF FPC_DOTTEDUNITS}

(************************************************************
 * File Stream error codes
 * the constant dmErrorClass is defined in ErrorBase.h
 *************************************************************)

const
  fileErrMemError            = fileErrorClass or 1;  // out of memory error
  fileErrInvalidParam        = fileErrorClass or 2;  // invalid parameter value passed
  fileErrCorruptFile         = fileErrorClass or 3;  // the file is corrupted/invalid/not a stream file
  fileErrNotFound            = fileErrorClass or 4;  // couldn't find the file
  fileErrTypeCreatorMismatch = fileErrorClass or 5;  // file's type and creator didn't match those expected
  fileErrReplaceError        = fileErrorClass or 6;  // couldn't replace an existing file
  fileErrCreateError         = fileErrorClass or 7;  // couldn't create a new file
  fileErrOpenError           = fileErrorClass or 8;  // generic open error
  fileErrInUse               = fileErrorClass or 9;  // file couldn't be opened or deleted because it is in use
  fileErrReadOnly            = fileErrorClass or 10; // couldn't open in write mode because db is read-only
  fileErrInvalidDescriptor   = fileErrorClass or 11; // invalid file descriptor (FileHandle)
  fileErrCloseError          = fileErrorClass or 12; // error closing the database
  fileErrOutOfBounds         = fileErrorClass or 13; // attempted operation went out of bounds of the file
  fileErrPermissionDenied    = fileErrorClass or 14; // couldn't write to a file open for read-only access
  fileErrIOError             = fileErrorClass or 15; // general I/O error
  fileErrEOF                 = fileErrorClass or 16; // end-of-file error
  fileErrNotStream           = fileErrorClass or 17; // attempted to open a file that is not a stream

(************************************************************
 * File Stream handle type
 *************************************************************)

type
  FileHand = MemHandle;

const
  fileNullHandle = FileHand(0);

(************************************************************
 * Mode flags passed to FileOpen
 *************************************************************)

// fileModeReadOnly, fileModeReadWrite, fileModeUpdate, and fileModeAppend are mutually exclusive - only
// pass one of them to FileOpen!
const
  fileModeReadOnly       = $80000000; // open for read access
  fileModeReadWrite      = $40000000; // create for read/write access, discarding previous if any */
  fileModeUpdate         = $20000000; // open/create for read/write, preserving previous if any
  fileModeAppend         = $10000000; // open/create for read/write, always writing at the end

  fileModeLeaveOpen      = $08000000; // leave open when app quits
  fileModeExclusive      = $04000000; // don't let anyone else open it
  fileModeAnyTypeCreator = $02000000; // if set, skip type/creator validation when
                                      // opening or replacing an existing file

  fileModeTemporary      = $01000000; // will automatically delete the file when it is closed;
                                      // if this bit is set and the file type passed to FileOpen is zero,
                                      // FileOpen will use sysFileTTemp (defined in SystemResources.h for the file
                                      // type (recommended) - this will enable automatic cleanup of undeleted
                                      // temp files following a system crash in future PalmOS versions
                                      // (post-crash cleanup will likely come after 3.0)

  fileModeDontOverwrite  = $00800000; // if set, will prevent fileModeReadWrite from discarding an existing file
                                      // with the same name; may only be specified together with fileModeReadWrite

// For debugging/validation
const
  fileModeAllFlags = fileModeReadOnly or fileModeReadWrite or fileModeUpdate or
                     fileModeAppend or fileModeLeaveOpen or fileModeExclusive or
                     fileModeAnyTypeCreator or fileModeTemporary or fileModeDontOverwrite;

(************************************************************
 * Origin passed to FileSetPos
 *************************************************************)

type
  FileOriginEnum = Enum;

const
  fileOriginBeginning  = 1;                      // from the beginning (first data byte of file)
  fileOriginCurrent = Succ(fileOriginBeginning); // from the current position
  fileOriginEnd = Succ(fileOriginCurrent);       // from the end of file (one position beyond last data byte)

(************************************************************
 * Operation passed to FileControl
 *************************************************************)

type
  FileOpEnum = Enum;

const
  fileOpNone = 0;                                        // no-op

  fileOpDestructiveReadMode = Succ(fileOpNone);          // switch to destructive read mode (there is no turning back);
                                                         // implicitly rewinds the file to the beginning;
                                                         // destructive read mode deletes file stream data blocks as
                                                         // data is being read, thus freeing up storage automatically;
                                                         // once in destructive read mode, FileWrite, FileSeek and FileTruncate
                                                         // are not allowed; stream's contents after closing (or crash)
                                                         // are undefined.
                                                         // ARGUMENTS:
                                                         //    stream = open stream handle
                                                         //    valueP = NULL
                                                         //    valueLenP = NULL
                                                         // RETURNS:
                                                         //    zero on success; fileErr... on error

  fileOpGetEOFStatus = Succ(fileOpDestructiveReadMode);  // get end-of-file status (err = fileErrEOF indicates end of file condition);
                                                         // use FileClearerr to clear this error status
                                                         // ARGUMENTS:
                                                         //    stream = open stream handle
                                                         //    valueP = NULL
                                                         //    valueLenP = NULL
                                                         // RETURNS:
                                                         //    zero if _not_ end of file; non-zero if end of file

  fileOpGetLastError = Succ(fileOpGetEOFStatus);         // get error code from last operation on file stream, and
                                                         // clear the last error code value (will not change end of file
                                                         // or I/O error status -- use FileClearerr to reset all error codes)
                                                         // ARGUMENTS:
                                                         //    stream = open stream handle
                                                         //    valueP = NULL
                                                         //    valueLenP = NULL
                                                         // RETURNS:
                                                         //    Error code from last file stream operation

  fileOpClearError = Succ(fileOpGetLastError);           // clear I/O and end of file error status, and last error
                                                         // ARGUMENTS:
                                                         //    stream = open stream handle
                                                         //    valueP = NULL
                                                         //    valueLenP = NULL
                                                         // RETURNS:
                                                         //    zero on success; fileErr... on error

  fileOpGetIOErrorStatus = Succ(fileOpClearError);       // get I/O error status (like C runtime's ferror); use FileClearerr
                                                         // to clear this error status
                                                         // ARGUMENTS:
                                                         //    stream = open stream handle
                                                         //    valueP = NULL
                                                         //    valueLenP = NULL
                                                         // RETURNS:
                                                         //    zero if _not_ I/O error; non-zero if I/O error is pending

  fileOpGetCreatedStatus = Succ(fileOpGetIOErrorStatus); // find out whether the FileOpen call caused the file to
                                                         // be created
                                                         // ARGUMENTS:
                                                         //    stream = open stream handle
                                                         //    valueP = ptr to Boolean type variable
                                                         //    valueLenP = ptr to Int32 variable set to sizeof(Boolean)
                                                         // RETURNS:
                                                         //    zero on success; fileErr... on error;
                                                         //    the Boolean variable will be set to non zero if the file was created.

  fileOpGetOpenDbRef = Succ(fileOpGetCreatedStatus);     // get the open database reference (handle) of the underlying
                                                         // database that implements the stream (NULL if none);
                                                         // this is needed for performing PalmOS-specific operations on
                                                         // the underlying database, such as changing or getting creator/type,
                                                         // version, backup/reset bits, etc.
                                                         // ARGUMENTS:
                                                         //    stream = open stream handle
                                                         //    valueP = ptr to DmOpenRef type variable
                                                         //    valueLenP = ptr to Int32 variable set to sizeof(DmOpenRef)
                                                         // RETURNS:
                                                         //    zero on success; fileErr... on error;
                                                         //    the DmOpenRef variable will be set to the file's open db reference
                                                         //    that may be passed to Data Manager calls;
                                                         // WARNING:
                                                         //    Do not make any changes to the data of the underlying database --
                                                         //    this will cause the file stream to become corrupted.

  fileOpFlush = Succ(fileOpGetOpenDbRef);                // flush any cached data to storage
                                                         // ARGUMENTS:
                                                         //    stream = open stream handle
                                                         //    valueP = NULL
                                                         //    valueLenP = NULL
                                                         // RETURNS:
                                                         //    zero on success; fileErr... on error;

  fileOpLAST = Succ(fileOpFlush);                        // ***ADD NEW OPERATIONS BEFORE THIS ENTRY***
                                                         // ***  AND ALWAYS AFTER EXISTING ENTRIES ***
                                                         // ***     FOR BACKWARD COMPATIBILITY     ***

(************************************************************
 * File Stream procedures
 *************************************************************)

// Open/create a file stream (name must all be valid -- non-null, non-empty)
// (errP is optional - set to NULL to ignore)
function FileOpen(cardNo: UInt16; const nameP: PAnsiChar; type_, creator, openMode: UInt32; var errP: Err): FileHand; syscall sysTrapFileOpen;

// Close the file stream
function FileClose(stream: FileHand): Err; syscall sysTrapFileClose;

// Delete a file
function FileDelete(cardNo: UInt16; const nameP: PAnsiChar): Err; syscall sysTrapFileDelete;

(***********************************************************************
 *
 * MACRO:      FileRead
 *
 * DESCRIPTION:   Read data from a file into a buffer.  If you need to read into a data storage
 *                heap-based chunk, record or resource, you _must_ use FileDmRead instead.
 *
 * PROTOTYPE:  Int32 FileRead(FileHand stream, void *bufP, Int32 objSize, Int32 numObj, Err *errP)
 *
 * PARAMETERS: stream      -- handle of open file
 *             bufP        -- buffer for reading data
 *             objSize     -- size of each object to read
 *             numObj      -- number of objects to read
 *             errP        -- ptr to variable for returning the error code (fileErr...)
 *                            (OPTIONAL -- pass NULL to ignore)
 *
 * RETURNED:   the number of objects that were read - this may be less than
 *             the number of objects requested
 *
 ***********************************************************************)

function FileRead(stream: FileHand; bufP: Pointer; objSize, numObj: Int32; var errP: Err): Int32;

(***********************************************************************
 *
 * MACRO:      FileDmRead
 *
 * DESCRIPTION:   Read data from a file into a data storage heap-based chunk, record
 *                or resource.
 *
 * PROTOTYPE:  Int32 FileDmRead(FileHand stream, void *startOfDmChunkP, Int32 destOffset,
 *                   Int32 objSize, Int32 numObj, Err *errP)
 *
 * PARAMETERS: stream      -- handle of open file
 *             startOfDmChunkP
 *                         -- ptr to beginning of data storage heap-based chunk, record or resource
 *             destOffset  -- offset from base ptr to the destination area (must be >= 0)
 *             objSize     -- size of each object to read
 *             numObj      -- number of objects to read
 *             errP        -- ptr to variable for returning the error code (fileErr...)
 *                            (OPTIONAL -- pass NULL to ignore)
 *
 * RETURNED:   the number of objects that were read - this may be less than
 *             the number of objects requested
 *
 ***********************************************************************)

function FileDmRead(stream: FileHand; startOfDmChunkP: Pointer; destOffset: Int32; objSize, numObj: Int32; var errP: Err): Int32;

// Low-level routine for reading data from a file stream -- use helper macros FileRead and FileDmRead
// instead of calling this function directly;
// (errP is optional - set to NULL to ignore)
function FileReadLow(stream: FileHand; baseP: Pointer; offset: Int32; dataStoreBased: Boolean;
                     objSize, numObj: Int32; var errP: Err): Int32; syscall sysTrapFileReadLow;

// Write data to a file stream
// (errP is optional - set to NULL to ignore)
function FileWrite(stream: FileHand; const dataP: Pointer; objSize, numObj: Int32; var errP: Err): Int32; syscall sysTrapFileWrite;

// Set position within a file stream
function FileSeek(stream: FileHand; offset: Int32; origin: FileOriginEnum): Err; syscall sysTrapFileSeek;

function FileRewind(stream: FileHand): Err;

// Get current position and filesize
// (fileSizeP and errP are optional - set to NULL to ignore)
function FileTell(stream: FileHand; var fileSizeP: Int32; var errP: Err): Int32; syscall sysTrapFileTell;

// Truncate a file
function FileTruncate(stream: FileHand; newSize: Int32): Err; syscall sysTrapFileTruncate;

// Returns the error code from the last operation on this file stream;
// if resetLastError is non-zero, resets the error status
// function FileControl(op: FileOpEnum; stream: FileHand; valueP: Pointer; var valueLenP: Int32): Err; syscall sysTrapFileControl;
function FileControl(op: FileOpEnum; stream: FileHand; valueP: Pointer; valueLenP: Pointer): Err; syscall sysTrapFileControl;

function FileEOF(stream: FileHand): Boolean;

function FileError(stream: FileHand): Err;

function FileClearerr(stream: FileHand): Err;

function FileGetLastError(stream: FileHand): Err;

function FileFlush(stream: FileHand): Err;

implementation

function FileRead(stream: FileHand; bufP: Pointer; objSize, numObj: Int32; var errP: Err): Int32;
begin
  FileRead := FileReadLow(stream, bufP, 0{offset}, False{dataStoreBased}, objSize, numObj, errP);
end;

function FileDmRead(stream: FileHand; startOfDmChunkP: Pointer; destOffset: Int32; objSize, numObj: Int32; var errP: Err): Int32;
begin
  FileDmRead := FileReadLow(stream, startOfDmChunkP, destOffset, True{dataStoreBased}, objSize, numObj, errP);
end;

function FileRewind(stream: FileHand): Err;
begin
  FileClearerr(stream);
  FileRewind := FileSeek(stream, 0, fileOriginBeginning);
end;

function FileEOF(stream: FileHand): Boolean;
begin
  FileEOF := FileControl(fileOpGetEOFStatus, stream, nil, nil) = fileErrEOF;
end;

function FileError(stream: FileHand): Err;
begin
  FileError := FileControl(fileOpGetIOErrorStatus, stream, nil, nil);
end;

function FileClearerr(stream: FileHand): Err;
begin
  FileClearerr := FileControl(fileOpClearError, stream, nil, nil);
end;

function FileGetLastError(stream: FileHand): Err;
begin
  FileGetLastError := FileControl(fileOpGetLastError, stream, nil, nil);
end;

function FileFlush(stream: FileHand): Err;
begin
  FileFlush := FileControl(fileOpFlush, stream, nil, nil);
end;

end.
