Question
· Nov 29, 2021

Invalid Oref when trying to extract Base64 Encoded PDF from HL7 Field

Hi all, 

I'm using a snippet I found from Scott Roth to extract, decode, and save a PDF from a HL7 message and save it to a specified file path, but I'm running issues with the following error:


My approach was to a create a utility function accessible from a DTL like this:

Class ELHTPRODPKG.Functions.Utility.ExtractPDF Extends Ens.Rule.FunctionSet
{

     ClassMethod DecodeBase64HL7(base64 As %Stream.GlobalBinary, Path As %String, FileName As %String) As %String [ Final ]
     {
          //Debug
          WRITE $LENGTH(base64)
          // Decode
          set Oref = ##class(%FileBinaryStream).%New()
          set Oref.Filename = Path_FileName

          Do base64.Rewind()

          While 'base64.AtEnd 
          {
                set ln=base64.ReadLine()
                set lnDecoded=$system.Encryption.Base64Decode(ln)
                do Oref.Write(lnDecoded)
          }

          Do Oref.%Save()
          return Oref.Filename
     }

}

But I think something must be wrong with my code, I am invoking the custom utility function in the DTL with a code action like this:



I am very new to writing ObjectScript so I apologise if this is a very basic error, I've spent ages trying to resolve the issue myself but I'm stumped,
Please could someone point me in the right direction and explain why what I've done doesn't work and what I would need to do to fix it, 

Thanks in advance, 
Ben

Discussion (7)1
Log in or sign up to continue

At this point in your code - Do base64.Rewind() - base64 isn't a stream object because of how you've populated it earlier in the DTL.

I'm guessing

target.{PIDgrpgrp(1).ORCgrp(1).OBXgrp(1).OBX:5(1).5} returns a string so you need to write that into the Stream:

base64.Write({PIDgrpgrp(1).ORCgrp(1).OBXgrp(1).OBX:5(1).5})

before you call your custom function (assuming you've already instantiated your stream).

Thanks for your reply, I was able to amend my code to render the PDF correctly, so thank you for your help

Class ELHTPRODPKG.Functions.Utility.ExtractPDF Extends Ens.Rule.FunctionSet
{
      ClassMethod DecodeBase64HL7(base64String As %String, Path As %String, FileName As %String)        As %String
      {
             set base64 = ##class(%Stream.GlobalBinary).%New()
             set Oref = ##class(%FileBinaryStream).%New()
            
set Oref.Filename = Path_FileName_".pdf"

             Do base64.Write(base64String)
             Do base64.Rewind()
         
            
While 'base64.AtEnd 
             
{
                   set ln=base64.ReadLine()
                   set lnDecoded=$system.Encryption.Base64Decode(ln)
                   do Oref.Write(lnDecoded)
             }
            Do Oref.%Save()
            return Oref.Filename
     }
}

You will want to fetch the stream using the GetFieldStreamRaw() method in EnsLib.HL7.Message rather than just referencing the field directly.

Set tSC=source.GetFieldStreamRaw(.varBase64,"PIDgrpgrp(1).ORCgrp(1).OBXgrp(1).OBX:5(1).5")
Return:$$$ISERR(tSC) tSC

This will have varBase64 as a proper stream object for use with your DecodeBase64HL7 method. GetFieldStreamRaw() supplies the stream as type %Stream.GlobalCharacter, so you may want to adjust your method ...

If the length of the encoded PDF is less than MAXSTRING (roughly 3.6MB) it will be populated in the message as type %String. Otherwise it's a %Stream.GobalCharacter, and working with them using property paths in many of the IRIS functions will cause problems. GetFieldStreamRaw() guarantees you have a stream to work with.

Things may work out fine with your current code, but I've always taken the precaution of making sure I'm working with a stream when there's a chance the field content may be large.

EDIT: Please ignore this I just answered my own question, I would just manually assign the path to a var in the DTL to be passed into the decode function

One more quick question, 
The aim was to create a non-specific utility function for use anywhere a PDF needs to be extracted, Instead of passing the field contents in as a string as then writing that to a stream object,  How would I programmatically get the path of the field in question as a string from within a DTL? 

E.g instead of getting the contents of the field at PIDgrpgrp(1).ORCgrp(1).OBXgrp(1).OBX:5(1).5,
I would want to get "PIDgrpgrp(1).ORCgrp(1).OBXgrp(1).OBX:5(1).5" as variable varFieldPath  to pass into the decode function via GetFieldStreamRaw() to give something like:

Set tSC=source.GetFieldStreamRaw(.varBase64,varFieldPath )

Thanks for your help, it's really appreciated :)