(*---------------------------------------------------------------------------
 :Program.      PPData.mod
 :Author.       Nico François / Fridtjof Siebert
 :Address.      Nobileweg 67, D-7000 Stuttgart 40
 :Shortcut.     [fbs]
 :Copyright.    FD
 :Language.     OBERON
 :Translator.   Amiga Oberon Compiler
 :History.      V1.1 08-Jun-90: Ported Nico's C-Code to Oberon [fbs]
 :Imports.      DecrunchBuffer from PPData.asm
 :Contents.     Procedure to decrompess PowerPacker-Files
---------------------------------------------------------------------------*)
(********************************************************************
*                                                                   *
*  'PP_LoadData' PowerPacker DATA file support function V1.1        *
*                                                                   *
*  You may use this code for non-commercial purposes provided this  *
*  copyright notice is left intact !                                *
*                                                                   *
*                          Copyright (c) Aug 1989 by Nico François  *
********************************************************************)

MODULE PPData;

IMPORT      Exec,
            Dos,
       ol:  OberonLib,
       sys: SYSTEM;

CONST
(* error codes *)
  LOADOK   * =    0;
  LOCKERR  * = 1000;
  OPENERR  * = 1001;
  READERR  * = 1002;
  NOMEMORY * = 1003;
  CRYPTED  * = 1004;
  PASSERR  * = 1005;

  SAFETYMARGIN = 64;

VAR
  FileInfoBlock: Dos.FileInfoBlockPtr;

PROCEDURE LoadData*(    file: ARRAY OF CHAR;
                    VAR buffer: Exec.ADDRESS;
                    VAR length: LONGINT): INTEGER;
(* :Input. file:   File that is to be decruched                                   *)
(* :Output. buffer: memory allocated by this procedure to contain decrunched file *)
(* :Output.         use DIPOSE(buffer) to free its memory                         *)
(* :Output. length: length of File                                                *)
(* :Result. one of the errorcodes above                                           *)
(* :Semantic. Loads and decrunches file                                           *)

VAR
  handle: Dos.FileHandlePtr;
  lock: Dos.FileLockPtr;
  filestart,ptr: POINTER TO BYTE;
  bufferlen: LONGINT;

  hdr: LONGINT;
  filelen,crunlen,efficiency: LONGINT;
  crunched: BOOLEAN;
  result: INTEGER;

CONST
  PX20 = sys.VAL(LONGINT,'PX20');
  PP11 = sys.VAL(LONGINT,'PP11');
  PP20 = sys.VAL(LONGINT,'PP20');


  PROCEDURE myRead(VAR t: ARRAY OF BYTE): BOOLEAN;
  BEGIN
    RETURN Dos.Read(handle,t,LEN(t))#LEN(t);
  END myRead;


  PROCEDURE DecrunchBuffer{"_pp_DecrunchBuffer"}(
                                 endcrun{8}: Exec.ADDRESS;
                                 buffer{9}: Exec.ADDRESS;
                                 efficiency{0}: LONGINT);

BEGIN

  lock := Dos.Lock(file,Dos.accessRead);
  IF lock=NIL THEN RETURN LOCKERR END;
  IF Dos.Examine(lock,FileInfoBlock) THEN END;
  Dos.UnLock(lock);
  crunlen := FileInfoBlock.size;

  handle := Dos.Open(file,Dos.oldFile);

  IF handle=NIL THEN RETURN OPENERR END;

  result := LOADOK;

  LOOP

    IF myRead(hdr) THEN EXIT END;

    IF (crunlen>16) AND ((hdr=PX20) OR (hdr=PP11) OR (hdr=PP20)) THEN
      IF hdr=PX20 THEN Dos.Close(handle); RETURN CRYPTED END;
      IF Dos.Seek(handle,crunlen-4,Dos.beginning)=0 THEN END;
      IF myRead(filelen) THEN EXIT END;
      filelen := filelen DIV 256;
      DEC(crunlen,8);
      IF Dos.Seek(handle,4,Dos.beginning)=0 THEN END;
      IF myRead(efficiency) THEN EXIT END;
      bufferlen := filelen + SAFETYMARGIN;
      crunched := TRUE;
    ELSE
      IF Dos.Seek(handle,0,Dos.beginning)=0 THEN END;
      bufferlen := crunlen;
      filelen := crunlen;
      crunched := FALSE;
    END;
    ol.New(filestart,bufferlen);
    IF filestart=NIL THEN Dos.Close(handle); RETURN NOMEMORY END;
    IF Dos.Read (handle,filestart^,crunlen) # crunlen THEN
      DISPOSE(filestart);
      EXIT
    END;

    IF crunched THEN
      DecrunchBuffer(sys.VAL(LONGINT,filestart)+crunlen,
                     sys.VAL(LONGINT,filestart)+SAFETYMARGIN,efficiency);
      ptr := sys.VAL(LONGINT,filestart)+SAFETYMARGIN;
      Exec.CopyMem(ptr^,filestart^,filelen);
    END;

    buffer := filestart;
    length := filelen;

    Dos.Close(handle);

    RETURN LOADOK;

  END;  (* LOOP *)

  Dos.Close(handle);

  RETURN READERR;

END LoadData;

BEGIN
  NEW(FileInfoBlock); IF FileInfoBlock=NIL THEN HALT(20) END;
END PPData.
