chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
package codec
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/zricethezav/gitleaks/v8/logging"
|
||||
)
|
||||
|
||||
// Decoder decodes various types of data in place
|
||||
type Decoder struct {
|
||||
decodedMap map[string]string
|
||||
}
|
||||
|
||||
// NewDecoder creates a default decoder struct
|
||||
func NewDecoder() *Decoder {
|
||||
return &Decoder{
|
||||
decodedMap: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// Decode returns the data with the values decoded in place along with the
|
||||
// encoded segment meta data for the next pass of decoding
|
||||
func (d *Decoder) Decode(data string, predecessors []*EncodedSegment) (string, []*EncodedSegment) {
|
||||
segments := d.findEncodedSegments(data, predecessors)
|
||||
|
||||
if len(segments) > 0 {
|
||||
result := bytes.NewBuffer(make([]byte, 0, len(data)))
|
||||
encodedStart := 0
|
||||
for _, segment := range segments {
|
||||
result.WriteString(data[encodedStart:segment.encoded.start])
|
||||
result.WriteString(segment.decodedValue)
|
||||
encodedStart = segment.encoded.end
|
||||
}
|
||||
|
||||
result.WriteString(data[encodedStart:])
|
||||
return result.String(), segments
|
||||
}
|
||||
|
||||
return data, segments
|
||||
}
|
||||
|
||||
// findEncodedSegments finds the encoded segments in the data
|
||||
func (d *Decoder) findEncodedSegments(data string, predecessors []*EncodedSegment) []*EncodedSegment {
|
||||
if len(data) == 0 {
|
||||
return []*EncodedSegment{}
|
||||
}
|
||||
|
||||
decodedShift := 0
|
||||
encodingMatches := findEncodingMatches(data)
|
||||
segments := make([]*EncodedSegment, 0, len(encodingMatches))
|
||||
for _, m := range encodingMatches {
|
||||
encodedValue := data[m.start:m.end]
|
||||
decodedValue, alreadyDecoded := d.decodedMap[encodedValue]
|
||||
|
||||
if !alreadyDecoded {
|
||||
decodedValue = m.encoding.decode(encodedValue)
|
||||
d.decodedMap[encodedValue] = decodedValue
|
||||
}
|
||||
|
||||
if len(decodedValue) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
segment := &EncodedSegment{
|
||||
predecessors: predecessors,
|
||||
original: toOriginal(predecessors, m.startEnd),
|
||||
encoded: m.startEnd,
|
||||
decoded: startEnd{
|
||||
m.start + decodedShift,
|
||||
m.start + decodedShift + len(decodedValue),
|
||||
},
|
||||
decodedValue: decodedValue,
|
||||
encodings: m.encoding.kind,
|
||||
depth: 1,
|
||||
}
|
||||
|
||||
// Shift decoded start and ends based on size changes
|
||||
decodedShift += len(decodedValue) - len(encodedValue)
|
||||
|
||||
// Adjust depth and encoding if applicable
|
||||
if len(segment.predecessors) != 0 {
|
||||
// Set the depth based on the predecessors' depth in the previous pass
|
||||
segment.depth = 1 + segment.predecessors[0].depth
|
||||
// Adjust encodings
|
||||
for _, p := range segment.predecessors {
|
||||
if segment.encoded.overlaps(p.decoded) {
|
||||
segment.encodings |= p.encodings
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
segments = append(segments, segment)
|
||||
logging.Debug().
|
||||
Str("decoder", m.encoding.kind.String()).
|
||||
Msgf(
|
||||
"segment found: original=%s pos=%s: %q -> %q",
|
||||
segment.original,
|
||||
segment.encoded,
|
||||
encodedValue,
|
||||
segment.decodedValue,
|
||||
)
|
||||
}
|
||||
|
||||
return segments
|
||||
}
|
||||
Reference in New Issue
Block a user