PeekHexBytes() and PokeHexBytes()

Share your advanced PureBasic knowledge/code with the community.
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: PeekHexBytes() and PokeHexBytes()

Post by Little John »

Oops :oops: => done now.
yrreti, thanks for telling me!

Regards, Little John
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: PeekHexBytes() and PokeHexBytes()

Post by SFSxOI »

is your first post in this thread the most current?
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: PeekHexBytes() and PokeHexBytes()

Post by Little John »

No, at the moment it isn't.

Trond came up with some code for poking, which I like very much. It is simpler and more flexible than the code I wrote so far. Based on his code, this post contains my most recent version (complete code in the 2nd code block of that post). As far as I can see, everything is fine with it. But I consider it a draft at the moment, since I wouldn't be surprised if Trond comes up with more improvements. :-) So at the moment I'm waiting for his reply. In a few days, I'll probably put my final version into the first post.
Thanks for your interest.

Regards, Little John
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: PeekHexBytes() and PokeHexBytes()

Post by Trond »

There is a problem with your input verification, it accepts illegal characters:

Code: Select all

For i = 15 To 26
  c = i
  c | %00100000
  If c < '0' Or (c > '9' And (c < 'a' Or c > 'f'))
    Debug "Failed input: " + Chr(i)
  Else
    Debug "Accepted input: " + Chr(i) + " (thought to be " + Chr(c) + ")"
  EndIf
Next
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: PeekHexBytes() and PokeHexBytes()

Post by Trond »

This should be relatively bullet-proof, it return the number of bytes written. It also accept a single character as a hex number (so you don't need to pad with 0 first), but rejects three hex digits in a row.

Code: Select all

Procedure _GetString(*M.Character, S.s)
  l = StringByteLength(S)
  If CompareMemory(*M, @S, L)
    ProcedureReturn *M+l
  EndIf
  ProcedureReturn *M
EndProcedure

Procedure IsHexChar(*Source.Character)
  Select *Source\c
    Case '0' To '9', 'A' To 'Z', 'a' To 'z'
      ProcedureReturn 1
  EndSelect
EndProcedure

Procedure _GetHexLength(*Source)
  If IsHexChar(*Source)
    If IsHexChar(*Source+SizeOf(Character))
      If IsHexChar(*Source+2*SizeOf(Character))
        ProcedureReturn 0 ; Error in input
      EndIf
      ProcedureReturn 2
    EndIf
    ProcedureReturn 1
  EndIf
EndProcedure

; Return number of bytes written
Procedure.i PokeHexBytes(*Dest.Ascii, Bytelist.s, Separator.s = "", Prefix.s = "")
  Protected *Source.Character = @Bytelist
  Protected *OrigDest = *Dest
  While *Source\c
    *Source = _GetString(*Source, Prefix)
    HexL = _GetHexLength(*Source)
    If HexL = 0
      Break
    EndIf
    PokeA(*Dest, Val("$" + PeekS(*Source, HexL)))
    *Source + HexL * SizeOf(Character)
    *Dest + 1
    *Source = _GetString(*Source, separator)
  Wend
  ProcedureReturn *Dest - *OrigDest
EndProcedure
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: PeekHexBytes() and PokeHexBytes()

Post by Little John »

Trond wrote:There is a problem with your input verification, it accepts illegal characters:
Oops :oops: I'm making so many stupid mistakes lately ... Thanks again!
I think I'll use the following instead:

Code: Select all

Macro CheckHexDigit ()
   Select *source\c
   Case '0' To '9', 'A' To 'F', 'a' To 'f'
      ; OK, do nothing
   Default      
      ProcedureReturn 0  ; error
   EndSelect
   *source + SizeOf(Character)
EndMacro
Trond wrote:This should be relatively bullet-proof, it return the number of bytes written. It also accept a single character as a hex number (so you don't need to pad with 0 first), but rejects three hex digits in a row.
My procedure returns the number of written bytes only on success, and 0 otherwise. I like to get a clear indicator in case of an error (-1 instead of 0 might be better, since poking "" is not really an error, and will also return 0.) Accepting a single character as a hex number is not what I personally want.

In your code, every time when _GetString() is called, it calles StringByteLength(S). This is not necessary, because S is either the separator or the prefix, and the lengths of both do not change during runtime of the procedure PokeHexBytes(). That's why I changed the code, so that both lengths are determined only once at the beginning, and then passed as parameter.

Regards, Little John
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: PeekHexBytes() and PokeHexBytes()

Post by Trond »

That's why I changed the code, so that both lengths are determined only once at the beginning, and then passed as parameter.
I understand, I just worked on my own code because that was simplest to me.

Now it returns -1 on failure each byte must be exactly two hex characters, but I didn't test it so buyer beware!

Code: Select all

Macro SkipString (_s_, _length_)
  If CompareMemory(*Source, @_s_, _length_)
    *source + _length_
  EndIf
EndMacro

Procedure IsHexChar(*Source.Character)
  Select *Source\c
    Case '0' To '9', 'A' To 'Z', 'a' To 'z'
      ProcedureReturn 1
  EndSelect
EndProcedure

; Return number of bytes written or -1 on failure
Procedure.i PokeHexBytes(*Dest.Ascii, Bytelist.s, Separator.s = "", Prefix.s = "")
  Protected *Source.Character = @Bytelist
  Protected *OrigDest = *Dest
  Protected lenPre = StringByteLength(Prefix)
  Protected lenSep = StringByteLength(Separator)
  While *Source\c
    SkipString(Prefix, lenPre)
    If IsHexChar(*Source) And IsHexChar(*Source+SizeOf(Character))
      PokeA(*Dest, Val("$" + PeekS(*Source, 2)))
      *Source + 2 * SizeOf(Character)
      *Dest   + 1
      SkipString(Separator, lenSep)
    Else
      ProcedureReturn -1
    EndIf
  Wend
  ProcedureReturn *Dest - *OrigDest
EndProcedure
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: PeekHexBytes() and PokeHexBytes()

Post by Rescator »

Heh, amusing that the routines are starting to ressemble mine a lot more :P

PS! Trond you'll get a speed gain if you unroll the procedure in the loop instead as calling the procedure has a higher overhead (stack etc.) than having repeating code (which modern CPUs do optimize for as well).
Then again my source has a bit too much branching and could probably be redone to get rid of half those ifelse.
You could probably speed up things a lot more by simply only acting on data you expect (ignoring anything else) rather than explicitly skipping and comparing things,
at least that was the idea behind the source I quickly threw together earlier.

My source also avoids PokeA() Val() PeekS() which has varying overheads, using direct reference like *string.Character and then using just *sting\c is the fastest way to do it in PureBasic (besides asm I believe).

In any case it's amusing seeing this kind of community collaboration on making the "ultimate" Hex Peek/poke routines. :P
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: PeekHexBytes() and PokeHexBytes()

Post by Little John »

Please see first post for new code. Trond, thanks again!

Regards, Little John
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: PeekHexBytes() and PokeHexBytes()

Post by SFSxOI »

Thanks a lot, works fine here on Windows 7 Ultimate x86 and with PB 4.50 :)
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
Post Reply