******************************************************************************

*  Program copyright Daniel Epp  March 1989

*  This program may be freely distributed as long as no charge is made for
*  it.
*  And the accompanying doc file remain with it.

*  B2A a program to convert IFF brush files to Assembler image data

*  You use this program at your OWN RISK no warrany of any kind is given!
******************************************************************************

* History
* 04/11/89 fixed bug did not release all memory on exit D.Epp
* 04/11/89 fixed bug Crashed system if there was a write error D.Epp
****************************************************************************


   INCLUDE  "exec/types.i"
   INCLUDE "exec/nodes.i"
   INCLUDE "exec/libraries.i"
   INCLUDE "libraries/dos.i"
   INCLUDE "exec.asm"
   INCLUDE "nMacros.asm"




   XREF _AbsExecBase
   XREF _LVOAllocMem
   XREF _LVOFreeMem
   XREF _LVOOpenLibrary
   XREF _LVOCloseLibrary
   XREF _LVOInput
   XREF _LVOOutput
   XREF _LVOIoErr
   XREF _LVODeleteFile
   XREF _LVOOpen
   XREF _LVOClose
   XREF _LVOSeek
   XREF _LVORead
   XREF _LVOWrite



ExecBase  EQU  $4


WriteFile MACRO
   move.l \1,d1         ;filename to write
   move.l \2,d2         ;Buffer to write from
   move.l \3,d3         ;number of chars to write
   move.l   DosBase,a6
   jsr    _LVOWrite(a6) ;write 'em
   ENDM

ReadFile MACRO
   move.l \1,d1         ;File to read
   move.l \2,d2         ;Buffer to Store data
   move.l \3,d3         ;maximum number of chars to read
   move.l   DosBase,a6
   jsr    _LVORead(a6)  ;read 'em
   ENDM

*---------------------------------------------------------------------------

   move.l   a7,saveSP
   move.l   _AbsExecBase,a6   ;find library address
   move.l   #DOS_Name,a1      ;pass string containing name
   clr.l    d0
   jsr      _LVOOpenLibrary(a6)
   move.l   d0,DosBase         ;a6 holds DOS library pointer from now on
   beq      Abort             ;if d0=0 Abort
   move.l   d0,a6
   jsr      _LVOInput(a6)     ;get input file handle, already open
   move.l   d0,StdIn          ;hang on to it
   beq      Abort             ;Abort if can't find
   jsr      _LVOOutput(a6)    ;get output file handle, if already open
   move.l   d0,StdOut         ;hang on to it
   beq      Abort             ;Abort if can't

   WriteFile StdOut,#gr_String,#gr_Len

GetFName:
   WriteFile StdOut,#FName_Prompt,#Prompt_Len
   ReadFile StdIn,#inFname,#80
   cmpi.b   #32,inFname
   bcs      Abort              ;quit on null string
   move.l   #inFname,a0        ;name of in file
   clr.b    -1(a0,d0.L)        ;null terminate it

   WriteFile StdOut,#OutName_Prompt,#Prompt_Len1
   ReadFile StdIn,#outFname,#80
   cmpi.b   #32,outFname
   bcs      Err_Args           ;quit on null string
   move.l   #outFname,a0       ;address of name of out file (could use Lea)
   clr.b    -1(a0,d0.L)        ;null terminate it

   WriteFile StdOut,#Ctab_Prompt,#ctab_Len
   ReadFile StdIn,#cmap,#80
   cmpi.b   #32,cmap
   bcs      1$                 ;not equal null do Colortable
   move.b   #1,doCtab          ;set flag
1$
   move.l   #inFname,d1       ;name of file
   move.l   #MODE_OLDFILE,d2  ;set access mode
   jsr      _LVOOpen(a6)      ;open file
   lea      bm_Struct,a5      ;address of Bit Map Buffer
   move.l   d0,pfhPic
   bne      Read_Ifile          ;did we get one?
*--------------------- All Error Msg's Are Here --------------------------*
Error
   WriteFile StdOut,#NotFound,#NotFoundLen ;express regrets could'nt open
   bra      GetFName          ;try again
ErrorILBM
   WriteFile StdOut,#NotILBM,#Err_Len
   bra      GetFName
Err_Args
   WriteFile StdOut,#NoInOutFile,#Err_InOut
   bra      Abort
ErrorMem
   WriteFile StdOut,#NoMem,#Err_LenM
   bra      Abort
UknComp
   WriteFile StdOut,#UknCompr,#Err_LenC
WriteError                           ;will only get here from 2 places
   jsr      _LVOIoErr(a6)
   move.l   d0,IoError
   move.l   Struct_fh,d1
   jsr      _LVOClose(a6)
   move.l   #0,Struct_fh
   move.l   #outFname,d1
   jsr      _LVODeleteFile(a6)
   WriteFile StdOut,#WrErr,#Err_LenW
   bra      Abort                    ;try to exit gracefully
Read_Ifile
   ReadFile pfhPic,#chunkBuff,#12
   cmp.l    #'FORM',chunkType
   bne      ErrorILBM

   cmp.l    #'ILBM',chunkSubType
   bne      ErrorILBM

ReadILBM
   ReadFile pfhPic,#chunkBuff,#8

CkBMHD
   move.l   chunkType,d0
   cmp.l    #'BMHD',d0
   bne      CkCMAP

   move.l  a5,d2                   ;a5 contains address of bmhd buffer
   ReadFile pfhPic,d2,#bmhd_SIZEOF
   bra      ReadILBM

CkCMAP
   cmp.l    #'CMAP',d0
   bne      CkCAMG
   move.l   chunkLen,d4
   divu     #3,d4
   move.w   d4,ccoMap
   subq     #1,d4
   lea.l    cmap,a3
   lea      chunkLen+1,a4
1$
   ReadFile pfhPic,#chunkLen+1,#3   ;read r,g,b values
   moveq    #2,d5                   ;rgb counter
   move.l   a4,a2                   ;reset a2 to Address of chunkLen
2$
   move.b   (a2)+,d0                ;get rgb value
   lsr.w    #4,d0                   ;need upper nibble of byte
   moveq    #1,d6                   ;counter for byte dec conversion
   moveq    #0,d7
3$
   divu     #10,d0                  ;just converting binary
   swap     d0
   move.b   d0,d1
4$
   add.b    #'0',d1
   clr.w    d0
   swap     d0                       ;to ASCII decimal
   tst.w    d0
   beq      5$
   move.b   d1,d7                    ;if here number is 2 digits (ie 10-15)
                                     ;so save d1 for later
   dbra     d6,3$                    ;go back & finish the number

5$
   move.b   d1,(a3)+                 ;store the result
   tst.b    d7
   beq      6$
   move.b   d7,(a3)+
6$
   move.b   #',',(a3)+
   dbra     d5,2$
   move.b   #0,-1(a3)                 ;null terminate
   dbra     d4,1$                     ;do again nColors-1
   bra      ReadILBM

CkCAMG
   cmp.l    #'CAMG',d0
   bne      CkBODY
   ReadFile pfhPic,#chunkSubType,#4
   move.w   chunkSubType+2,TossIt
   bra      ReadILBM

CkBODY
   cmp.l    #'BODY',d0
   beq      Continue

DontNeed
   move.l   pfhPic,d1
   move.l   chunkLen,d2
   moveq    #OFFSET_CURRENT,d3
   jsr      _LVOSeek(a6)
   bra      ReadILBM

Continue
   move.l   chunkLen,d7                ;length in bytes of Body
   move.l   a5,a3                      ;address of bmhd Buffer

   cmp.b    #2,bmhd_compression(a3)
   bge      UknComp
   move.l   d7,d0                      ;allocate memory for file
   move.l    #MEMF_CLEAR!MEMF_PUBLIC,d1
   move.l   ExecBase,a6
   jsr      _LVOAllocMem(a6)
   move.l   d0,picBuff
   beq      ErrorMem

*------------ Figure out approx memory need for out file ---*
   move.w   bmhd_w(a3),d3           ;width of image
   add.w    #16,d3                  ;plus 16
   bclr     #0,d3                   ;make sure even number
   moveq    #0,d0
   move.w   bmhd_h(a3),d0           ;height of image
   addq     #1,d0
   mulu     d0,d3                   ;width*height
   lsr.l    #3,d3                   ;divided by 8 (convert to bytes)
   btst     #0,d3
   beq      Ok1
   addq     #2,d3                   ;make even number of bytes
   bclr     #0,d3
Ok1
                                 ;1 binary byte = 2 ASCII bytes
   lsl.l    #1,d3                ;*2 for ASCII conversion
   move.l   d3,bytes_per_Plane   ;save for later

   moveq    #0,d2
   move.b   bmhd_nPlanes(a3),d2
   subq     #1,d2                   ;-1 for dbra loop
   lea.l    PlanePtr,a2             ;Array for memory for Planes Ptr's

MoreMem                          ;Allocate memory for n Planes
   move.l   d3,d0
   move.l   #MEMF_CLEAR!MEMF_PUBLIC,d1
   jsr      _LVOAllocMem(a6)
   move.l   d0,(a2)+
   beq      ErrorMem
   dbra     d2,MoreMem

   ReadFile pfhPic,picBuff,d7

Decomp
   lea.l    PlanePtr,a6                 ;ptr to Plane 1 buffer
   cmp.b    #1,bmhd_masking(a3)
   bne      10$
   moveq    #0,d0
   move.b   bmhd_nPlanes(a3),d0
   lsl.w    #2,d0
   move.l   #$FE0000,0(a6,d0.w)
   addq.b   #1,bmhd_nPlanes(a3)
10$
   moveq    #0,d6
   move.w   bmhd_w(a3),d6  ;width of image
   divu     #8,d6          ;divided by 8 = bytes per row
   move.l   d6,d5
   swap     d5             ;check for remainder from divide
   tst.w    d5
   beq      11$            ;if yes
   add.w    #2,d6          ;add 2 bytes
   bclr     #0,d6          ;make sure d6 is even number
11$
   move.l   picBuff,a0     ;address of picture file
   move.w   bmhd_h(a3),d4  ;# of rows
   subq.w   #1,d4          ;# of rows -1
   moveq    #0,d3
1$
   moveq    #0,d5
   move.b   bmhd_nPlanes(a3),d5      ;# of planes in picture
   move.l   a6,a2                    ;restore plane ptr to 1st
2$
   dbra     d5,3$                    ;loop each plane convert 1 row
   move.w   d6,d1                    ;d6 is offset in to file
   lsl.w    #1,d1                    ;*2 because were moving words after
   add.w    d1,d3                    ;conversion
   dbra     d4,1$                    ;decrement rows and do it again for all
                                     ;rows
   bra      MakeFile                 ;done go write the converted file
3$
   move.l   (a2)+,a1
   add.w    d3,a1
35$
   move.w   d6,d2                     ;put bytes per row in d2
   tst.b    bmhd_compression(a3)      ;is file compressed?
   bne      50$                       ;branch if <> 0 compressed = 1
   subq     #1,d2                     ;if were here
4$                                    ;row not compressed
   move.b   (a0)+,d0                  ;so move bytes literally
   bsr      bin2Hex                   ;convert to ASCII
   move.w   d0,(a1)+                  ;store in Plane (n) buffer
   dbra     d2,4$                     ;do d2 times (1 row)
   bra      2$
50$                                   ;if here row is compressed
   tst.w    d2                        ;d2 = bytes_per_row
   ble      2$                        ;if 0 this row done
   moveq    #0,d1
51$
   move.b   (a0)+,d1                  ;d1 contains #bytes to replicate if -
   bmi      53$                       ;if not - do d1 row of bytes
   sub.w    d1,d2
   subq.w   #1,d2
52$
   move.b   (a0)+,d0
   bsr      bin2Hex
   move.w   d0,(a1)+
   dbra     d1,52$
   bra      50$
53$
   cmp.b    #128,d1                     ;byte was negative so d1
   beq      50$                         ;is # of bytes to replicate
   neg.b    d1                          ;change to plus value
   sub.w    d1,d2
   subq.w   #1,d2
   move.b   (a0)+,d0                    ;replicate byte in d0 d1 times
   bsr      bin2Hex
54$
   move.w   d0,(a1)+
   dbra     d1,54$
   bra      50$
*------------------------- Convert binary to ASCII ----------------------*
bin2Hex
   movem.l  d1-d2/a0-a1,-(a7)       ;save registers used
   lea      HexTab,a1               ;Hex digits
   lea      Hdigit,a0               ;longword to store results
   adda.l   #2,a0                   ;word operation for this use
   move.l   #1,d1                   ;loop twice
hLoop
   move.l   d0,d2                   ;d0 contains byte to convert
   andi.l   #15,d2                  ;mask off all but lower nibble
   move.b   0(a1,d2),-(a0)          ;move value from hex table
   lsr.l    #4,d0                   ;get next nibble
   dbra     d1,hLoop
   move.w   (a0)+,d0                ;put result back in d0
   movem.l  (a7)+,d1-d2/a0-a1
   rts

MakeFile
   move.l   a5,a3               ;Get info for Image Structure
   move.w   bmhd_x(a3),d0
   lea      image_left,a0
   bsr      BintoDec
   move.w   bmhd_y(a3),d0
   lea      image_top,a0
   bsr      BintoDec
   move.w   bmhd_w(a3),d0
   lea      image_w,a0
   bsr      BintoDec
   move.w   bmhd_h(a3),d0
   lea      image_h,a0
   bsr      BintoDec
   move.b   bmhd_nPlanes(a3),d0
   lea      image_nPlane,a0
   bsr      BintoDec
   move.l   DosBase,a6
   move.l   #outFname,d1          ;name of file
   move.l   #MODE_NEWFILE,d2      ;set access mode
   jsr      _LVOOpen(a6)          ;open file

   move.l   d0,Struct_fh          ;d0 contains our file handle
   beq      CloseFil              ;didn't get one? Panic

   lea      image_left,a0         ;fill Image Structure with values
   lea      im_Structure,a1       ;obtained above
   moveq    #4,d2                 ;5 values (x,y,width,height,depth)
   bsr      fill_Str
   move.b   #' ',-1(a1)           ;removes last comma from fill_Str routine

   WriteFile Struct_fh,#im_Structure,#im_Send   ;write the image structure

do_Data
   lea      PlanePtr,a0
   moveq    #0,d3
   move.b   bmhd_nPlanes(a3),d3
   subq.b   #1,d3
1$
   move.l   (a0)+,a1             ;ptr's to n planes of data
   move.l   bytes_per_Plane,d2
   lsr.l    #2,d2                ;convert bytes to longwords
   lsr.l    #3,d2                ;d2 longwords / 8 per row
   subq     #1,d2                ;-1 for dbra counter loop
10$
   moveq    #7,d0                ;n entries-1 per row
   lea      formatBuff,a2        ;buffer for formatting output
20$
   move.w      #'  ',(a2)+
   move.l      #' dc.',(a2)+
   move.l      #'w  $',(a2)+
   cmp.w       #7,d0             ;1st time thru each line don't put a ,$
   beq         31$
30$
   move.w      #',$',(a2)+       ;append ,$
31$
   move.l      (a1)+,(a2)+       ;takes long move to move ASCII word '0000'
   beq         34$               ;no more in this plane?
   dbra        d0,30$            ;loop thru 1 line at a time
33$
   movem.l     d2-d3/a0-a2,-(a7)
   WriteFile   Struct_fh,#formatBuff,#57   ;write the line
   movem.l     (a7)+,d2-d3/a0-a2
   tst.l       d0
   bmi         WriteError
   dbra        d2,10$                      ;loop thru 1 plane at a time

   movem.l     d2-d3/a0-a2,-(a7)
   WriteFile   Struct_fh,#BlankLine,#57    ;insert a blank line
   movem.l     (a7)+,d2-d3/a0-a2
   tst.l       d0
   bmi         WriteError
   dbra        d3,1$                       ;do next plane
   tst.b       doCtab                      ;Did user want Palette info?
   beq         Abort                         ;=0? Close up shop were done!
   bsr         DoColorDATA                 ;if so Go do it
36$
   bra         Abort                       ;Were Done!
*--------------- This is for last line padding each plane ------------*
34$
   subq.l      #6,a2                ;get rid of extra characters
   moveq       #0,d2                ;set line counter to 0
35$
   move.w      #'  ',(a2)+          ;pad out with spaces
   move.l      #'    ',(a2)+
   dbra        d0,35$               ;amount left in d0
   bra         33$                  ;go back and write the line

fill_Str
   add.w    #10,a1                  ;don't overwrite dc.w in buffer
1$
   moveq    #7,d1                   ;check 8 bytes each
10$
   move.b   (a0)+,d0
   beq      12$                     ;if not 0 put value
11$
   move.b   d0,(a1)+                ;in buffer and
12$
   dbra     d1,10$
   move.b   #',',(a1)+              ;append comma
   dbra     d2,1$
   rts

DoColorDATA
   WriteFile   Struct_fh,#ColorTabName,#ct_Len  ;color table label
   move.w      ccoMap,d5                        ;no of colors
   subq        #1,d5                            ;-1
   lea         cmap,a4                          ;address of colortable
40$
   lea         ColorData+10,a3
   moveq       #0,d3
41$
   addq        #1,d3                         ;# of bytes moved
   move.b      (a4)+,(a3)+                   ;copy rgb to format buffer
   bne         41$                           ;till hit 0 byte
   move.b      #10,-1(a3)                    ;put linefeed char
   add.w        #10,d3                       ;add 10 char for spaces & dc.w
   WriteFile   Struct_fh,#ColorData,d3       ;write the line
   tst.l       d0
   bmi         WriteError
   dbra        d5,40$                        ;do nColors-1 times
   rts
*--------------------- Convert Bin Decimal Number --------------------*
*  Enter with number to convert in d0                                 *
*  Ptr to 8 byte buffer in a0
*  Handles only 4 digit ASCII conversion                              *
*  The amount that fits one longword! (thats all I needed)            *
*---------------------------------------------------------------------*
BintoDec
   moveq    #5,d1
   moveq    #0,d2
dLoop
   divu     #10,d0          ;divide the number by 10 (base ten)
   swap     d0              ;the remainder is the number we need
   move.b   d0,d2        ;remainder is in high order of word
   add.b    #'0',d2       ;add 30 to result to make it ASCII
   ror.l    #8,d2
   clr.w    d0
   swap     d0
   tst      d0              ;If d0 not 0 go divide again
   beq      nMoreDigits
   dbra     d1,dLoop
   bra      ConvertDone
nMoreDigits
   ;move.b   #' ',-(a0)      ;pad out unused decimal places with spaces
   ;dbra     d1,nMoreDigits
ConvertDone
    move.l  d2,(a0)
    rts

Write
   move.l   DosBase,a6
   jsr      _LVOWrite(a6)
   rts
Read
   move.l   DosBase,a6
   jsr      _LVORead(a6)
   rts

Abort
CloseFil
   move.l   saveSP,sp
   move.l   DosBase,a6
   move.l   pfhPic,d1
   beq      3$
   jsr      _LVOClose(a6)
3$
   move.l   Struct_fh,d1
   beq      4$
   jsr      _LVOClose(a6)
4$

   tst.l    picBuff
   beq      10$
   move.l   picBuff,a1
   move.l   d7,d0
   move.l   ExecBase,a6
   jsr      _LVOFreeMem(a6)
10$
   lea.l    PlanePtr,a4
11$
   move.l   (a4)+,d0
   beq      20$
   move.l   d0,a1
   move.l   bytes_per_Plane,d0
   move.l   ExecBase,a6
   jsr      _LVOFreeMem(a6)
   bra      11$
20$
   move.l   DosBase,d0
   beq      30$
   move.l   d0,a1
   move.l   ExecBase,a6
   jsr      _LVOCloseLibrary(a6)
30$
   move.l   IoError,d0
   rts

   SECTION data,DATA
* ===========================================================================
* IFF BitMap header structure (BMHD)
   STRUCTURE BitMapHeader,0
      UWORD bmhd_w
      UWORD bmhd_h
      WORD  bmhd_x
      WORD  bmhd_y
      UBYTE bmhd_nPlanes
      UBYTE bmhd_masking
      UBYTE bmhd_compression
      UBYTE bmhd_pad1
      UWORD bmhd_transparentColor
      UBYTE bmhd_xAspect
      UBYTE bmhd_yAspect
      WORD  bmhd_pageWidth
      WORD  bmhd_pageHeight
   LABEL bmhd_SIZEOF
      cnop 0,2
* ===========================================================================


DOS_Name:
   dc.b     'dos.library',0   ;any version
   cnop 0,2
gr_String
   dc.b  $9b,'3;33;42m'
   dc.b  ' Brush to Asm',$9b,'0;33;42m V 1.01 Copyright © 1989 by Dan Epp '
   dc.b  $9b,'0;31;40m',13,10
gr_Len equ *-gr_String
   cnop 0,2

FName_Prompt:
   dc.b  10,'Brush File to Convert: ',0
Prompt_Len EQU    *-FName_Prompt
   cnop 0,2

OutName_Prompt
   dc.b  'Name of Out File: ',0
Prompt_Len1 EQU    *-OutName_Prompt
   cnop 0,2

Ctab_Prompt
   dc.b  'Do you Want Color Info? Return = None: ',0
ctab_Len    equ   *-Ctab_Prompt
   cnop 0,2

NotFound
   dc.b     'Sorry, Could not Open File... Not Found? ',13,10
NotFoundLen EQU   *-NotFound
   cnop 0,2

NotILBM
   dc.b     'File is not an IFF Brush File',13,10
Err_Len     EQU *-NotILBM
   cnop 0,2

NoMem
   dc.b     'Could not Allocate Memory For Buffers!',10
Err_LenM    EQU *-NoMem
   cnop 0,2

UknCompr
   dc.b     'Can not Read, Unknown Compression Used!',10
Err_LenC    EQU *-UknCompr
   cnop 0,2
NoInOutFile
   dc.b     'Must supply In and Out File Names!',10
Err_InOut   equ  *-NoInOutFile
   cnop 0,2
WrErr
   dc.b     10,'Write Error Occurred, File Removed',10
Err_LenW  equ  *-WrErr
   cnop 0,2

BlankLine
   dc.b ';End of Plane                                           ',10
   cnop 0,2
bl_Len equ *-BlankLine

formatBuff
   dc.b '                                                        ',10
fm_Len equ *-formatBuff
   cnop 0,2

saveSP      dc.l  0
PlanePtr    dc.l  0,0,0,0,0,0,0,0      ;array for plane ptrs
StdIn       dc.l  0
StdOut      dc.l  0
IoError     dc.l  0
Struct_fh   dc.l  0    ;file handle for Output File
pfhPic      dc.l  0    ;file Handle for Picture file
picBuff     dc.l  0    ;ptr to Buffer for ILBM file
DosBase     dc.l  0

bytes_per_Plane dc.l 0

chunkBuff
chunkType    dc.l  0                  ;IFF chunk info read here
chunkLen     dc.l  0
chunkSubType dc.l  0
fGotCMAP     dc.b  0
doCtab       dc.b  0

image_left     dcb.b 8,0
image_top      dcb.b 8,0
image_w        dcb.b 8,0
image_h        dcb.b 8,0
image_nPlane   dcb.b 2,0
image_dPtr     dcb.b 16,0
image_planPick dcb.b 4,0
image_pad      dcb.b 2,0
image_Next     dcb.b 16,0

ColorTabName
   dc.b  'ColorTable',10
ct_Len   equ *-ColorTabName
ColorData
   dc.b  '   dc.w            '
cd_Len   equ *-ColorData

im_Structure
   dc.b '   dc.w                   ;left_edge,top_edge,width,height,depth ',10
im_f1  equ *-im_Structure

im_data_Ptr
   dc.b '   dc.l   0                ;Ptr to Image Data ',10

im_Plane_Pick
   dc.b '   dc.b   3,0              ;PlanePick PlaneOff ',10

im_Ptr_Next
   dc.b '   dc.l   0                ;Ptr to Next Image ',13,10
   dc.b ';--------------------- Image Data --------------------',10
im_Send equ *-im_Structure
   cnop 0,2

HexTab dc.b '0123456789ABCDEF'
   cnop 0,2

TossIt      dc.w 0
ccoMap      dc.w 0
Hdigit      dc.w 0

   SECTION BSS
inFname    ds.b  80    ;Buffer for in file name
outFname   ds.b  80    ;Buffer for out file name
bm_Struct  ds.b  bmhd_SIZEOF
cmap       ds.b  (32*4)

   END




