Encoding Base64 from a Stream - Chunk Sizes
Hi all.
I'm currently looking at a use case where I need to take a Stream, and then encode the contents as a Base64 Stream. This is currently achieved with a snippet of code that has previously been placed in multiple classes within this particular environment, and relied on the dotnet gateway (which suffers with a bug in 2022.1, corrected 2022.1.1).
Therefore I will be replacing the dotnet implementation with the standard $System.Encryption.Base64Encode, and then place this all in a nice function to replace each instance of the same (currently non-functional) snippet of code placed in the various classes.
On to the question:
This function will have the option for the base64 to have line returns or not. I know that I will need to chunk the stream in multiples of 3s when encoding the data, and if I want to also include line returns this will need to be every 57 of the stream. Is there any harm in just chunking every 57 regardless of the inclusion of line returns, or is there some form of performance increase/decrease in chunking in values greater than 57?
Comments
Hopefully this can save you some work. It uses a much larger chunk size (which is a multiple of 57) and works with or without CR/LFs (set the argument pAddCRLF):
Class Example.B64.Util Extends %RegisteredObject
{
/// Be cautious if changing CHUNKSIZE. Incorrect values could cause the resulting encoded data to be invalid.
/// It should always be a multiple of 57 and needs to be less than ~2.4MB when MAXSTRING is 3641144
Parameter CHUNKSIZE = 2097144;
ClassMethod B64EncodeStream(pStream As %Stream.Object, pAddCRLF As %Boolean = 0) As %Stream.Object
{
set tEncodedStream=##class(%Stream.GlobalCharacter).%New()
do pStream.Rewind()
while ('pStream.AtEnd) {
set tReadLen=..#CHUNKSIZE
set tChunk=pStream.Read(.tReadLen)
do tEncodedStream.Write($System.Encryption.Base64Encode(tChunk,'pAddCRLF))
if (pAddCRLF && 'pStream.AtEnd) {
do tEncodedStream.Write($c(13,10))
}
}
do tEncodedStream.Rewind()
quit tEncodedStream
}
}Hey Marc.
Firstly, thank you for sharing this. This does seem to closely follow what I had intended to use, with a slight variation or two.
Would you mind giving some insight on this line "set tReadLen=..#CHUNKSIZE" as I'm not familiar with the use of the # symbol in this way. Is this acting as a modulo in this context?
"#" is for referring to a parameter defined in the class. Parameters are similar to static variables in Java.
https://docs.intersystems.com/irisforhealth20221/csp/docbook/DocBook.UI…
Hey Marc.
Thank you for sharing this - I have no idea how I have yet to come across this!
How would I convert the tEncodedStream to a %String?
If the B64 is "small" to fit a %String (~3.5MB or less), then just use $System.Encryption.Base64Decode()
I need to take the Encoded Stream and send it as an Encoded String. How would I take a Stream and send it as a String?
Set string= $System.Encryption.Base64Decode(stream.Read($$$MaxStringLength))
Do you need to decode a Base64 stream or you just need to read a stream to a string?
If so, then:
Set string=stream.Read($$$MaxStringLength)