Question
Julian Matthews · Sep 16

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?

Product version: IRIS 2022.1
0
0 96
Discussion (4)1
Log in or sign up to continue

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?

Hey Marc.

Thank you for sharing this - I have no idea how I have yet to come across this!