(*---------------------------------------------------------------------------
   :Program.    ReDump
   :Author.     Fridtjof Björn Siebert (Amok)
   :Address.    Nobileweg 67, D-7000 Stuttgart-40
   :Phone.      (0)711/822509
   :Shortcut.   [fbs]
   :Version.    .01
   :Date.       11-May-88
   :Copyright.  PD
   :Language.   Modula-II
   :Translator. M2Amiga
   :Imports.    none.
   :Contents.   Program to create a file out of a Hex-Dump.
   :Remark.     Usage: ReDump Source [TO] Dest [WIDTH xx] [ASC]
---------------------------------------------------------------------------*)

(*-------------------------------------------------------------------------*)
(*                            -----------------                            *)
(*                -   -   -   -  R E D U M P  -  -  -  -  -                *)
(*                            -----------------                            *)
(*                                                                         *)
(*  © 1988 by Fridtjof Siebert                                             *)
(*            Nobileweg 67                                                 *)
(*            7000 Stuttgart 40 (Stammheim)                                *)
(*            Germany                                                      *)
(*     Phone: (0)711/822509                                                *)
(*                                                                         *)
(*  Usage:                                                                 *)
(*    ReDump Source [TO] Dest [WIDTH xx] [ASC]                             *)
(*                                                                         *)
(*     Source: The HexDump File                                            *)
(*     Dest:   The Destination File                                        *)
(*     Width:  Number of Words per Line (default = 8)                      *)
(*     ASC:    IF ASC is selected, the ASCII-Code at the end of the Line   *)
(*             is, when it's no Point ("."), replaced by the Hex-Number,   *)
(*             it represents. So Text can be changed very easy.            *)
(*             Be careful with TYPE OPT H- HexDumps. They mustn't be Re-   *)
(*             Dumped with the ASC-Option because this Option needs to be  *)
(*             sure that there is only one Space between the last Hex-     *)
(*             Number and the ASCII-Codes !!!                              *)
(*                                                                         *)
(*-------------------------------------------------------------------------*)

MODULE ReDump;

(*------  Importlist:  ------*)

FROM SYSTEM IMPORT ADR,ADDRESS,BYTE,WORD,BITSET,SHIFT,CAST;
FROM Arts IMPORT TermProcedure,Assert;
FROM Arguments IMPORT NumArgs,GetArg;
FROM Dos IMPORT Open,Close,Read,Write,FileHandlePtr,oldFile,newFile,Output;
FROM Exec IMPORT AllocMem,FreeMem,MemReqSet,MemReqs,UByte;
FROM InOut IMPORT WriteString,WriteLn,WriteCard;
FROM Strings IMPORT first,last,Delete,Copy,Insert,Compare,Length,Occurs;
FROM Conversions IMPORT StrToVal;

(*------  Types:  ------*)

TYPE
  ArgStr  = ARRAY[0..79] OF CHAR;
  String2 = ARRAY[0..1] OF CHAR;

(*------  Variables:  ------*)

VAR
  argc: CARDINAL;                     (* count args *)
  argv: ARRAY[0..4] OF ArgStr;        (* the arguments *)
  i,ic,count: CARDINAL;               (* no special use *)
  j: INTEGER;
  InBuffer: ARRAY[0..255] OF CHAR;    (* Buffer for Input *)
  OutBuffer: POINTER TO ARRAY[0..255] OF CHAR;
  RQPos,RQLen: LONGINT;               (* for ReadQuick() *)
  RQBuffer: POINTER TO ARRAY[0..511] OF CHAR; (* ReadQuick's Buffer *)
  len: LONGCARD;                      (* for saving Writes's result *)
  InH,OutH: FileHandlePtr;            (* FileHandles for I/O *)
  Hex: ARRAY[0..39] OF CHAR;          (* for Hex-Numbers *)
  Adr,FoundAdr: CARDINAL;
  SourceFile,DestFile: ArgStr;
  WIDTH: CARDINAL;
  LIWIDTH: LONGINT;
  ASC: BOOLEAN;
  Ende: BOOLEAN;
  ok,ok2: BOOLEAN;

(*-----------------------  TermProcedure:  --------------------------------*)

PROCEDURE CleanUp();

BEGIN
(*------  Close Files:  ------*)

  Close(OutH);
  Close(InH);

(*------  Give Mem back:  ------*)

  FreeMem(RQBuffer,768);

END CleanUp;

(*-----  Read Without calling Read() all day and all of the night !  ------*)

PROCEDURE ReadQuick(To: ADDRESS; Count: CARDINAL);

VAR
  ToPtr: POINTER TO ARRAY[0..9999] OF UByte;
  i: CARDINAL;

BEGIN
  ToPtr := To;
  i := 0;
  REPEAT
    IF RQPos=RQLen THEN
      RQLen := Read(InH,RQBuffer,512);
      RQPos := 0;
    END;
    ToPtr^[i] := ORD(RQBuffer^[RQPos]);
    INC(RQPos); INC(i);
  UNTIL i=Count;
END ReadQuick;


(*------------------------  Hex To Val:  ----------------------------------*)
(*  Convert a 2-Chars Hex-Number to a CHAR                                 *)

PROCEDURE HexToVal(HexStr: ADDRESS): CHAR;

VAR
  l,h: CHAR;
  HexPtr: POINTER TO ARRAY[0..1] OF CHAR;

BEGIN
  HexPtr := HexStr;
(*------  high nibble:  ------*)
  h := HexPtr^[0];
  IF ORD(h)>96 THEN
    DEC(h,87);
  ELSIF ORD(h)>58 THEN
    DEC(h,55);
  ELSE
    DEC(h,48);
  END;
(*------  low nibble:  ------*)
  l := HexPtr^[1];
  IF ORD(l)>96 THEN
    DEC(l,87);
  ELSIF ORD(l)>58 THEN
    DEC(l,55);
  ELSE
    DEC(l,48);
  END;

  RETURN CHAR(SHIFT(ORD(h),4)+ORD(l));
END HexToVal;

(*-------------------------  Start  ---------------------------------------*)

BEGIN

(*------  Get Commandline:  ------*)

argc := NumArgs();
Assert(argc<=7,ADR("Too many parameters"));
Assert(argc>=2,ADR("Not enough parameters"));

(*------  No Parameters? Then type Usage:  ------*)

IF argc=0 THEN
  WriteString("Usage:"); WriteLn;
  WriteString("  ReDump Source [TO] Dest [WIDTH xx] [ASC]"); WriteLn;
  WriteLn;
  WriteString("  Source: HexDump-File to be redumped"); WriteLn;
  WriteString("  Dest  : The destination File"); WriteLn;
  WriteString("  xx    : The number of Words per line, default = 8"); WriteLn;
  WriteString("  ASC   : Create file from ASCII-Chars, if they aren't `.'"); WriteLn;
  WriteString(" © 1988 by Fridtjof Siebert, Nobileweg 67,D-7000 Stgt-40"); WriteLn;
  WriteString("    Phone: (0)711/822509"); WriteLn;
  HALT;
END;

(*------  read parameters  ------*)

FOR i:=1 TO argc DO
  GetArg(i,argv[i-1],j);
END;

(*------  analyse commandline:  ------*)

SourceFile := argv[0];
ic := 1; WIDTH := 8; ASC := FALSE;
IF Compare(argv[ic],first,2,"TO",FALSE)=0 THEN (* DestFile: *)
  Assert(argc>=3,ADR("Wrong Parameters."));
  ic := 2;
END;
DestFile := argv[ic];
INC(ic);
IF argc>ic THEN
  IF Compare(argv[ic],first,5,"WIDTH",FALSE)=0 THEN  (* Width *)
    ok := FALSE;
    StrToVal(argv[ic+1],LIWIDTH,ok,10,ok2);
    WIDTH := CARDINAL(LIWIDTH);
    Assert(NOT(ok2),ADR("Error while calculating width."));
    INC(ic,2)
  END;
END;
IF argc>ic THEN (* ASCII *)
  Assert(Compare(argv[ic],first,3,"ASC",FALSE)=0,
         ADR("Wrong Parameters"));
  ASC := TRUE;
END;

RQBuffer  := AllocMem(768,MemReqSet{chip,memClear}); (* Speicher *)
Assert(RQBuffer#NIL,ADR("Not enough Memory !!!"));
OutBuffer := ADDRESS(LONGCARD(RQBuffer) + 512);

(*------  Open Files:  ------*)

OutH := Open(ADR(DestFile),newFile);
Assert(OutH#NIL,ADR("Couldn't open destination."));
InH := Open(ADR(SourceFile),oldFile); (* open source for reading *)
IF InH=NIL THEN Close(OutH); Assert(FALSE,ADR("Source not found.")) END;
TermProcedure(CleanUp);

(*------  Create HexDump:  ------*)

RQLen := 0; RQPos := 0;
Adr := NIL; INC(WIDTH,WIDTH);
ReadQuick(ADR(InBuffer),5);
Ende := FALSE;

WHILE (RQLen#0) AND NOT(Ende) DO
  Assert(InBuffer[4]=":",ADR("Wrong HexDump"));
  FoundAdr := ORD(HexToVal(ADR(InBuffer[0])));
  FoundAdr := SHIFT(FoundAdr,8) + CARDINAL(HexToVal(ADR(InBuffer[2])));
  Assert(FoundAdr=Adr,ADR("Wrong Address Found"));
  count := 0;
  REPEAT
    (* delete Spaces: *)
    j := 0; (* j detects too many Spaces, i.e. End of File *)
    REPEAT
      ReadQuick(ADR(InBuffer[0]),1);
      INC(j);
    UNTIL (InBuffer[0]#" ") OR (RQLen=0);
    IF j<3 THEN
      ReadQuick(ADR(InBuffer[1]),1);
      OutBuffer^[count] := HexToVal(ADR(InBuffer[0]));
      INC(count);
    ELSE
      Ende := TRUE;
    END
  UNTIL (count=WIDTH) OR Ende;
  IF ASC THEN
    IF NOT(Ende) THEN
      ReadQuick(ADR(InBuffer[0]),1);
      ReadQuick(ADR(InBuffer[0]),1);
    END;
    i := 0;
    WHILE (InBuffer[0]#CHAR(10)) AND (i<count) DO
      IF InBuffer[0]#"." THEN
      OutBuffer^[i] := InBuffer[0];
      END;
      INC(i);
      ReadQuick(ADR(InBuffer[0]),1);
    END;
  END;
  len := Write(OutH,OutBuffer,count);
  WHILE InBuffer[0]#CHAR(10) DO
    ReadQuick(ADR(InBuffer[0]),1);
  END;
  ReadQuick(ADR(InBuffer),5);
  IF Adr<=(65535-count) THEN
    INC(Adr,count);
  ELSE
    Adr := ((Adr-32768)+count)-32768; (* this avoids Overflow *)
  END;
END;

(*------  That's it! ------*)

END ReDump.
