Monday, 6 April 2009

File attachment and Infopath 2003 SP1

We have been working on a small project using Infopath 2003 and MOSS to create a faster way to input information in a list. Among the challenges (which was quite a few despite it was software from MS on both "sides") faced was how to enable uploading a file while submitting information to a list.

Infopath 2003 provides a File Attachment Control which enables the end-user to select and attach a file to the form. Infopath automatically encodes the file in Base64 and adds a dynamic header in the front of the file. So we wanted to use the "AddAttachment" web service available to post the file, one of the parameters is a Base64 encoded string. Great! Well, the header added by Infopath is also included in the encoding. We only have Jscript or VBScript to use in Infopath 2003 if we don´t want to start to deploy extra code on the clients (which I try to prefer to stay away from) and the support for decoding/encoding files in those languages are not to great.

So our solution is to extract the filename from the header (code below) and the attach a list item event receiver for "ItemAttachmentAdded" which decode the file, removes the header and saves the file again serverside.

Here is the code for extracting the filename from an Infopath Base64 encoded attachment:

dim node

Set node = XDocument.DOM.documentElement.selectSingleNode("/my:myFields/my:FileAttchmentControl")

If(node.text <> "") Then

'typecast the node to base64 as Infopath doesn't do this in node definition

node.DataType = "bin.base64"

'convert base64 node value to binary and store in nodeValue byte array

nodeValue = node.nodeTypedValue

dim convertByteArrayToHexString

convertByteArrayToHexString = ""

For intCounter = 1 to LenB(nodeValue)

convertByteArrayToHexString = convertByteArrayToHexString & Right("0" & Hex(AscB(MidB(nodeValue, intCounter, 1))), 2)

If(intCounter = 100) Then 'Assuming that the header is no longer that 100 bytes
exit for
end if


dim filenameBuffer
dim filename
filename = ""
filenameBuffer = 0

'The length of the filenamebuffer is stored on pos 20-24 (byte), which means 41.47 in Hex and 1 as startpos for Arrays

filenameBuffer = getFilenameBuffer(convertByteArrayToHexString,41,47)

'Read the filename from position (49 to filenamebuffer * unicode - "\n") as end char

filename = getFileName(convertByteArrayToHexString,49,filenameBuffer*4 + 49 - 2)

Function getFilenameBuffer(data,startLoop,stopLoop)
dim k

dim filenameBuffer

for k = startLoop to stopLoop step 2

dim y1
dim y2
dim y3

y1 = Mid(data,k,2)
y2 = CLng("&h" & y1)
y3 = y3 + Int(y2)

filenameBuffer = y3


getFilenameBuffer = filenameBuffer

End Function

Function getFileName(data,startLoop, stopLoop)
dim k

dim filename

for k = startLoop to stopLoop step 4

dim h1
dim h2
dim h3

h1 = Mid(data,k,2)
h2 = CLng("&h" & h1)
h3 = Chr(h2)

if(h3 <> "") then
filename = filename & Cstr(h3)
end if


getFileName = filename
End Function

No comments: