'
'      *** BINDUMP - a universal binary dumper ***
'
' Sometimes I need to check a (text-)file with a binary viewer
'   whether or not it contains a Carriage Return (0x0D) or
'                   some other character.
'
' This small program can do so, the -c parameter generates
'   colored output.
'
' We read the target program in chunks of 16 bytes instead of
' reading it into memory completely, to avoid memory overflow
'             problems with really large files.
'
' PvE, February 2010 - GPL.
' Revised March 2012 - PvE.
' Revised December 2013 - PvE.
' -------------------------------------------------------------------

' Chunks of 16 bytes
CONST Chunk_Size = 16

' Declare as 'int' to avoid compiler warnings with FORMAT
DECLARE counter, Total_Rows TYPE int
DECLARE byte TYPE unsigned char

' Get the current amount of rows
IF ROWS > 0 THEN
    Total_Rows = ROWS-2
ELSE
    Total_Rows = 23
END IF

' Parse arguments to program
SPLIT ARGUMENT$ BY " " TO arg$ SIZE dim
IF dim < 2 THEN
    PRINT "Usage: bindump [-c] <file>"
    END
ENDIF

' Get parameter
IF arg$[1] = "-c" AND dim = 3 THEN
    Use_Color = TRUE
    prog$ = arg$[2]
ELSE
    Use_Color = FALSE
    prog$ = arg$[1]
END IF

' Check if file exists
IF NOT(FILEEXISTS(prog$)) THEN
    PRINT "ERROR: file not found!"
    END
END IF

' This is the memory area which will be printed
Mem_Block = MEMORY(Chunk_Size)

' Start reading the file
OPEN prog$ FOR READING AS file

' Walk through file until end
WHILE NOT(ENDFILE(file)) DO

    ' Reset memory area to clean previous data
    FOR i = 0 TO Chunk_Size - 1
        POKE Mem_Block + i, 0
    NEXT

    ' Set File Pointer to next position
    SEEK file OFFSET counter*Chunk_Size

    ' Perform a binary read into our memory area
    GETBYTE Mem_Block FROM file SIZE Chunk_Size

    ' Print the current memory address
    IF Use_Color THEN COLOR FG TO RED
    PRINT "[";

    IF Use_Color THEN COLOR FG TO YELLOW
    PRINT counter * Chunk_Size FORMAT "%08x"

    IF Use_Color THEN COLOR FG TO RED
    PRINT "]  ";

    ' Dump binary values as hex on screen
    FOR i = 0 TO Chunk_Size - 1
        byte = PEEK(Mem_Block + i)

        IF Use_Color THEN COLOR FG TO GREEN
        PRINT byte FORMAT "%02X "
    NEXT
    PRINT " ";

    ' Dump binary values as character on screen
    FOR i = 0 TO Chunk_Size - 1
        byte = PEEK(Mem_Block + i)

        IF Use_Color THEN COLOR FG TO CYAN
        IF byte > 31 AND byte < 127 THEN PRINT CHR$(byte);
        ELSE PRINT ".";
    NEXT

    ' Next line and chunk
    PRINT:INCR counter

    ' Get key from user
    IF MOD(counter, Total_Rows) = 0 THEN
        COLOR RESET
        PRINT "<space> = next, <u> = up, <ESC> or <q> = exit"

        key = GETKEY
        SELECT key
            CASE 113;
            CASE 27
                BREAK
            CASE 117
                IF counter > Total_Rows THEN
                    DECR counter, 2*Total_Rows
                ELSE
                    counter = 0
                END IF
        END SELECT
    END IF

WEND

' Reset and close all
IF Use_Color THEN COLOR RESET

CLOSE FILE file
FREE Mem_Block