
'========================================================================
'' Hex dump demo, modal dialog as main.
''
'' The file to dump must be specified on the command line,
'' or just dropped onto the EXE.
'========================================================================

'========================================================================
'' This function takes a source address and a byte count, allocates a
'' buffer, builds a hex-ascii dump of the source memory in the buffer,
'' and returns the address of the buffer, or zero if the byte count is
'' zero or the allocation failed. The source memory must be mapped into
'' the address space of the calling process and must be readable. The
'' fZeroBase parameter specifies that the displayed addresses should
'' be relative to the start of the buffer.
''
'' This code uses fast table lookups, unrolled loops in the code that
'' processes the full paragraphs, and only 386-compatible instructions.
'========================================================================

Function HexDump( Byval pSrc As Byte Ptr, _
                  Byval cbSrc As Integer, _
                  Byval fZeroBase As Integer) As Byte Ptr

  Dim As Integer i, cbBuff, cParagraphs, cbExtra, baseAdjust
  Dim As Byte Ptr pDest, pTemp

  If cbSrc = 0 Then Return 0

  '' The number of full paragraphs is stored in cParagraphs and the
  '' number of bytes in the last partial paragraph in cbExtra.

  cParagraphs = cbSrc \ 16
  cbExtra = cbSrc Mod 16
  cbBuff = ( cParagraphs + iif(cbExtra, 1, 0) ) * 79 + 1

  pDest = callocate( cbBuff )

  If pDest = 0 Then Return 0

  If fZeroBase Then baseAdjust = cast(Integer,pSrc)

  '' Overwrite the area of the buffer where the dump of the last
  '' paragraph will be stored with spaces, to allow the code to
  '' handle partial paragraphs with a minimum of monkey motion.
  '' The terminating null must not be overwritten.

  For i = cbBuff - 68 To cbBuff - 4
    *(pDest+i) = 32
  Next

  asm

    '' Switch to the data secton and align on a 16-byte boundary.

    .data
    .balign 16

  hex_table:

    .ascii "000102030405060708090A0B0C0D0E0F"
    .ascii "101112131415161718191A1B1C1D1E1F"
    .ascii "202122232425262728292A2B2C2D2E2F"
    .ascii "303132333435363738393A3B3C3D3E3F"
    .ascii "404142434445464748494A4B4C4D4E4F"
    .ascii "505152535455565758595A5B5C5D5E5F"
    .ascii "606162636465666768696A6B6C6D6E6F"
    .ascii "707172737475767778797A7B7C7D7E7F"
    .ascii "808182838485868788898A8B8C8D8E8F"
    .ascii "909192939495969798999A9B9C9D9E9F"
    .ascii "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"
    .ascii "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"
    .ascii "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"
    .ascii "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"
    .ascii "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"
    .ascii "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"

  ascii_table:

    '' Note the escapes for double-quote and backslash.

    .ascii "................"
    .ascii "................"
    .ascii " !\x22#$%&'()*+,-./"
    .ascii "0123456789:;<=>?"
    .ascii "@ABCDEFGHIJKLMNO"
    .ascii "PQRSTUVWXYZ[\\]^_"
    .ascii "`abcdefghijklmno"
    .ascii "pqrstuvwxyz{|}~."
    .ascii "................"
    .ascii "................"
    .ascii "................"
    .ascii "................"
    .ascii "................"
    .ascii "................"
    .ascii "................"
    .ascii "................"

    '' Switch back to the code section.

    .text

    mov edi, [pDest]
    mov esi, [pSrc]
    mov ecx, [cParagraphs]
    test ecx, ecx
    jz  do_partial_paragraph
    jmp paragraph_loop

    .balign 16

  hex_address:

    '' Convert the address of the paragraph to hex and
    '' copy the digits to the buffer. EBX must contain
    '' the address of the hex table.

    push ecx
    mov ecx, esi
    Sub ecx, [baseAdjust]
    movzx edx, cl
    movzx eax, WORD Ptr [ebx+edx*2]
    mov [edi+6], ax
    Shr ecx, 8
    movzx edx, cl
    movzx eax, WORD Ptr [ebx+edx*2]
    mov [edi+4], ax
    Shr ecx, 8
    movzx edx, cl
    movzx eax, WORD Ptr [ebx+edx*2]
    mov [edi+2], ax
    Shr ecx, 8
    movzx edx, cl
    movzx eax, WORD Ptr [ebx+edx*2]
    mov [edi], ax
    add edi, 8
    pop ecx
    ret

  paragraph_loop:

    lea ebx, hex_table
    Call hex_address
    mov Byte Ptr [edi], 0x20
    add edi, 1

    push esi

    .rept 8
      mov Byte Ptr [edi], 0x20
      movzx edx, Byte Ptr [esi]
      movzx eax, WORD Ptr [ebx+edx*2]
      mov [edi+1], ax
      add edi, 3
      add esi, 1
    .endr

    mov WORD Ptr [edi], 0x2D20
    add edi, 2

    .rept 8
      mov Byte Ptr [edi], 0x20
      movzx edx, Byte Ptr [esi]
      movzx eax, WORD Ptr [ebx+edx*2]
      mov [edi+1], ax
      add edi, 3
      add esi, 1
    .endr

    pop esi

    mov WORD Ptr [edi], 0x2020
    add edi, 2

    lea ebx, ascii_table
    .rept 16
      movzx edx, Byte Ptr [esi]
      movzx eax, Byte Ptr [ebx+edx]
      mov [edi], al
      add esi, 1
      add edi, 1
    .endr

    mov WORD Ptr [edi], 0x0A0D
    add edi, 2

    Sub ecx, 1
    jnz paragraph_loop

  do_partial_paragraph:

    mov ecx, [cbExtra]
    test ecx, ecx
    jz  finished

    lea ebx, hex_table
    Call hex_address

    mov Byte Ptr [edi], 0x20
    add edi, 1

    push ecx
    push esi

    mov edx, 8

  hex_loop1:

    mov Byte Ptr [edi], 0x20

    '' If past the end of the source memory, indicated by ECX < 0,
    '' skip the source read, table lookup, and destination store
    '' steps, but update the source and destination pointers.

    Sub ecx, 1
    js  L1
    movzx eax, Byte Ptr [esi]
    movzx eax, WORD Ptr [ebx+eax*2]
    mov [edi+1], ax
  L1:
    add edi, 3
    add esi, 1

    Sub edx, 1
    jnz hex_loop1

    '' Store the "-" only if at least one byte follows.

    cmp ecx, 1
    jl  L2
    mov WORD Ptr [edi], 0x2D20
  L2:
    add edi, 2

    mov edx, 8

  hex_loop2:

    mov Byte Ptr [edi], 0x20
    Sub ecx, 1
    js  L3
    movzx eax, Byte Ptr [esi]
    movzx eax, WORD Ptr [ebx+eax*2]
    mov [edi+1], ax
  L3:
    add edi, 3
    add esi, 1

    Sub edx, 1
    jnz hex_loop2

    pop esi
    pop ecx

    mov WORD Ptr [edi], 0x2020
    add edi, 2

    lea ebx, ascii_table
    mov edx, 16

  ascii_loop:

    Sub ecx, 1
    js L4
    movzx eax, Byte Ptr [esi]
    movzx eax, Byte Ptr [ebx+eax]
    mov [edi], al
  L4:
    add esi, 1
    add edi, 1

    Sub edx, 1
    jnz ascii_loop

    mov WORD Ptr [edi], 0x0A0D

  finished:

  End asm

  Return pDest

End Function

/'
dim as byte ptr p
dim as integer i
dim as byte arr(255)

for i = 0 to 255
  arr(i) = i
next
for i = 0 to 255
  p = HexDump( @arr(0), i + 1 )
  print *cast(zstring ptr,p)
  deallocate(p)
  sleep
next
sleep
'/
 
#include "dialogs.bas"
#include "vbcompat.bi"
#include "win/shlwapi.bi"

'========================================================================

Function DialogProc( Byval hDlg As  HWND, _
                     Byval uMsg As UINT, _
                     Byval wParam As WPARAM, _
                     Byval lParam As LPARAM ) As Integer

  Static As HWND hWndEdit
  Dim As Byte Ptr pBuffer, pDump
  Dim As RECT rcDlg

  Select Case uMsg

    Case WM_CTLCOLORSTATIC

      '' Change the background for the read-only edit control,
      '' which by default is too dark for easy reading, to a
      '' more normal white.

      Return cast(Integer,GetStockObject( WHITE_BRUSH ))

    Case WM_INITDIALOG

      hWndEdit = GetDlgItem( hDlg, 101 )
      SendMessage( hWndEdit, EM_SETLIMITTEXT, 1000000, 0 )

      Open Command For Binary As 1

      If Lof(1) Then

        Dim As Integer tbbwidth
        Dim As String temp

        GetClientRect( hDlg, @rcDlg )

        tbbwidth = GetSystemMetrics( SM_CXSIZE )

        temp = Command

        '' Compact the path string if it exceeds the width of
        '' the title bar less 3 title-bar button widths.

        PathCompactPath( GetDC( hDlg ), Strptr(temp), _
                         rcDlg.right - 3 * tbbwidth )

        '' Display the path.

        SetWindowText( hDlg, temp )

      End If

      pBuffer = allocate( Lof(1) )

      Get #1, , *pBuffer, Lof(1)

      pDump = HexDump( pBuffer, Lof(1), true )

      SendMessage( hWndEdit, WM_SETTEXT, 0, cast(LPARAM,pDump) )

      '' Cannot remove highlight by sending EM_SETSEL directly,
      '' see http://support.microsoft.com/kb/96674 for details.

      SetFocus( hWndEdit )
      PostMessage( hWndEdit, EM_SETSEL ,0 , 0 )

    Case WM_COMMAND

      If loword(wParam) = IDCANCEL Then

          EndDialog( hDlg, null )

      End If

    Case WM_SIZE

      '' This is a one-time sizing of the edit control to
      '' fit the client area of the dialog.

      GetClientRect( hDlg, @rcDlg )

      MoveWindow( hWndEdit, 0, 0, rcDlg.right, rcDlg.bottom, true )

    Case WM_CLOSE

      deallocate( pBuffer )
      deallocate( pDump )

      EndDialog( hDlg, null )

  End Select

  Return 0

End Function

'========================================================================
'' Start of implicit main.
'========================================================================

Dim As LPDLGTEMPLATE lpdt

'' Specify a fixed-pitch font.

Dialog( 1, 0, 0, 320, 240, "Hex Dump Demo", lpdt, _
        WS_OVERLAPPED Or WS_SYSMENU Or  DS_CENTER Or DS_SETFONT, _
        8, "Courier New" )

EditText( 101, 0, 0, 0, 0, "", _
           WS_VSCROLL Or _
           ES_MULTILINE Or _
           ES_AUTOVSCROLL Or _
           ES_NOHIDESEL Or _
           ES_WANTRETURN Or _
           ES_READONLY )

CreateModalDialog( 0, @DialogProc, 0, lpdt )

'========================================================================
 