encodeHex(memoryBlock)

In the old framework, you could use:

encodeHex(memoryBlock)

to display the hex values of each individual byte of the memoryblock. Is there a simple way to do this with the new xojo.core.memoryBlock? I’m trying to use variations of datatotext, but just can’t seem to get it right. It’s probably simple, and I’m just roadblocked by my inexperience with the new framework. I’m tryin’… and any help is appreciated. Thanks!

BTW, need to be able to do this without looping through the byte position of the memoryblock… as that would be extremely slow for what I need done. Also, the memoryblock will not always contain text data… so I can’t use encodeHex(textencoding.#.convertDataToText), as it would throw an error.

[code] dim s as string = “Here comes the sun…”+chr(0)
dim t as text = s.ToText

Dim utf8Data As Xojo.Core.MemoryBlock
utf8Data = Xojo.Core.TextEncoding.UTF8.ConvertTextToData(t)

msgbox encodehex(replace(utf8Data.CStringValue(0),chr(0),""))[/code]

Michel,

That approach doesn’t work… I tried. The memoryBlock that I want to encodeHex contains bitWise.bitXor data between two other sets of memoryBlocks, so its contents aren’t always something that can be converted using the textencoding. Trust me, I’ve tried. :frowning:

[quote=183700:@Eric Brown]Michel,

That approach doesn’t work… I tried. The memoryBlock that I want to encodeHex contains bitWise.bitXor data between two other sets of memoryBlocks, so its contents aren’t always something that can be converted using the textencoding. Trust me, I’ve tried. :([/quote]

Your question was how to encodeHex a Xojo.Core.MemoryBlock, and that is exactly what the very last line of the code I posted does.

All the other lines except maybe for the first one that adds a Chr(0) to avoid an OutOfBounds exception upon retrieval, are just here to create the Xojo.Core.memoryBlock. I should just have removed them, since you seem to get stuck in them.

Now another example, that has nothing to do with TextEncoding, still with the very last line that was the only one really replying to your question :

[code] Dim bytes() As Byte
for i as integer = 1 to 200
bytes.Append(max(Rnd*255,1))
next
bytes.Append(0)

Dim b As New Xojo.Core.MemoryBlock(bytes)

msgbox encodehex(replace(b.CStringValue(0),chr(0),""))[/code]

This creates a Xojo.Core.MemoryBlock with non Text convertible data. The only limitation of that method is that since it uses a termination null character, the data itself cannot contain it.

Since there is no way to get a stringvalue other than CString or WString from a Xojo.Core.MemoryBlock, the only way I can think of to obtain a string containing null characters would be to create an old MemoryBlock from the Xojo.Core.MemoryBlock using its PtrValue. But then, why bother at all with the new framework…

I believe the “proper” way to get a string with null characters in it from a Xojo.Core.MemoryBlock is to use Int32Value sequentially, but that is precisely what you explicitly said you did not want to do.

If your app is not an iOS app, I would tend to think the new framework is not the best way to get what you want…

Aye, appreciate the feedback and assistance, Michel. If the old framework works best, I’ll use it. I’m just not keen on relying on something that will someday (if not soon) no longer be there. I’m sure the old framework will eventually be depreciated. This is the only reason I’m moving as much over to the new one as possible… that and learning it, of course.

BTW, your suggestion worked like a charm… thanks.

I understand. The thing is at the moment, and maybe still for a good while to come, Xojo engineers simply do not want the String data type to be associated in any way with the new framework, so we are stuck with TextEncoding that cannot deal with control characters, so the old encodeHex cannot be used. Using CStringValue is probably already considered a hack by purists.

As I said, the “proper” way would be sequential, but here is the way to find the price to pay for the “proper” way :

[code]Dim bytes() As Byte
for i as integer = 1 to 200000
bytes.Append(max(Rnd*255,1))
next
bytes.Append(0)

Dim b As New Xojo.Core.MemoryBlock(bytes)

dim oldMics as double = Microseconds
Dim HexVal as string
for i as integer = 0 to b.Size-1
HexVal = HexVal+b.UInt8Value(i).ToHex
next
dim hv1 as double = Microseconds-oldMics
OldMics = Microseconds
Dim HexVal2 as string = encodehex(replace(b.CStringValue(0),chr(0),“”))
dim hv2 as double = Microseconds-oldMics

msgbox “Sequential : “+format(hv1,”###,###”)+EndOfLine+“CString : “+format(hv2,”###,###”)[/code]

Sequential : 2,995,879 Microseconds
CString : 2,610 Microseconds

If speed is your concern, the new framework is not what you want to do. I know we all fear the great deprecation, when the sky is going to fall, but moving prematurely to a framework that is not able to deliver what you need is, IMHO, not

… a wise move.

(Hit return by mistake and of course Edit chose not to work. Sorry)

This is really slow, you should append to an array then join after the loop. Actually, since the size is known you can presize and assign instead of append. Also, I haven’t measured the new framework, but in the old, accessing data through a Ptr is faster than Memoryblock. So “dim p As Ptr = b” then use p in the loop might help. And you can precalculate a list of all 2 byte mappings then lookup from that instead. Saves calling ToHex and is half the amount of Ptr accesses (because 2 bytes at a time).

You are quite right.The array plus join is way faster than the concatenation.

This gives 259,259 Microseconds instead of 2,995,879 Microseconds

Dim HexVal(-1) as string for i as integer = 0 to b.Size-1 HexVal.append(b.UInt8Value(i).ToHex) next dim result as string = join(HexVal,"") dim hv1 as double = Microseconds-oldMics OldMics = Microseconds

It still remains way slower than the CString way, though.

I am not too sure about what you mean by accessing through a Ptr, though. Dim p as Ptr = Xojo.Core.MemoryBlock.PtrValue(0) is probably the equivalent of the old dim p As Ptr = b but how do you “use p in a loop” to obtain a string ?

“dim p As Ptr = b.PtrValue(0)” returns the first 4 bytes of the Memoryblock as a Ptr.

“dim p As Ptr = b” puts the address of the Memoryblock into the Ptr. Then, the Ptr type has most of the accessor methods Memoryblock does, UInt32, Int16 etc and it acts like another view on the data, just a bit faster. So something like this

dim p As Ptr = b for i as integer = 0 to b.Size-1 HexVal.append(p.UInt8(i).ToHex) next
I don’t think there will be much speed up from that though. Using a lookup array and stepping 2 bytes at a time might have more impact, but probably not the 100x faster it needs to be to rival your Cstring technique.

[quote=183720:@Will Shank]“dim p As Ptr = b.PtrValue(0)” returns the first 4 bytes of the Memoryblock as a Ptr.

“dim p As Ptr = b” puts the address of the Memoryblock into the Ptr. Then, the Ptr type has most of the accessor methods Memoryblock does, UInt32, Int16 etc and it acts like another view on the data, just a bit faster. So something like this

dim p As Ptr = b for i as integer = 0 to b.Size-1 HexVal.append(p.UInt8(i).ToHex) next
I don’t think there will be much speed up from that though. Using a lookup array and stepping 2 bytes at a time might have more impact, but probably not the 100x faster it needs to be to rival your Cstring technique.[/quote]

Unfortunately, dim p As Ptr = b simply does not work for Xojo.Core.MemoryBlock.

It would be great if Xojo engineers, in the great wisdom, allowed us mere mortals, something like Xojo.Core.MemoryBlock.HexValue(). Maybe in this holy time of XDC such a wish would be granted ?

[quote=183718:@Michel Bujardet]

Dim HexVal(-1) as string for i as integer = 0 to b.Size-1 HexVal.append(b.UInt8Value(i).ToHex) next dim result as string = join(HexVal,"") dim hv1 as double = Microseconds-oldMics OldMics = Microseconds[/quote]

I ended up having to go with something similar to this, due to the fact that the memoryBlock I was using was a XoR of two other memoryBlocks… and the potential for a ‘0’ value besides the one we appended to keep the OutOfBounds from happening we not impossible (or any other value we would’ve used).

This can’t be right!? I mean you’re right that that doesn’t work but it should I think. From the new docs… http://developer.xojo.com/ptr

[quote]Ptr (Data Type)
A pointer to a chunk of memory. You can pass a MemoryBlock object using this data type and it will be treated as a pointer to the memory contained within the MemoryBlock.[/quote]
Casting Memoryblock to Ptr is essential for so many declares, so it must be possible somehow but I can’t find it.

Oh OK. Memoryblock doesn’t implicitly cast to Ptr anymore, it’s

dim p As Ptr = b.Data

Here’s a version using a 2 byte lookup map thats about 9-10x faster than ToHexing each byte.

In building the map i.ToHex(4) is flipping the bytes on my little endian mac so there’s a little extra work to flip that back around. Maybe on big endian machines that shouldn’t be done.

I tried some variations like Appending vs assigning and scaling the index vs assigning and incrementing the index. Scaling seemed to be the faster but not always, times would jump around but they’re all pretty close. Also Text vs String didn’t make a measurable difference, they ping-ponged times too.

The first time called there’s overhead in building the map so time a second call.

Function MemToHex(mem As Xojo.Core.MemoryBlock) As Text
  if mem = nil or mem.Size < 1 then return ""
  
  static map() As Text   //prebuild lookup
  if map.Ubound < 0 then
    redim map(65535)
    dim s As Text
    for i As integer = 0 to 65535
      s = i.ToHex(4)
      map(i) = s.Right(2) + s.Left(2)
    next
  end
  
  dim dingle As integer = mem.Size mod 2      //even 0, odd 1
  dim last As integer = (mem.Size - 2) \\ 2    //last 2 byte index to lookup
  dim elem As integer = last + dingle         //last array index
  
  dim r() As Text  //result array, presized
  redim r(elem)
  
  dim p As Ptr = mem.Data        //quicker view
  for i As integer = 0 to last   //map each 2 byte value
    r(i) = map( p.UInt16(i*2) ) 
  next
  
  if dingle = 1 then r(elem) = p.UInt8(mem.Size-1).ToHex(2)  //add possible trailing byte
  
  return Text.Join(r, "")
  
End Function

Hi, I know I am digging this thread up :slight_smile:
This code works well and very fast for me, I use it to insert metafile pictures in rtf text (Richedit) :

[code] ’ Convert MemoryBlock mDataIn into Hex String
Dim pDataIn As Ptr = mDataIn
Dim nSizeOut As Integer

Declare Function CryptBinaryToString Lib “crypt32.dll” Alias “CryptBinaryToStringA” _
(ByVal pbBinary As ptr, ByVal cbBinary As Integer, ByVal dwFlags As Integer, _
ByVal pcchString As Ptr, ByRef pSizeStringOut As Integer) As Integer
Const CRYPT_STRING_HEXRAW = &Hc

’ Get Size
ret = CryptBinaryToString (pDataIn, mDataIn.Size, CRYPT_STRING_HEXRAW, Nil, nSizeOut)
If (ret = 0) Or (nSizeOut <=0) Then
Return
End If
nSizeOut = nSizeOut - 1 ’ we don’t want an ending chr(0)

Dim mHexStringOut As New MemoryBlock (nSizeOut)
Dim pHexStringOut As Ptr = mHexStringOut
ret = CryptBinaryToString (pData, nSize, CRYPT_STRING_HEXRAW, pHexStringOut, nSizeOut)

MyBinaryStream.Write mHexStringOut
’ or
MyString = mStringOut

’ Clean
mHexStringOut = Nil
mDataIn = Nil[/code]