Page 1 of 2

Hex 2 Binary

Posted: Fri May 15, 2020 8:15 am
by wayne-c
I have an image as a hex-encoded string. How can I convert it back to binary?

Code: Select all

481830010FFD8FFE000104A46494600010201004800480000FFE11CB24578696600004D4D0......

Re: Hex 2 Binary

Posted: Fri May 15, 2020 9:07 am
by Michael Vogel
Do you need the byte values or a binary string?

Re: Hex 2 Binary

Posted: Fri May 15, 2020 9:09 am
by wayne-c
Michael Vogel wrote:Do you need the byte values or a binary string?
Hey Hichael thank you for your reply. I need a *Buffer to be able to save the originial image file to disk.

Re: Hex 2 Binary

Posted: Fri May 15, 2020 10:21 am
by HeX0R

Code: Select all

Procedure Hex2Mem(HexString.s)
	Protected *Buffer, i, Size, *b.BYTE
	
	Size    = Len(HexString) / 2
	*Buffer = AllocateMemory(Size)
	*b      = *Buffer
	For i = 0 To Size - 1
		*b\b = Val("$" + Mid(HexString, i * 2 + 1, 2))
		*b + 1
	Next i
	
	ProcedureReturn *Buffer
EndProcedure


a$ = "481830010FFD8FFE000104A46494600010201004800480000FFE11CB24578696600004D4D0"
*b = Hex2Mem(a$)
For i = 0 To MemorySize(*b) - 1
	Debug RSet(Hex(PeekB(*b + i), #PB_Byte), 2, "0")
Next i

Re: Hex 2 Binary

Posted: Fri May 15, 2020 10:38 am
by Mijikai

Re: Hex 2 Binary

Posted: Fri May 15, 2020 1:10 pm
by infratec
More cryptic, but faster:

Code: Select all

EnableExplicit

Procedure.i Hex2Mem(HexString$)
 
  Protected *Buffer, *b.BYTE, *c.Character, b.a
 
 
  *Buffer = AllocateMemory(Len(HexString$) / 2, #PB_Memory_NoClear)
  If *Buffer
    *b = *Buffer
    *c = @HexString$
   
    While *c\c
      b = *c\c - '0'
      If b > 9
        b - 7
        If b > 15
          b - 32
        EndIf
      EndIf
      *b\b  = b << 4
      *c + 2
     
      b = *c\c - '0'
      If b > 9
        b - 7
        If b > 15
          b - 32
        EndIf
      EndIf
      *b\b | b
      *c + 2
     
      *b + 1
    Wend
  EndIf
 
  ProcedureReturn *Buffer
 
EndProcedure


Define a$, *b

a$ = "4a1830010FFD8FFE000104A46494600010201004800480000FFE11CB24578696600004D4D0"
*b = Hex2Mem(a$)
If *b
  ShowMemoryViewer(*b, MemorySize(*b))
  FreeMemory(*b)
EndIf

Re: Hex 2 Binary

Posted: Fri May 15, 2020 1:51 pm
by NicTheQuick
If you want to use infratec's version keep in mind that it only works with uppercase letters in your HEX string.

Re: Hex 2 Binary

Posted: Fri May 15, 2020 1:57 pm
by infratec
updated the code above for lowercase letters too. :wink:

Re: Hex 2 Binary

Posted: Fri May 15, 2020 4:34 pm
by NicTheQuick
@infratec:
Do you like bit fiddling? I've got something for you:

Code: Select all

b = (*c\c | %100000) - '0' - (*c\c >> 6) * 39
It replaces all this:

Code: Select all

      b = *c\c - '0'
      If b > 9
        b - 7
        If b > 15
          b - 32
        EndIf
      EndIf
But I don't know if it is faster. It's just more fancy. :lol:

Edit:
Even better:

Code: Select all

b = (*c\c & %1111) + (*c\c >> 6) * 9

Re: Hex 2 Binary

Posted: Mon May 18, 2020 10:52 am
by Mijikai
My try:

Code: Select all

EnableExplicit

Procedure.i Hex2Bin(Input.s);upper case & unicode only!
  Protected *dat
  Protected *bin.Ascii
  Protected *str.Unicode
  Protected *cmp.Long
  Protected *tbl.Long
  Protected siz.i
  Protected pos.i
  siz = Len(Input)
  If siz
    If Not Mod(siz,2)
      siz >> 1
      *bin = AllocateMemory(siz)
      If *bin
        *dat = *bin
        *str = @Input
        *cmp = *str
        Repeat
          For pos = 0 To 255
            *tbl = ?hex2bin_table + (pos << 2)
            If *tbl\l = *cmp\l
              *bin\a = pos
              *bin + 1
              Break
            EndIf
          Next
          *str + 2
          *cmp + 4
        Until *str\u = #Null
      EndIf
    EndIf
  EndIf
  If *dat 
    If (*bin - *dat) = siz
      ProcedureReturn *dat
    Else
      FreeMemory(*dat)
      ProcedureReturn #Null
    EndIf
  EndIf
  ProcedureReturn #Null
  hex2bin_table:
  !du '00','01','02','03','04','05','06','07','08','09','0A','0B','0C','0D','0E','0F'
  !du '10','11','12','13','14','15','16','17','18','19','1A','1B','1C','1D','1E','1F'
  !du '20','21','22','23','24','25','26','27','28','29','2A','2B','2C','2D','2E','2F'
  !du '30','31','32','33','34','35','36','37','38','39','3A','3B','3C','3D','3E','3F'
  !du '40','41','42','43','44','45','46','47','48','49','4A','4B','4C','4D','4E','4F'
  !du '50','51','52','53','54','55','56','57','58','59','5A','5B','5C','5D','5E','5F'
  !du '60','61','62','63','64','65','66','67','68','69','6A','6B','6C','6D','6E','6F'
  !du '70','71','72','73','74','75','76','77','78','79','7A','7B','7C','7D','7E','7F'
  !du '80','81','82','83','84','85','86','87','88','89','8A','8B','8C','8D','8E','8F'
  !du '90','91','92','93','94','95','96','97','98','99','9A','9B','9C','9D','9E','9F'
  !du 'A0','A1','A2','A3','A4','A5','A6','A7','A8','A9','AA','AB','AC','AD','AE','AF'
  !du 'B0','B1','B2','B3','B4','B5','B6','B7','B8','B9','BA','BB','BC','BD','BE','BF'
  !du 'C0','C1','C2','C3','C4','C5','C6','C7','C8','C9','CA','CB','CC','CD','CE','CF'
  !du 'D0','D1','D2','D3','D4','D5','D6','D7','D8','D9','DA','DB','DC','DD','DE','DF'
  !du 'E0','E1','E2','E3','E4','E5','E6','E7','E8','E9','EA','EB','EC','ED','EE','EF'
  !du 'F0','F1','F2','F3','F4','F5','F6','F7','F8','F9','FA','FB','FC','FD','FE','FF'
EndProcedure

Global hstr.s = "FF0001"
Global *binary

*binary = Hex2Bin(hstr)

If *binary
  ShowMemoryViewer(*binary,MemorySize(*binary))
EndIf

End
The code also checks if in- and output is valid.

Re: Hex 2 Binary

Posted: Mon May 18, 2020 11:31 am
by NicTheQuick
@Mijikai: Without testing it I assume that your method will be a lot slower because you do a For-loop for every byte, so the worst case scenario makes will loop 256 times by byte and on average 128 times which is still too much.

Re: Hex 2 Binary

Posted: Mon May 18, 2020 1:50 pm
by JagV12
I love "*b.BYTE, *c.Character" declaration and *c\c and *b\b usage but didn't know about it. The role is obvious here but is there a place I should read to learn more about it ?

Re: Hex 2 Binary

Posted: Mon May 18, 2020 5:13 pm
by breeze4me
2 asm procedures and 1 PB procedure.

Code: Select all

Procedure IsValidHexString(*HexSrting.Character)
  
  If MemoryStringLength(*HexSrting, #PB_Unicode) % 2 Or *HexSrting = 0
    ProcedureReturn 0
  EndIf
  
  While *HexSrting\c
    If *HexSrting\c > 'f' Or *HexSrting\c < '0'
      ProcedureReturn 0
    EndIf
    
    If *HexSrting\c > '9' And *HexSrting\c < 'A'
      ProcedureReturn 0
    EndIf
    
    If *HexSrting\c > 'F' And *HexSrting\c < 'a'
      ProcedureReturn 0
    EndIf
    
    *HexSrting + SizeOf(Character)
  Wend
  
  ProcedureReturn 1
EndProcedure

Procedure HexStringToBinData_ASM1(*InHexSrting, *OutBinData)
  CompilerIf Not #PB_Compiler_InlineAssembly
    EnableASM
    ___temp___:
  CompilerEndIf
  
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    MOV edx, *OutBinData
    MOV eax, *InHexSrting
  CompilerElse
    MOV rdx, *OutBinData
    MOV rax, *InHexSrting
  CompilerEndIf
  
  CompilerIf Defined(___temp___, #PB_Label)
    DisableASM
  CompilerEndIf
  
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    !PUSH ebx
    !PUSH esi
    !PUSH edi
    !MOV edi, 9
    
    !@@:
    ;1st character
    !MOVZX ebx, word [eax]
    !TEST ebx, ebx
    !JZ @f
    
    ;(c & %1111) + (c >> 6) * 9
    !XOR ecx, ecx
    !TEST ebx, 0x40
    !CMOVNZ ecx, edi
    !ADD ebx, ecx
    
    !SHL ebx, 4
    
    ;2nd character
    !MOVZX esi, word [eax + 2]
    
    ;(c & %1111) + (c >> 6) * 9
    !XOR ecx, ecx
    !TEST esi, 0x40
    !CMOVNZ ecx, edi
    !AND esi, 0x0F
    !ADD esi, ecx
    
    !OR ebx, esi
    
    ;save the combined value to *OutBinData
    !MOV byte [edx], bl
    
    ;for the next 2 characters
    !ADD eax, 4
    !ADD edx, 1
    !JMP @r
    
    !@@:
    !POP edi
    !POP esi
    !POP ebx
    
  CompilerElse  ;x64
    !PUSH rbx
    !MOV r9, 9
    
    !@@:
    ;1st character
    !MOVZX rbx, word [rax]
    !TEST ebx, ebx
    !JZ @f
    
    ;(c & %1111) + (c >> 6) * 9
    !XOR rcx, rcx
    !TEST ebx, 0x40
    !CMOVNZ rcx, r9
    !ADD ebx, ecx
    
    !SHL ebx, 4
    
    ;2nd character
    !MOVZX r8, word [rax + 2]
    
    ;(c & %1111) + (c >> 6) * 9
    !XOR rcx, rcx
    !TEST r8, 0x40
    !CMOVNZ rcx, r9
    !AND r8, 0x0F
    !ADD r8, rcx
    
    !OR rbx, r8
    
    ;save the combined value to *OutBinData
    !MOV byte [rdx], bl
    
    ;for the next 2 characters
    !ADD rax, 4
    !ADD rdx, 1
    !JMP @r
    
    !@@:
    !POP rbx
  CompilerEndIf
  
  ProcedureReturn
EndProcedure

Procedure HexStringToBinData_ASM2(*InHexSrting, *OutBinData)
  CompilerIf Not #PB_Compiler_InlineAssembly
    EnableASM
    ___temp___:
  CompilerEndIf
  
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    MOV ecx, *InHexSrting
    MOV edx, *OutBinData
  CompilerElse
    MOV rcx, *InHexSrting
    MOV rdx, *OutBinData
  CompilerEndIf
  
  CompilerIf Defined(___temp___, #PB_Label)
    DisableASM
  CompilerEndIf
  
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    !PUSH esi
    !PUSH ebx
    
    !MOV ebx, ___lb_HexTable
    
    !@@:
    ;1st character
    !MOVZX eax, word [ecx]
    !TEST eax, eax
    !JZ @f
    
    !XLATB
    !SHL eax, 4
    !MOV esi, eax
    
    ;2nd character
    !MOVZX eax, word [ecx + 2]
    
    !XLATB
    !OR eax, esi
    
    ;save the combined value to *OutBinData
    !MOV byte [edx], al
    
    ;for the next 2 characters
    !ADD ecx, 4
    !ADD edx, 1
    !JMP @r
    
    !@@:
    !POP ebx
    !POP esi
    
  CompilerElse  ;x64
    !MOV r9, ___lb_HexTable
    
    !@@:
    ;1st character
    !MOVZX rax, word [rcx]
    !TEST eax, eax
    !JZ @f
    
    !MOV al, byte [r9 + rax]
    !SHL eax, 4
    !MOV r8, rax
    
    ;2nd character
    !MOVZX rax, word [rcx + 2]
    
    !MOV al, byte [r9 + rax]
    !OR rax, r8
    
    ;save the combined value to *OutBinData
    !MOV byte [rdx], al
    
    ;for the next 2 characters
    !ADD rcx, 4
    !ADD rdx, 1
    !JMP @r
    
    !@@:
  CompilerEndIf
  
  ProcedureReturn
EndProcedure

Procedure HexStringToBinData_PB(*InHexSrting.Character, *OutBinData.Byte)
  
  Structure ByteArray
    b.b[0]
  EndStructure
  
  Protected *Table.ByteArray = ?___lb_HexTable
  Protected v
  
  While *InHexSrting\c
    
    v = *InHexSrting\c
    *InHexSrting + 2
    
    *OutBinData\b = (*Table\b[v] << 4) | *Table\b[*InHexSrting\c]
    
    *InHexSrting + 2
    *OutBinData + 1
  Wend
  
  ProcedureReturn
EndProcedure

DataSection
  ___lb_HexTable:
  !___lb_HexTable:
  Data.q 0, 0, 0, 0, 0, 0
  Data.b 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  Data.b 0, 0, 0, 0, 0, 0, 0
  Data.b 10, 11, 12, 13, 14, 15
  Data.q 0, 0, 0
  Data.b 0, 0
  Data.b 10, 11, 12, 13, 14, 15
EndDataSection



*m = AllocateMemory(10240)
FillMemory(*m, 1024, $11)

a$ = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F" +
     "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F" +
     "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF" +
     "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF" +
     "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
     "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" +
     "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf" +
     "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"


If IsValidHexString(@a$)
  
  ;HexStringToBinData_ASM1(@a$, *m)
  ;HexStringToBinData_ASM2(@a$, *m)
  HexStringToBinData_PB(@a$, *m)
  
  ShowMemoryViewer(*m, 1024)
  
EndIf
[/size]


Edit: a bug is fixed.
!MOVZX rbx, word [eax] --> !MOVZX rbx, word [rax]
:mrgreen:

Re: Hex 2 Binary

Posted: Mon May 18, 2020 6:47 pm
by mk-soft
I love "*b.BYTE, *c.Character" declaration and *c\c and *b\b usage but didn't know about it. The role is obvious here but is there a place I should read to learn more about it ?
Is top secret ...

Not find in PB help

Re: Hex 2 Binary

Posted: Mon May 18, 2020 6:58 pm
by infratec
I'm a whisteblower :wink:

You can define structures as you want.
The (hidden) point is:
The structures for the basic variable types (Character, Integer, Byte ...) are already defined.

Code: Select all

Structure ByteStructue
  byte.a
EndStructure


Define Long.l, i.i
Define *Byte.ByteStructue

Long = $12345678

*Byte = @Long
For i = 0 To 3
  Debug Hex(*Byte\byte)
  *Byte + 1
Next i