yq/pkg/yqlib/decoder_base64.go
2025-11-15 14:11:55 +11:00

71 lines
1.7 KiB
Go

//go:build !yq_nobase64
package yqlib
import (
"bytes"
"encoding/base64"
"io"
"strings"
)
type base64Decoder struct {
reader io.Reader
finished bool
readAnything bool
encoding base64.Encoding
}
func NewBase64Decoder() Decoder {
return &base64Decoder{finished: false, encoding: *base64.StdEncoding}
}
func (dec *base64Decoder) Init(reader io.Reader) error {
// Read all data from the reader and strip leading/trailing whitespace
// This is necessary because base64 decoding needs to see the complete input
// to handle padding correctly, and we need to strip whitespace before decoding.
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(reader); err != nil {
return err
}
// Strip leading and trailing whitespace
stripped := strings.TrimSpace(buf.String())
// Add padding if needed (base64 strings should be a multiple of 4 characters)
padLen := len(stripped) % 4
if padLen > 0 {
stripped += strings.Repeat("=", 4-padLen)
}
// Create a new reader from the stripped and padded data
dec.reader = strings.NewReader(stripped)
dec.readAnything = false
dec.finished = false
return nil
}
func (dec *base64Decoder) Decode() (*CandidateNode, error) {
if dec.finished {
return nil, io.EOF
}
base64Reader := base64.NewDecoder(&dec.encoding, dec.reader)
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(base64Reader); err != nil {
return nil, err
}
if buf.Len() == 0 {
dec.finished = true
// if we've read _only_ an empty string, lets return that
// otherwise if we've already read some bytes, and now we get
// an empty string, then we are done.
if dec.readAnything {
return nil, io.EOF
}
}
dec.readAnything = true
return createStringScalarNode(buf.String()), nil
}