MemoryBlock to Xojo.Core.MemoryBlock conversion?

Hi folks,

I’m trying to upload a file to a web service using the new framework and am running into a few issues trying to port code from an HTTPSocket example to the new framework to use http 1.1.

I’ve got the following method which seems to do most of what I need (please excuse poor error checking etc, as it’s still a work in progress). Basically, I pass a socket, dictionary and string to it, and in the current state all content I pass through is correctly parsed and put into the mbData memory block.

The part that I’m struggling with is getting the data from the postContent binary stream into the postData xojo.core.memoryblock to send to the web service. I’ve read the documentation and some of the posts on the forum, but am unsure of how to convert the data into the required format. Any help appreciated.

SetFormData(sock as Xojo.net.HTTPSocket, FormData As Dictionary, Boundary As String)
  If Boundary.Trim = "" Then
    Boundary = "--" + Right(EncodeHex(MD5(Str(Microseconds))), 24) + "--bndry"
  End If
  
  Static CRLF As String = EndOfLine.Windows
  
  Dim mbData As New MemoryBlock(0)
  Dim postContent As New BinaryStream(mbData)
  
  For Each key As String In FormData.Keys
    postContent.Write("--" + Boundary + CRLF)
    If VarType(FormData.Value(Key)) = Variant.TypeString Then
      postContent.Write("Content-Disposition: form-data; name=""" + key + """" + CRLF + CRLF)
      postContent.Write(FormData.Value(key) + CRLF)
    ElseIf FormData.Value(Key) IsA FolderItem Then
      Dim file As FolderItem = FormData.Value(key)
      postContent.Write("Content-Disposition: form-data; name=""" + key + """; filename=""" + File.DisplayName + """" + CRLF)
      postContent.Write("Content-Type: application/octet-stream" + CRLF + CRLF) ' replace with actual MIME Type
      Dim bs As BinaryStream = BinaryStream.Open(File)
      postContent.Write(bs.Read(bs.Length) + CRLF)
      bs.Close
    End If
  Next
  postContent.Write("--" + Boundary + "--" + CRLF)
  
  Dim mbpostData as xojo.Core.MemoryBlock
  Dim postData As New xojo.Core.MemoryBlock(mbpostData)
  
  'Convert MB to X.C.MB?
  
  postContent.Close
  
  sock.SetRequestContent(postData, "application/x-www-form-urlencoded; boundary=" + Boundary.ToText) 
  'Change mime type as required
  sock.Send("POST", "https://www.virustotal.com/vtapi/v2/file/scan")

Loop byte-by-byte:

Dim Clone As New Xojo.Core.MutableMemoryBlock(Source.Size) Clone.LittleEndian = Source.LittleEndian For I As Integer = 0 To Source.Size - 1 Clone.UInt8Value(I) = Source.UInt8Value(I) Next

Thank you Thom, that worked perfectly, much appreciated.

This is probably faster:

  dim nmb as new Xojo.Core.MemoryBlock( mb )
  nmb = nmb.Left( mb.Size )

[quote=295033:@Kem Tekinay]This is probably faster:

dim nmb as new Xojo.Core.MemoryBlock( mb ) nmb = nmb.Left( mb.Size ) [/quote]
Kem, can you explain your code? It doesn’t make any sense to me, let alone within the question’s context.

I might have misunderstood. The question was how to copy data from a classic MemoryBlock to a Xojo.Core.MemoryBlock, yes?

A Constructor for Xojo.Core.MemoryBlock will take a Ptr, and the classic MemoryBlock auto-converts to Ptr. But a MemoryBlock created from a pointer has an undetermined size, so Left copies the data from that Pointer as a new Xojo.Core.MemoryBlock.

But if I did misunderstand, I’ve successfully answered a different question. :slight_smile:

That’s exactly the goal. The code is just very unintuitive. Even knowing the goal, I couldn’t see what it was doing.

Thank you both - both ways work exactly as needed. :slight_smile:

From your code above: do you really need to copy from the “classic” memory block to the “Xojo.Core” one? If not, you can create a “Xojo.Core” memory block pointing to the same memory of the “classic” one:

Dim nmb As New Xojo.Core.MemoryBlock(mb, ms.Size)

I didn’t realize (or remember) that version of the Constructor, but here’s the “gotcha” with doing it that way: the new MemoryBlock points to the memory held by the original, classic MemoryBlock. If that goes out of scope, the data is lost. For example, just to illustrate:

dim nmb as Xojo.Core.MemoryBlock
if true then // scope
  dim mb as MemoryBlock = "some string"
  nmb = new Xojo.Core.MemoryBlock( mb, mb.Size )
  // nmb looks good at this point
end if

// nmb now "contains" garbage since mb went out of scope

This is another example:

Dim mb As MemoryBlock = "abcdef" Dim nmb As New Xojo.Core.MemoryBlock(mb, mb.Size) mb = Nil // nmb is now garbage
I wasn’t aware of that. I thought memory blocks were like classes reference-counted.

[quote=295082:@Eli Ott]This is another example:

Dim mb As MemoryBlock = "abcdef" Dim nmb As New Xojo.Core.MemoryBlock(mb, mb.Size) mb = Nil // nmb is now garbage
I wasn’t aware of that. I thought memory blocks were like classes reference-counted.[/quote]
They are, but the constructor is for a pointer to the original. If the original goes away, the pointer is wrong.

In Kem’s first example, he creates a new memoryblock from the data returned by the pointer. That’s the nmb = nmb.Left line.

It seems that Xojo.Core.MemoryBlocks are reference-counted among themselves, and classic ones among themselves:

[code] Dim nmb As Xojo.Core.MutableMemoryBlock

If True Then
Dim mb As New Xojo.Core.MutableMemoryBlock(7)
mb.CStringValue(0) = “abcdef”
nmb = mb
mb = Nil
End

MsgBox nmb.CStringValue(0) // shows “abcdef”[/code]
Same for classic ones.

Slightly off-topic, but you should use “multipart/form-data” as the content type instead of “application/x-www-form-urlencoded”.

But try that with the same Constructor, i.e…

...
nmb = new Xojo.Core.MemoryBlock( mb.Data, mb.Size )
...

Just guessing, but I bet you’ll again end up with invalid data after the if block ends. I don’t think the pointers are being reference-counted.