(**************************************************************************

     $RCSfile: IFFParse.mod $
  Description: Interface to iffparse.library

   Created by: fjc (Frank Copeland)
    $Revision: 3.2 $
      $Author: fjc $
        $Date: 1994/08/08 00:56:10 $

  Includes Release 40.15

  (C) Copyright 1985-1993 Commodore-Amiga, Inc.
      All Rights Reserved

  Oberon-A interface Copyright © 1994, Frank Copeland.
  This file is part of the Oberon-A Interface.
  See Oberon-A.doc for conditions of use and distribution.

***************************************************************************)

MODULE IFFParse;

(*
** $C- CaseChk       $I- IndexChk  $L+ LongAdr   $N- NilChk
** $P- PortableCode  $R- RangeChk  $S- StackChk  $T- TypeChk
** $V- OvflChk       $Z- ZeroVars
*)

IMPORT E := Exec, C := Clipboard, U := Utility, SYS := SYSTEM;

(*
**      $VER: iffparse.h 39.1 (1.6.92)
**
**      iffparse.library structures and constants
*)


TYPE

(* Structure associated with an active IFF stream.
 * "stream" is a value used by the client's read/write/seek functions -
 * it will not be accessed by the library itself and can have any value
 * (could even be a pointer or a BPTR).
 *
 * This structure can only be allocated by iffparse.library
 *)
  IFFHandlePtr * = CPOINTER TO IFFHandle;
  IFFHandle * = RECORD
    stream * : E.ULONG;
    flags *  : SET;
    depth *  : LONGINT;      (*  Depth of context stack.  *)
  END; (* IFFHandle *)

(*
 * Bit masks for "IFFHandle.flags" field.
 *)

CONST

  read *       = {};                     (* read mode - default *)
  write *      = {0};                    (* write mode *)
  rwBits *     = read + write;           (* read/write bits *)
  fSeek *      = {1};                    (* forward seek only *)
  rSeek *      = {2};                    (* random seek *)
  reserved *   = {16 .. 31};             (* Don't touch these bits. *)

(*****************************************************************************)

(*
 * When the library calls your stream handler, you'll be passed a pointer
 * to this structure as the "message packet".
 *)

TYPE

  IFFStreamCmdPtr * = CPOINTER TO IFFStreamCmd;
  IFFStreamCmd * = RECORD
    command * : LONGINT;     (*  Operation to be performed (cmd...) *)
    buf *     : E.APTR;      (*  Pointer to data buffer              *)
    nBytes *  : LONGINT;     (*  Number of bytes to be affected      *)
  END; (* IFFStreamCmd *)

(*****************************************************************************)

(*
 * A node associated with a context on the iffStack.  Each node
 * represents a chunk, the stack representing the current nesting
 * of chunks in the open IFF file.  Each context node has associated
 * local context items in the (private) LocalItems list.  The ID, type,
 * size and scan values describe the chunk associated with this node.
 *
 * This structure can only be allocated by iffparse.library
 *)

TYPE

  ContextNodePtr * = CPOINTER TO ContextNode;
  ContextNode * = RECORD (E.MinNode)
    id *   : LONGINT;
    type * : LONGINT;
    size * : LONGINT;        (*  Size of this chunk             *)
    scan * : LONGINT;        (*  # of bytes read/written so far *)
  END; (* ContextNode *)

(*****************************************************************************)

(*
 * Local context items live in the ContextNode's.  Each class is identified
 * by its lciIdent code and has a (private) purge vector for when the
 * parent context node is popped.
 *
 * This structure can only be allocated by iffparse.library
 *)

TYPE

  LocalContextItemPtr * = CPOINTER TO LocalContextItem;
  LocalContextItem * = RECORD (E.MinNode)
    id *    : E.ULONG;
    type *  : E.ULONG;
    ident * : E.ULONG;
  END; (* LocalContextItem *)

(*****************************************************************************)

(*
 * StoredProperty: a local context item containing the data stored
 * from a previously encountered property chunk.
 *)

TYPE

  StoredPropertyPtr * = CPOINTER TO StoredProperty;
  StoredProperty * = RECORD
    size * : LONGINT;
    data * : E.APTR;
  END; (* StoredProperty *)

(*****************************************************************************)

(*
 * Collection Item: the actual node in the collection list at which
 * client will look.  The next pointers cross context boundaries so
 * that the complete list is accessable.
 *)

TYPE

  CollectionItemPtr * = CPOINTER TO CollectionItem;
  CollectionItem * = RECORD
    next * : CollectionItemPtr;
    size * : LONGINT;
    data * : E.APTR;
  END; (* CollectionItem *)

(*****************************************************************************)

(*
 * Structure returned by OpenClipboard().  You may do cmdPosts and such
 * using this structure.  However, once you call OpenIFF(), you may not
 * do any more of your own I/O to the clipboard until you call CloseIFF().
 *)

TYPE

  ClipboardHandlePtr * = CPOINTER TO ClipboardHandle;
  ClipboardHandle * = RECORD (C.IOClipReq)
    cbport *      : E.MsgPort;
    satisfyPort * : E.MsgPort;
  END; (* ClipboardHandle *)

(*****************************************************************************)

(*
 * IFF return codes.  Most functions return either zero for success or
 * one of these codes.  The exceptions are the read/write functions which
 * return positive values for number of bytes or records read or written,
 * or a negative error code.  Some of these codes are not errors per sae,
 * but valid conditions such as EOF or EOC (End of Chunk).
 *)

CONST

  errEOF *              = -1;     (*  Reached logical end of file *)
  errEOC *              = -2;     (*  About to leave context      *)
  errNoScope *          = -3;     (*  No valid scope for property *)
  errNoMem *            = -4;     (*  Internal memory alloc failed*)
  errRead *             = -5;     (*  Stream read error           *)
  errWrite *            = -6;     (*  Stream write error          *)
  errSeek *             = -7;     (*  Stream seek error           *)
  errMangled *          = -8;     (*  Data in file is corrupt     *)
  errSyntax *           = -9;     (*  IFF syntax error            *)
  errNotIFF *           = -10;    (*  Not an IFF file             *)
  errNoHook *           = -11;    (*  No call-back hook provided  *)
  return2Client *       = -12;    (*  Client handler normal return*)

(*****************************************************************************)

(*
 * Universal IFF identifiers.
 *)

CONST

  idForm *   = 0464F524DH;  (* MakeID('F','O','R','M') *)
  idList *   = 04C495354H;  (* MakeID('L','I','S','T') *)
  idCat *    = 043415420H;  (* MakeID('C','A','T',' ') *)
  idProp *   = 050524F50H;  (* MakeID('P','R','O','P') *)
  idNull *   = 020202020H;  (* MakeID(' ',' ',' ',' ') *)

(*
 * Identifier codes for universally recognized local context items.
 *)

CONST

  lciProp *         = 070726F70H;  (* MakeID('p','r','o','p') *)
  lciCollection *   = 0636F6C6CH;  (* MakeID('c','o','l','l') *)
  lciEntryHandler * = 0656E6864H;  (* MakeID('e','n','h','d') *)
  lciExitHandler *  = 065786864H;  (* MakeID('e','x','h','d') *)

(*****************************************************************************)

(*
 * Control modes for ParseIFF() function.
 *)

CONST

  parseScan *           = 0;
  parseStep *           = 1;
  parseRawStep *        = 2;

(*****************************************************************************)

(*
 * Control modes for StoreLocalItem().
 *)

CONST

  sliRoot *             = 1;      (*  Store in default context       *)
  sliTop *              = 2;      (*  Store in current context       *)
  sliProp *             = 3;      (*  Store in topmost FORM or LIST  *)

(*****************************************************************************)

(* Magic value for writing functions. If you pass this value in as a size
 * to PushChunk() when writing a file, the parser will figure out the
 * size of the chunk for you. If you know the size, is it better to
 * provide as it makes things faster.
 *)

  sizeUnknown *         = -1;

(*****************************************************************************)

(*
 * Possible call-back command values.  (Using 0 as the value for iffCmdInit
 * was, in retrospect, probably a bad idea.)
 *)

CONST

  cmdInit *     = 0;       (*  Prepare the stream for a session    *)
  cmdCleanup *  = 1;       (*  Terminate stream session            *)
  cmdRead *     = 2;       (*  Read bytes from stream              *)
  cmdWrite *    = 3;       (*  Write bytes to stream               *)
  cmdSeek *     = 4;       (*  Seek on stream                      *)
  cmdEntry *    = 5;       (*  You just entered a new context      *)
  cmdExit *     = 6;       (*  You're about to leave a context     *)
  cmdPurgeLCI * = 7;       (*  Purge a LocalContextItem            *)

(*****************************************************************************)

(* Obsolete IFFParse definitions, here for source code compatibility only.
 * Please do NOT use in new code.
 *)
CONST

  sccInit *     = cmdInit;
  sccCleanup *  = cmdCleanup;
  sccRead *     = cmdRead;
  sccWrite *    = cmdWrite;
  sccSeek *     = cmdSeek;


(*-- Library Base variable --------------------------------------------*)

TYPE

  IffParseBasePtr * = CPOINTER TO IffParseBase;
  IffParseBase * = RECORD (E.Library) END;

CONST

  Name * = "iffparse.library";
  iffparseName * = Name;

VAR

  base * : IffParseBasePtr;


(*-- Library Functions ------------------------------------------------*)

(*
**      $VER: iffparse_protos.h 39.1 (1.6.92)
*)

(*--- functions in V36 or higher (Release 2.0) ---*)

(* ------ Basic functions ------*)

LIBCALL (base : IffParseBasePtr) AllocIFF* ()
  : IFFHandlePtr;
  -30;
LIBCALL (base : IffParseBasePtr) OpenIFF*
  ( iff    [8] : IFFHandlePtr;
    rwMode [0] : SET )
  : LONGINT;
  -36;
LIBCALL (base : IffParseBasePtr) ParseIFF*
  ( iff     [8] : IFFHandlePtr;
    control [0] : LONGINT )
  : LONGINT;
  -42;
LIBCALL (base : IffParseBasePtr) CloseIFF*
  ( iff [8] : IFFHandlePtr );
  -48;
LIBCALL (base : IffParseBasePtr) FreeIFF*
  ( iff [8] : IFFHandlePtr );
  -54;

(* ------ Read/Write functions ------*)

LIBCALL (base : IffParseBasePtr) ReadChunkBytes*
  ( iff      [8] : IFFHandlePtr;
    VAR buf  [9] : ARRAY OF SYS.BYTE;
    size     [0] : LONGINT )
  : LONGINT;
  -60;
LIBCALL (base : IffParseBasePtr) WriteChunkBytes*
  ( iff  [8] : IFFHandlePtr;
    buf  [9] : ARRAY OF SYS.BYTE;
    size [0] : LONGINT )
  : LONGINT;
  -66;
LIBCALL (base : IffParseBasePtr) ReadChunkRecords*
  ( iff            [8] : IFFHandlePtr;
    VAR buf        [9] : ARRAY OF SYS.BYTE;
    bytesPerRecord [0] : LONGINT;
    nRecords       [1] : LONGINT )
  : LONGINT;
  -72;
LIBCALL (base : IffParseBasePtr) WriteChunkRecords*
  ( iff            [8] : IFFHandlePtr;
    buf            [9] : ARRAY OF SYS.BYTE;
    bytesPerRecord [0] : LONGINT;
    nRecords       [1] : LONGINT )
  : LONGINT;
  -78;

(* ------ Context entry/exit ------*)

LIBCALL (base : IffParseBasePtr) PushChunk*
  ( iff  [8] : IFFHandlePtr;
    type [0] : LONGINT;
    id   [1] : LONGINT;
    size [2] : LONGINT )
  : LONGINT;
  -84;
LIBCALL (base : IffParseBasePtr) PopChunk*
  ( iff [8] : IFFHandlePtr )
  : LONGINT;
  -90;

(* ------ Low-level handler installation ------*)

LIBCALL (base : IffParseBasePtr) EntryHandler*
  ( iff      [8] : IFFHandlePtr;
    type     [0] : LONGINT;
    id       [1] : LONGINT;
    position [2] : LONGINT;
    handler  [9] : U.HookPtr;
    object  [10] : E.APTR )
  : LONGINT;
  -102;
LIBCALL (base : IffParseBasePtr) ExitHandler*
  ( iff      [8] : IFFHandlePtr;
    type     [0] : LONGINT;
    id       [1] : LONGINT;
    position [2] : LONGINT;
    handler  [9] : U.HookPtr;
    object  [10] : E.APTR )
  : LONGINT;
  -108;

(* ------ Built-in chunk/property handlers ------*)

LIBCALL (base : IffParseBasePtr) PropChunk*
  ( iff  [8] : IFFHandlePtr;
    type [0] : LONGINT;
    id   [1] : LONGINT )
  : LONGINT;
  -114;
LIBCALL (base : IffParseBasePtr) PropChunks*
  ( iff       [8] : IFFHandlePtr;
    propArray [9] : ARRAY OF LONGINT;
    nProps    [0] : LONGINT )
  : LONGINT;
  -120;
LIBCALL (base : IffParseBasePtr) StopChunk*
  ( iff  [8] : IFFHandlePtr;
    type [0] : LONGINT;
    id   [1] : LONGINT )
  : LONGINT;
  -126;
LIBCALL (base : IffParseBasePtr) StopChunks*
  ( iff       [8] : IFFHandlePtr;
    propArray [9] : ARRAY OF LONGINT;
    nProps    [0] : LONGINT )
  : LONGINT;
  -132;
LIBCALL (base : IffParseBasePtr) CollectionChunk*
  ( iff  [8] : IFFHandlePtr;
    type [0] : LONGINT;
    id   [1] : LONGINT )
  : LONGINT;
  -138;
LIBCALL (base : IffParseBasePtr) CollectionChunks*
  ( iff       [8] : IFFHandlePtr;
    propArray [9] : ARRAY OF LONGINT;
    nProps    [0] : LONGINT )
  : LONGINT;
  -144;
LIBCALL (base : IffParseBasePtr) StopOnExit*
  ( iff  [8] : IFFHandlePtr;
    type [0] : LONGINT;
    id   [1] : LONGINT )
  : LONGINT;
  -150;

(* ------ Context utilities ------*)

LIBCALL (base : IffParseBasePtr) FindProp*
  ( iff  [8] : IFFHandlePtr;
    type [0] : LONGINT;
    id   [1] : LONGINT )
  : StoredPropertyPtr;
  -156;
LIBCALL (base : IffParseBasePtr) FindCollection*
  ( iff  [8] : IFFHandlePtr;
    type [0] : LONGINT;
    id   [1] : LONGINT )
  : CollectionItemPtr;
  -162;
LIBCALL (base : IffParseBasePtr) FindPropContext*
  ( iff [8] : IFFHandlePtr )
  : ContextNodePtr;
  -168;
LIBCALL (base : IffParseBasePtr) CurrentChunk*
  ( iff [8] : IFFHandlePtr )
  : ContextNodePtr;
  -174;
LIBCALL (base : IffParseBasePtr) ParentChunk*
  ( contextNode [8] : ContextNodePtr )
  : ContextNodePtr;
  -180;

(* ------ LocalContextItem support functions ------*)

LIBCALL (base : IffParseBasePtr) AllocLocalItem*
  ( type     [0] : LONGINT;
    id       [1] : LONGINT;
    ident    [2] : LONGINT;
    dataSize [3] : LONGINT )
  : LocalContextItemPtr;
  -186;
LIBCALL (base : IffParseBasePtr) LocalItemData*
  ( localItem [8] : LocalContextItemPtr )
  : E.APTR;
  -192;
LIBCALL (base : IffParseBasePtr) SetLocalItemPurge*
  ( localItem [8] : LocalContextItemPtr;
    purgeHook [9] : U.HookPtr );
  -198;
LIBCALL (base : IffParseBasePtr) FreeLocalItem*
  ( localItem [8] : LocalContextItemPtr );
  -204;
LIBCALL (base : IffParseBasePtr) FindLocalItem*
  ( iff   [8] : IFFHandlePtr;
    type  [0] : LONGINT;
    id    [1] : LONGINT;
    ident [2] : LONGINT )
  : LocalContextItemPtr;
  -210;
LIBCALL (base : IffParseBasePtr) StoreLocalItem*
  ( iff       [8] : IFFHandlePtr;
    localItem [9] : LocalContextItemPtr;
    position  [0] : LONGINT )
  : LONGINT;
  -216;
LIBCALL (base : IffParseBasePtr) StoreItemInContext*
  ( iff          [8] : IFFHandlePtr;
    localItem    [9] : LocalContextItemPtr;
    contextNode [10] : ContextNodePtr );
  -222;

(* ------ IFFHandle initialization ------*)

LIBCALL (base : IffParseBasePtr) InitIFF*
  ( iff        [8] : IFFHandlePtr;
    flags      [0] : SET;
    streamHook [9] : U.HookPtr );
  -228;
LIBCALL (base : IffParseBasePtr) InitIFFasDOS*
  ( iff [8] : IFFHandlePtr );
  -234;
LIBCALL (base : IffParseBasePtr) InitIFFasClip*
  ( iff [8] : IFFHandlePtr );
  -240;

(* ------ Internal clipboard support ------*)

LIBCALL (base : IffParseBasePtr) OpenClipboard*
  ( unitNum [0] : LONGINT )
  : ClipboardHandlePtr;
  -246;
LIBCALL (base : IffParseBasePtr) CloseClipboard*
  ( clipboard [8] : ClipboardHandlePtr );
  -252;

(* ------ Miscellaneous ------*)

LIBCALL (base : IffParseBasePtr) GoodID*
  ( id [0] : LONGINT )
  : LONGINT;
  -258;
LIBCALL (base : IffParseBasePtr) GoodType*
  ( type [0] : LONGINT )
  : LONGINT;
  -264;
LIBCALL (base : IffParseBasePtr) IDtoStr*
  ( id      [0] : LONGINT;
    VAR buf [8] : ARRAY OF CHAR )
  : E.STRPTR;
  -270;


(*-- C Macros defined as procedures -----------------------------------*)
(* $L+ Absolute long addressing for globals *)


(*-----------------------------------*)
(*$D-*)
PROCEDURE MakeID (id : ARRAY OF CHAR) : LONGINT;
BEGIN (* MakeID *)
  RETURN
    ( SYS.LSH (LONG (ORD (id [0])), 24)
      + SYS.LSH (LONG (ORD (id [1])), 16)
      + SYS.LSH (LONG (ORD (id [2])), 8)
      + LONG (ORD (id [3])) )
END MakeID;
(*$D+*)


(*-- Library Base variable --------------------------------------------*)
(* $L- Address globals through A4 *)


(*-----------------------------------*)
PROCEDURE* CloseLib ();

BEGIN (* CloseLib *)
  IF base # NIL THEN E.base.CloseLibrary (base) END
END CloseLib;

(*-----------------------------------*)
PROCEDURE OpenLib * (mustOpen : BOOLEAN);

BEGIN (* OpenLib *)
  IF base = NIL THEN
    base :=
      SYS.VAL
        ( IffParseBasePtr,
          E.base.OpenLibrary (Name, E.libraryMinimum) );
    IF base # NIL THEN SYS.SETCLEANUP (CloseLib)
    ELSIF mustOpen THEN HALT (100)
    END;
  END;
END OpenLib;


BEGIN
  base := NIL
END IFFParse.
