Accessing InfoPath File Attachments in code

Welcome to my first SharePoint-blog! I can't image life as a programmer without the millions and millions of interesting posts on the internet that helped me reach my goals time after time. Since this helped me a lot, time has come to do my part of the share...hopefully I can provide you with some interesting posts as I learn more about SharePoint! Here we go!

The latest project I have been working on required some InfoPath forms processing: once a form was stored in a SharePoint library an EventReceiver needed to process the XML and send an e-mail with a summary of the InfoPath fields. Nothing special, I hear you think...indeed nothing special if it wasn't for the file attachments in the form. Somehow these needed to be converted from a meaningless string back to a file.

If you take a look at the XML that InfoPath produces for the XML file, you'll notice the tag contains one big base64 encoded string. But decoding the string is not enough to extract the file: upon attaching a file InfoPath builds a header which has the following structure:

SizeContents
0: 4 bytes [DECIMAL]199, 73, 70, 65
4: DWORD (4 bytes)Size of the header
8: DWORD (4 bytes)InfoPath Version
12: DWORD (4 bytes)Reserved
16: DWORD (4 bytes)File Size
20: DWORD (4 bytes)Size of FileName buffer
24: VariableName of the file

The first four bytes are not chosen randomly: the first byte is an unexistent ASCII code. Just to make sure the XML field is not misinterpreted as a text field. The other 3 bytes identify the field as an Infopath Form Attachment (73: I, 70: F, 65: A)

So in order to attach the file to a e-mail I need to read out the filename size, the filename and of course the file. Some code:

// file = the deserialized version of the InfoPath Form // objAttachmentResponse = the attachment field byte[] xmlFileString = file.objAttachmentResponse; if (xmlFileString != null) { //length of filename is on place 20 in the byte[], encoded in unicode --> x2 int nameBufferLen = xmlFileString[20] * 2; byte[] fileNameBuffer = new byte[nameBufferLen]; //Name of the file is on place 24 in the byte[] for (int j = 0; j < nameBufferLen; j++) { fileNameBuffer[j] = xmlFileString[24 + j]; } //decode the filename char[] asciiChars = UnicodeEncoding.Unicode.GetChars(filenameBuffer); string fileName = new string(asciiChars); //Remove the trailing \0 character fileName = fileName.Substring(0, fileName.Length - 1); //file content can be retreived after the fileName in the byte[] byte[] fileContent = new byte[xmlFileString.Length - (24 + nameBufferLen)]; for (int j = 0; j < fileContent.Length; j++) { fileContent[j] = xmlFileString[24 + nameBufferLen + j]; } //attach the file to the mail MemoryStream ms = new MemoryStream(fileContent); mail.Attachments.Add(new Attachment(ms, filename)); }