[mod.computers.vax] Undump revisited - Source + Doc - Compaction

lrosen@BUFFALO.CSNET (Leonard Rosenblum) (01/29/86)

I have improved on Keith Lynch's (KFL@MIT-MC.ARPA) UNDUMP.FOR program
he distributed in this newsgroup to compact (and uncompact) the
file created by the DUMP command.  The compacted dump file consumes
much less space.  For example:
 
   Filename Extension   Output from Program   # Characters   # Blocks
         .EXE                 LINK                2052           4
         .DMP                 DUMP                8032          16
         .CDM                COMDUMP               801           2
         .DMQ               UNCOMDUMP             4848          10
         .EXE                UNDUMP               2052           4
 
As you can see COMDUMP eliminates about 90% from the DUMP file and 
about 60% from the original .EXE file.  However, sometimes it consumes a
bit more (up to ~40% or so) than the original .EXE file.
 
I have them organized in DCL command procedures so I had to modify
the I/O part of Keith's program.  
 
To set up the system:
 
1-Save the first file as name CDUMP.COM.  Modify the 'LENC' to be the
  directory name where the programs are stored.  This is the command
  procedure which translates the executable image to compacted form.
  Feel free to mail this form.
2-Save the second file as name UNCDUMP.COM.  Modify the 'LENC' to be the 
  directory name where the programs are stored.  This is the command 
  procedure which translates the compacted form into an executable image.
3-Save the third file as name COMDUMP.PAS.  Compile and link it
  to file COMDUMP.EXE and store it in the 'LENC' (see #1 above) dir.
4-Save the forth file as name UNCOMDUMP.PAS.  Compile and link it 
  to file UNCOMDUMP.EXE and store it in the 'LENC' (see #2 above) dir.
5-Save the fifth file as name UNDUMP.FOR.  Compile and link it to
  file UNDUMP.EXE and store it in the 'LENC' (see #2 above) dir.
  This is the modified version of Keith's program.
 
The files are seperated by ~s.  I am sure that more efficient techniques
to compact and especially uncompact are possible.  I commented all the
programs so feel free to improve on them.
 
For those of you who missed the original posting the point to this
system is to be able to mail/save-to-tape executable files.
 
<<<--- Lenny --->>>
---------------------------------------------------------------------
UUCP   : {cmcl2,hao,harpo}!seismo!rochester!rocksvax!sunybcs!lrosen | 
         ...{allegra,decvax,watmath}!sunybcs!lrosen                 |
CSNET  : lrosen@buffalo                                             |
ARPA   : lrosen%buffalo.CSNET@csnet-relay                           |
BITNET : lrosen@sunybcs   OR   v131dllf@sunyabva                    |
---------------------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
$!This COM file does the following:
$!
$! 1-Dump the specified file name (FN) with an EXE extension
$!   to the file fn.DMP
$! 2-Compact file fn.DMP to file fn.CDM 
$! 3-Delete file fn.DMP
$!
$!Note that this COM file reassigns logical files PAS$INPUT
$!  and PAS$OUTPUT and then deassigns them.
$!
$!Written by Leonard Rosenblum and last updated on 86/01/21.
$!
$DUMP/OUTPUT='P1'.DMP 'P1'.EXE
$ASSI 'P1'.DMP PAS$INPUT
$ASSI 'P1'.CDM PAS$OUTPUT
$R 'LENC'COMDUMP
$DEL 'P1'.DMP;
$DEASSI PAS$INPUT
$DEASSI PAS$OUTPUT
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
$!This COM file does the following:
$!
$! 1-Uncompact the specified file (fn) with extension CDM
$!   to file fn.DMQ
$! 2-Create file ZZZUNDUMP.TMP
$! 3-Undump file fn.DMQ to file fn.EXE
$! 4-Delete files fn.DMQ and ZZZUNDUMP.TMP
$!
$!Note that logical files PAS$INPUT and PAS$OUTPUT
$!  are reassigned and then deassigned.  Also, file
$!  ZZZUNDUMP.TMP is created, used as logical file 
$!  ZZZUN, and later deleted.
$!
$!Written by Leonard Rosenblum and last updated on 86/01/21.
$!
$ASSI 'P1'.CDM PAS$INPUT
$ASSI 'P1'.DMQ PAS$OUTPUT
$R 'LENC'UNCOMDUMP
$DEASSI PAS$INPUT
$DEASSI PAS$OUTPUT
$OPEN/WRITE ZZZUN ZZZUNDUMP.TMP
$WR ZZZUN P1+".DMQ"
$WR ZZZUN P1+".EXE"
$CLOSE ZZZUN
$R 'LENC'UNDUMP
$DEL 'P1'.DMQ;,ZZZUNDUMP.TMP;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
PROGRAM COMPACTDUMP(INPUT,OUTPUT);
 
(****************************************************)
(*                                                  *)
(* PROGRAMMER  : LEONARD ROSENBLUM                  *)
(* LAST UPDATED: 86/01/21                           *)
(* PURPOSE     : COMPACTS THE OUTPUT OF A DUMP FILE.*)
(*               ITS INVERSE IS THE PROGRAM UNCOMP. *)
(*               THIS OUTPUT IS TO BE FED TO PROGRAM*)
(*               UNDUMP WRITTEN BY K LYNCH.  THE    *)
(*               WHOLE INTENT IS TO BE ABLE TO MAIL *)
(*               EXECUTABLE FILES EFFICIENTLY.      *)
(*               THIS IS OFCAUSE MACHINE DEPENDENT. *)
(*                                                  *)
(****************************************************)
 
VAR
  NIBLE:ARRAY [1..1024] OF CHAR;
  CH:CHAR;
  NF,NZ,L,I,J,K,LEN:INTEGER;
 
 
PROCEDURE Z(VAR NZ:INTEGER);
 
(****************************************************)
(*                                                  *)
(* PURPOSE  : CREATE AND WRITE THE CODE FOR A SERIES*)
(*            OF NIBLES OF ZEROS.                   *)
(* PARAMETER: NZ IS THE NUMBER OF ZERO NIBLES FOUND *)
(*            FROM THE DUMP FILE IN A ROW.          *)
(*                                                  *)
(****************************************************)
 
VAR
  BLK,INDIV:INTEGER;
 
BEGIN
  BLK:=NZ DIV 8;
  INDIV:=NZ MOD 8;
  IF(INDIV <> 0) THEN
    BEGIN
      CASE INDIV OF
        1:WRITE('0':1);
        2:WRITE('G':1);
        3:WRITE('H':1);
        4:WRITE('I':1);
        5:WRITE('J':1);
        6:WRITE('K':1);
        7:WRITE('L':1)
      END;
      LEN:=LEN-1;
      IF(LEN = 0) THEN
        BEGIN
          LEN:=60;
          WRITELN('W':1)
        END
    END;
  IF(BLK <> 0) THEN
    BEGIN
      WRITE('Z':1,BLK:1,'X':1);
      LEN:=LEN-5;
      IF(LEN <= 0) THEN
        BEGIN
          LEN:=60;
          WRITELN('W':1)
        END
    END;
  NZ:=0
END;
 
 
PROCEDURE F(VAR NF:INTEGER);
 
(****************************************************)
(*                                                  *)
(* PURPOSE  : CREATE AND WRITE THE CODE FOR A SERIES*)
(*            OF NIBLES OF ONES.                    *)
(* PARAMETER: NF IS THE NUMBER OF 'F' NIBLES FOUND  *)
(*            FROM THE DUMP FILE IN A ROW.          *)
(*                                                  *)
(****************************************************)
 
VAR
  BLK,INDIV:INTEGER;
 
BEGIN
  BLK:=NF DIV 8;
  INDIV:=NF MOD 8;
  IF(INDIV <> 0) THEN
    BEGIN
      CASE INDIV OF
        1:WRITE('F':1);
        2:WRITE('M':1);
        3:WRITE('N':1);
        4:WRITE('O':1);
        5:WRITE('P':1);
        6:WRITE('Q':1);
        7:WRITE('R':1)
      END;
      LEN:=LEN-1;
      IF(LEN = 0) THEN
        BEGIN
          LEN:=60;
          WRITELN('W':1)
        END
    END;
  IF(BLK <> 0) THEN
    BEGIN
      WRITE('Y':1,BLK:1,'X':1);
      LEN:=LEN-5;
      IF(LEN <= 0) THEN
        BEGIN
          LEN:=60;
          WRITELN('W':1)
        END
    END;
  NF:=0
END;
 
BEGIN
  WHILE NOT EOF(INPUT) DO
    BEGIN
      (* READ IN ONE BLOCK OF 512 BYTES AT A TIME *)
      FOR I:=1 TO 6 DO
        READLN;
      K:=0;
      (* INPUT ALL THE BYTES IN ARRAY NIBLE *)
      FOR L:=1 TO 16 DO
        BEGIN
          FOR I:=1 TO 8 DO
            BEGIN
              READ(CH);
              FOR J:=1 TO 8 DO
                BEGIN
                  K:=K+1;
                  READ(NIBLE[K])
                END
            END;
          READLN
        END;
 
      LEN:=60;
      NZ:=0;
      NF:=0;
      FOR I:=1 TO 1024 DO
        BEGIN
          IF(NIBLE[I] = '0') THEN
            BEGIN
              NZ:=NZ+1;
              IF(NF <> 0) THEN
                F(NF);
            END
          ELSE IF(NIBLE[I] = 'F') THEN
            BEGIN
              NF:=NF+1;
              IF(NZ <> 0) THEN
                Z(NZ);
            END
          ELSE
            BEGIN
              IF(NZ <> 0) THEN
                Z(NZ);
              IF(NF <> 0) THEN
                F(NF);
              WRITE(NIBLE[I]:1);
              LEN:=LEN-1;
              IF(LEN = 0) THEN
                BEGIN
                  LEN:=60;
                  WRITELN('W':1)
                END
            END
        END (* FOR *);
      IF(NZ <> 0) THEN
        Z(NZ)
      ELSE
        F(NF);
      WRITELN('W':1);
      WRITELN('T':1)
    END
END.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
PROGRAM UNCOMPACT(INPUT,OUTPUT);
 
(*******************************************)
(*                                         *)
(* PROGRAMMER  : LEONARD ROSENBLUM         *)
(* LAST UPDATED: 86/01/21                  *)
(* PURPOSE     : UNCOMPACT THE COMPACTED   *)
(*               VERSION OF A DUMPED .EXE  *)
(*               FILE.  SEE PROGRAM COMPACT*)
(*               FOR MORE INFO.            *)
(*                                         *)
(*******************************************)
 
VAR
  I,CH:CHAR;
  M,L,J,K:INTEGER;
  OUT:ARRAY [1..1024] OF CHAR;
 
BEGIN
  WHILE NOT EOF(INPUT) DO
    BEGIN
      FOR K:=1 TO 6 DO
        WRITELN('T':1);
      K:=0;
      REPEAT
        READ(CH);
        CASE CH OF
           '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F':
                 BEGIN
                   K:=K+1;
                   OUT[K]:=CH
                 END;
           'G','H','I','J','K','L':
               FOR I:='F' TO CH DO
                 BEGIN
                   K:=K+1;
                   OUT[K]:='0'
                 END;
           'M','N','O','P','Q','R':
               FOR I:='L' TO CH DO
                 BEGIN
                   K:=K+1;
                   OUT[K]:='F'
                 END;
           'T','W':
               READLN;
           'Y':BEGIN
                 READ(J);
                 FOR L:=1 TO J DO
                   FOR M:=1 TO 8 DO 
                     BEGIN
                       K:=K+1;
                       OUT[K]:='F'
                     END;
                 READ(CH)
               END;
           'Z':BEGIN
                 READ(J);
                 FOR L:=1 TO J DO
                   FOR M:=1 TO 8 DO
                     BEGIN
                       K:=K+1;
                       OUT[K]:='0'
                     END;
                 READ(CH)
               END;
        END (* CASE *)
      UNTIL (CH = 'T');
 
      (* ERROR-CHECK VALUE OF NIBLES FOUND IN BLOCK *)
      IF(K <> 1024) THEN
        WRITELN(' ERROR K=',K);
 
      (* WRITE ARRAY OUT IN 8 X 16 BLOCKS OF NIBLES *)
      K:=0;
      FOR M:=1 TO 16 DO
        BEGIN
          FOR L:=1 TO 8 DO
            BEGIN
              WRITE(' ');
              FOR J:=1 TO 8 DO
                BEGIN
                  K:=K+1;
                  WRITE(OUT[K])
                END
            END;
          WRITELN(' .')
        END
  END
END.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
        Program UnDump   !By Keith F. Lynch (KFL@MIT-MC.ARPA) October 1983.
        Implicit None    !Opposite of the DUMP command for .EXE files under
                         !VMS.  Use $DUMP/OUTPUT=UNDMP.UDM filename.EXE
                         !        Feel free to mail or copy UNDMP.UDM
                         !        To rerun use: $ R UNDUMP 
                         !           Enter file: UNDMP.UDM
C==================================================================
C  THIS PROGRAM HAS BEEN MODIFIED TO READ THE FILE NAMES OF UNITS
C    1 AND 2 (INPUT AND OUTPUT) FROM FILE 'ZZZUNDUMP.TMP'.
C    THE REASON FOR THIS IS SO THAT THE PROGRAM CAN BE EXECUTED
C    USING DCL PARAMETER SUBSTITUTION.  MODIFIED 86/01/21.
C==================================================================
 
C  NOTE: This is not ANSI standard Fortran but since the program is VMS 
C        dependant...
C
        Byte Block(512),Revers(512),Name(40)   
        Integer*2 Length,Row,Column,Record,J
           OPEN (3,NAME='ZZZUNDUMP.TMP',STATUS='OLD')
           Read (3,13) Length,(Name(J),J=1,39)
13         Format (Q,39A1)
           Name(Length+1) = 0
           Open (Unit=1,Name=Name,Status='Old',Readonly,Shared)
           READ(3,13) Length,(Name(j),j=1,39)
           CLOSE(3)
           Name(Length+1)=0
           Open (Unit=2,Name=Name,Status='New',
     *        Form='Unformatted',Access='Direct',Recordsize=128)
        Record = 0
        Do While (.True.)
           Record = Record + 1
           Read (1,20,End=4)
20         Format (////)
           Read (1,21) Revers
21         Format (16(/,8(1X,4Z2)))
           Do Row=0,15
              Do Column=1,32
                 Block(32*Row + Column) = Revers(32*Row + (33-Column))
              End Do
           End Do
           Write (2,Rec=Record) Block
        End Do
4       Stop
        End
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~