Question
· Sep 13, 2023

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

Product version: Caché 2017.1
Discussion (4)2
Log in or sign up to continue

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"?>
<Export generator="IRIS" version="26" zv="IRIS for Windows (x86-64) 2023.2.0L (Build 159U)" ts="2023-09-13 11:20:00">
<RoutineBase64 name="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.

I wrote a simple function to find non-printable characters in a routine:

findNonAscii
stream = ##class(%FileCharacterStream).%New()
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