Cache: Binary export output
I have an odd binary result exporting a specific routine via Studio, Export. Below is the beginning. The seemingly same routine in a different directory is exported fine, regular human readable code. Inspecting ^ROUTINE and ^rIndex did not give me any clues. Any insights?
<?xml version="1.0" encoding="UTF-8"?>
<Export generator="Cache" version="25" zv="Cache for Windows (x86-64) 2017.2.1 (Build 801U)" ts="2023-09-13 10:49:52">
<RoutineBase64 name="Utils" type="INT" languagemode="0" timestamp="66728,61062.933847">VXRpbHMJOyBVdGlsaXR5IE1ldGhvZHM7MjAyMy0wOS0xMSAxNjo1Nzo0MiBBTgoJcSAKY2hrQ3Ry
bChmaXg9MCkKCWsgXmdnRwoJcyB0PSJeUkZHIgoJcyBjdHI9MAoJdyAiUkZHIiwhCglmICBzIHQ9
Comments
This can happen if the routine contains an ASCII character that cannot be printed to XML. Here is an example from a routine I created:
> set routine = ##class(%Routine).%OpenId("pbarton.test.MAC")
> zw routine.Read()
"pbarton"_$c(10)_" write ""hello"_$c(7)_""""You can see the routine contains $c(7), which is a non-printable ASCII character. When I export the routine it looks like this:
<?xml version="1.0" encoding="UTF-8"?><Exportgenerator="IRIS"version="26"zv="IRIS for Windows (x86-64) 2023.2.0L (Build 159U)"ts="2023-09-13 11:20:00"><RoutineBase64name="pbarton.test"type="MAC"languagemode="0"timestamp="66730,40577.6434199">cGJhcnRvbgogd3JpdGUgImhlbGxvByI=
</RoutineBase64></Export>You can check for XML invalid characters by decoding the encoded payload. For example:
zw $SYSTEM.Encryption.Base64Decode("VXRpbHMJOyBVdGlsaXR5IE1ldGhvZHM7MjAyMy0wOS0xMSAxNjo1Nzo0MiBBTgoJcSAKY2hrQ3RybChmaXg9MCkKCWsgXmdnRwoJcyB0PSJeUkZHIgoJcyBjdHI9MAoJdyAiUkZHIiwhCglmICBzIHQ9")
"Utils"_$c(9)_"; Utility Methods;2023-09-11 16:57:42 AN"_$c(10,9)_"q "_$c(10)_"chkCtrl(fix=0)"_$c(10,9)_"k ^ggG"_$c(10,9)_"s t=""^RFG"""_$c(10,9)_"s ctr=0"_$c(10,9)_"w ""RFG"",!"_$c(10,9)_"f s t="Look for a $C( ? ) where ? is in 0,1,2,3 .. 30,31.
Note: Tab $C(9) and New line ($C(10) and $C(13,10) are fine.
Sometimes cut-n-paste from an email / word document will use $C(22) as a quote character.
That was it, invalid characters in a test method string. Thanks, @Pravin Barton and @Alex Woodhead!
I wrote a simple function to find non-printable characters in a routine:
findNonAscii
s stream = ##class(%FileCharacterStream).%New()
s stream.Filename="C:\TestAGbackup_2024-04-15_AG.txt"
f {
q:stream.AtEnd
s line = stream.ReadLine()
; Strip all control characters, including non-processable by XML export, except for tabs and newlines
s l2=$ZSTRIP(line,"*C","",$C(9)_$C(10)_$C(13))
w:l2'=line line,!,l2,!
}
q