/
uzer_007
/
gobase64
Обзор
Документация
Войти
/
uzer_007
/
gobase64
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
encode.go
2 031 строка
58 KB
uzer_007
release: v1.2.0
12 авг 2026, 10:34
12 авг 2026, 10:34
55f3cc9
Код
Авторство
О чём код?
// Copyright 2009 The Go Authors. All rights reserved. // Portions of this file are governed by the BSD-style license in LICENSE_GO. package base64 import ( "slices" ) const maxSmallEncode = 32 const maxSmallEncodedPadded = 44 // Encode encodes src using enc, writing EncodedLen(len(src)) bytes to dst. func (enc *Encoding) Encode(dst, src []byte) { if len(src) == 0 { return } enc.encodePublicDispatch(dst, src) } func (enc *Encoding) encodePublicDispatch(dst, src []byte) { if uint(len(src)-8) <= 7 && enc.tables == stdEncodingTables && enc.padChar == StdPadding { if uncheckedLittleEndianStores && len(dst) < int(encodedLenPaddedSmall[len(src)]) { panic("encoding/base64: output byte slice is too small") } encodeStdPadded8To15Hot(enc.tables, dst, src) return } if len(src) <= 4 && enc.tables == nil { alphabet := enc.customAlphabet() switch len(src) { case 1: b0 := src[0] v := uint32(alphabet[b0>>2]) | uint32(alphabet[(b0&0x03)<<4])<<8 if enc.padChar == NoPadding { _ = dst[1] putUint16LE(dst, uint16(v)) } else { _ = dst[3] putUint32LE(dst, v|enc.padTail1) } case 2: b0, b1 := src[0], src[1] v := uint32(alphabet[b0>>2]) | uint32(alphabet[(b0&0x03)<<4|b1>>4])<<8 | uint32(alphabet[(b1&0x0f)<<2])<<16 if enc.padChar == NoPadding { _ = dst[2] putUint16LE(dst, uint16(v)) dst[2] = byte(v >> 16) } else { _ = dst[3] putUint32LE(dst, v|enc.padTail2) } case 3: _ = dst[3] putUint32LE(dst, encodeAlphabetWord(alphabet, src[0], src[1], src[2])) case 4: if enc.padChar == NoPadding { _ = dst[5] } else { _ = dst[7] } putUint32LE(dst, encodeAlphabetWord(alphabet, src[0], src[1], src[2])) b0 := src[3] v := uint32(alphabet[b0>>2]) | uint32(alphabet[(b0&0x03)<<4])<<8 if enc.padChar == NoPadding { putUint16LE(dst[4:], uint16(v)) } else { putUint32LE(dst[4:], v|enc.padTail1) } } return } if len(src) == 8 && enc.tables == nil { alphabet := enc.customAlphabet() if enc.padChar == NoPadding { _ = dst[10] } else { _ = dst[11] } putUint32LE(dst, encodeAlphabetWord(alphabet, src[0], src[1], src[2])) putUint32LE(dst[4:], encodeAlphabetWord(alphabet, src[3], src[4], src[5])) b0, b1 := src[6], src[7] v := uint32(alphabet[b0>>2]) | uint32(alphabet[(b0&0x03)<<4|b1>>4])<<8 | uint32(alphabet[(b1&0x0f)<<2])<<16 if enc.padChar == NoPadding { putUint16LE(dst[8:], uint16(v)) dst[10] = byte(v >> 16) } else { putUint32LE(dst[8:], v|enc.padTail2) } return } if len(src) <= 8 && enc.padChar == NoPadding && (enc.tables == stdEncodingTables || enc.tables == urlEncodingTables) { t := enc.tables switch len(src) { case 1: _ = dst[1] putUint16LE(dst, uint16(t.enc1[src[0]])) case 2: _ = dst[2] b0, b1 := src[0], src[1] v := uint32(t.encQuad[int(b0)<<4|int(b1>>4)]) | uint32(t.encode[(b1&0x0f)<<2])<<16 putUint16LE(dst, uint16(v)) dst[2] = byte(v >> 16) case 3: _ = dst[3] encodeQuantum(t, dst, src) case 4: _ = dst[5] encodeQuantum(t, dst, src) putUint16LE(dst[4:], uint16(t.enc1[src[3]])) case 5: _ = dst[6] encodeQuantum(t, dst, src) b0, b1 := src[3], src[4] v := uint32(t.encQuad[int(b0)<<4|int(b1>>4)]) | uint32(t.encode[(b1&0x0f)<<2])<<16 putUint16LE(dst[4:], uint16(v)) dst[6] = byte(v >> 16) case 6: _ = dst[7] encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) case 7: _ = dst[9] encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) putUint16LE(dst[8:], uint16(t.enc1[src[6]])) case 8: _ = dst[10] encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) b0, b1 := src[6], src[7] v := uint32(t.encQuad[int(b0)<<4|int(b1>>4)]) | uint32(t.encode[(b1&0x0f)<<2])<<16 putUint16LE(dst[8:], uint16(v)) dst[10] = byte(v >> 16) } return } if len(src) <= 8 && enc.padChar != StdPadding && enc.padChar != NoPadding && (enc.tables == stdEncodingTables || enc.tables == urlEncodingTables) { t := enc.tables switch len(src) { case 1: _ = dst[3] putUint32LE(dst, t.enc1[src[0]]|enc.padTail1) case 2: _ = dst[3] b0, b1 := src[0], src[1] putUint32LE(dst, uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|enc.padTail2) case 3: _ = dst[3] encodeQuantum(t, dst, src) case 4: _ = dst[7] encodeQuantum(t, dst, src) putUint32LE(dst[4:], t.enc1[src[3]]|enc.padTail1) case 5: _ = dst[7] encodeQuantum(t, dst, src) b0, b1 := src[3], src[4] putUint32LE(dst[4:], uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|enc.padTail2) case 6: _ = dst[7] encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) case 7: _ = dst[11] encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) putUint32LE(dst[8:], t.enc1[src[6]]|enc.padTail1) case 8: _ = dst[11] encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) b0, b1 := src[6], src[7] putUint32LE(dst[8:], uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|enc.padTail2) } return } if len(src) <= 7 && enc.padChar == StdPadding && (enc.tables == stdEncodingTables || enc.tables == urlEncodingTables) { t := enc.tables switch len(src) { case 1: _ = dst[3] putUint32LE(dst, t.enc1[src[0]]|uint32('=')<<16|uint32('=')<<24) case 2: _ = dst[3] b0, b1 := src[0], src[1] putUint32LE(dst, uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|uint32('=')<<24) case 3: _ = dst[3] encodeQuantum(t, dst, src) case 4: _ = dst[7] encodeQuantum(t, dst, src) putUint32LE(dst[4:], t.enc1[src[3]]|uint32('=')<<16|uint32('=')<<24) case 5: _ = dst[7] encodeQuantum(t, dst, src) b0, b1 := src[3], src[4] putUint32LE(dst[4:], uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|uint32('=')<<24) case 6: _ = dst[7] encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) case 7: _ = dst[11] encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) putUint32LE(dst[8:], t.enc1[src[6]]|uint32('=')<<16|uint32('=')<<24) } return } if uint(len(src)-8) <= 8 && enc.padChar == StdPadding && (enc.tables == stdEncodingTables || enc.tables == urlEncodingTables) { if uncheckedLittleEndianStores && len(dst) < int(encodedLenPaddedSmall[len(src)]) { panic("encoding/base64: output byte slice is too small") } t := enc.tables switch len(src) { case 8: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeTailStd(t, dst[8:], src[6:]) case 10: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeTailStd(t, dst[12:], src[9:]) case 13: encodeStdPadded13(t, dst, src) case 16: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeQuantum(t, dst[16:], src[12:]) putUint32LE(dst[20:], t.enc1[src[15]]|uint32('=')<<16|uint32('=')<<24) default: encodeTinyStd9(t, dst, src) } return } if uncheckedLittleEndianStores && len(dst) < enc.EncodedLen(len(src)) { panic("encoding/base64: output byte slice is too small") } if enc.tables == nil { alphabet := enc.customAlphabet() switch len(src) { case 16: _ = src[15] _ = dst[23] putUint32LE(dst, encodeAlphabetWord(alphabet, src[0], src[1], src[2])) putUint32LE(dst[4:], encodeAlphabetWord(alphabet, src[3], src[4], src[5])) putUint32LE(dst[8:], encodeAlphabetWord(alphabet, src[6], src[7], src[8])) putUint32LE(dst[12:], encodeAlphabetWord(alphabet, src[9], src[10], src[11])) putUint32LE(dst[16:], encodeAlphabetWord(alphabet, src[12], src[13], src[14])) b0 := src[15] v := uint32(alphabet[b0>>2]) | uint32(alphabet[(b0&0x03)<<4])<<8 if enc.padChar == NoPadding { putUint16LE(dst[20:], uint16(v)) } else { putUint32LE(dst[20:], v|enc.padTail1) } return case 12: putUint32LE(dst, encodeAlphabetWord(alphabet, src[0], src[1], src[2])) putUint32LE(dst[4:], encodeAlphabetWord(alphabet, src[3], src[4], src[5])) putUint32LE(dst[8:], encodeAlphabetWord(alphabet, src[6], src[7], src[8])) putUint32LE(dst[12:], encodeAlphabetWord(alphabet, src[9], src[10], src[11])) return case 15: putUint32LE(dst, encodeAlphabetWord(alphabet, src[0], src[1], src[2])) putUint32LE(dst[4:], encodeAlphabetWord(alphabet, src[3], src[4], src[5])) putUint32LE(dst[8:], encodeAlphabetWord(alphabet, src[6], src[7], src[8])) putUint32LE(dst[12:], encodeAlphabetWord(alphabet, src[9], src[10], src[11])) putUint32LE(dst[16:], encodeAlphabetWord(alphabet, src[12], src[13], src[14])) return case 24: putUint32LE(dst, encodeAlphabetWord(alphabet, src[0], src[1], src[2])) putUint32LE(dst[4:], encodeAlphabetWord(alphabet, src[3], src[4], src[5])) putUint32LE(dst[8:], encodeAlphabetWord(alphabet, src[6], src[7], src[8])) putUint32LE(dst[12:], encodeAlphabetWord(alphabet, src[9], src[10], src[11])) putUint32LE(dst[16:], encodeAlphabetWord(alphabet, src[12], src[13], src[14])) putUint32LE(dst[20:], encodeAlphabetWord(alphabet, src[15], src[16], src[17])) putUint32LE(dst[24:], encodeAlphabetWord(alphabet, src[18], src[19], src[20])) putUint32LE(dst[28:], encodeAlphabetWord(alphabet, src[21], src[22], src[23])) return case 32: putUint32LE(dst, encodeAlphabetWord(alphabet, src[0], src[1], src[2])) putUint32LE(dst[4:], encodeAlphabetWord(alphabet, src[3], src[4], src[5])) putUint32LE(dst[8:], encodeAlphabetWord(alphabet, src[6], src[7], src[8])) putUint32LE(dst[12:], encodeAlphabetWord(alphabet, src[9], src[10], src[11])) putUint32LE(dst[16:], encodeAlphabetWord(alphabet, src[12], src[13], src[14])) putUint32LE(dst[20:], encodeAlphabetWord(alphabet, src[15], src[16], src[17])) putUint32LE(dst[24:], encodeAlphabetWord(alphabet, src[18], src[19], src[20])) putUint32LE(dst[28:], encodeAlphabetWord(alphabet, src[21], src[22], src[23])) putUint32LE(dst[32:], encodeAlphabetWord(alphabet, src[24], src[25], src[26])) putUint32LE(dst[36:], encodeAlphabetWord(alphabet, src[27], src[28], src[29])) b0, b1 := src[30], src[31] v := uint32(alphabet[b0>>2]) | uint32(alphabet[(b0&0x03)<<4|b1>>4])<<8 | uint32(alphabet[(b1&0x0f)<<2])<<16 if enc.padChar == NoPadding { putUint16LE(dst[40:], uint16(v)) dst[42] = byte(v >> 16) } else { putUint32LE(dst[40:], v|enc.padTail2) } return } if len(src) <= maxSmallEncode { enc.encodeLazyCustomSmall(dst, src) } else { enc.encodeLazyCustom(dst, src) } return } enc.encodePublicNonEmpty(dst, src) } func (enc *Encoding) encodePublicNonEmpty(dst, src []byte) { switch len(src) { case 1: if enc.kind == encodingStd && enc.padChar == StdPadding { putUint32LE(dst, enc.tables.enc1[src[0]]|uint32('=')<<16|uint32('=')<<24) return } v := enc.tables.enc1[src[0]] if enc.padChar == NoPadding { putUint16LE(dst, uint16(v)) } else { putUint32LE(dst, v|enc.padTail1) } return case 2: if enc.kind == encodingStd && enc.padChar == StdPadding { t := enc.tables b0, b1 := src[0], src[1] putUint32LE(dst, uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|uint32('=')<<24) return } t := enc.tables b0, b1 := src[0], src[1] v := uint32(t.encQuad[int(b0)<<4|int(b1>>4)]) | uint32(t.encode[(b1&0x0f)<<2])<<16 if enc.padChar == NoPadding { dst[0] = byte(v) dst[1] = byte(v >> 8) dst[2] = byte(v >> 16) } else { putUint32LE(dst, v|enc.padTail2) } return case 3: encodeQuantum(enc.tables, dst, src) return case 4: if enc.kind == encodingStd && enc.padChar == StdPadding { t := enc.tables encodeQuantum(t, dst, src) encodeTailStd(t, dst[4:], src[3:]) return } encodeQuantum(enc.tables, dst, src) encodeTail(enc, dst[4:], src[3:]) return case 5: if enc.kind == encodingStd && enc.padChar == StdPadding { t := enc.tables encodeQuantum(t, dst, src) encodeTailStd(t, dst[4:], src[3:]) return } case 6: if enc.kind == encodingStd && enc.padChar == StdPadding { t := enc.tables encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) return } case 7: if enc.kind == encodingStd && enc.padChar == StdPadding { t := enc.tables encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeTailStd(t, dst[8:], src[6:]) return } case 8: t := enc.tables if enc.kind == encodingStd && enc.padChar == StdPadding { encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeTailStd(t, dst[8:], src[6:]) return } encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeTail(enc, dst[8:], src[6:]) return case 9, 10, 11, 12, 13, 14, 15: if enc.kind == encodingStd && enc.padChar == StdPadding { encodeTinyStd9(enc.tables, dst, src) return } case 16: t := enc.tables if enc.kind == encodingStd && enc.padChar == StdPadding { encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeQuantum(t, dst[16:], src[12:]) encodeTailStd(t, dst[20:], src[15:]) return } encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeQuantum(t, dst[16:], src[12:]) encodeTail(enc, dst[20:], src[15:]) return case 24: if enc.kind == encodingStd && enc.padChar == StdPadding { t := enc.tables encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeQuantum(t, dst[16:], src[12:]) encodeQuantum(t, dst[20:], src[15:]) encodeQuantum(t, dst[24:], src[18:]) encodeQuantum(t, dst[28:], src[21:]) return } case 32: if enc.kind == encodingStd && enc.padChar == StdPadding { encodeStdPadded32(enc.tables, dst, src) return } enc.encodeSmallGeneric(dst, src) return case 128: if enc.kind == encodingStd && enc.padChar == StdPadding { if encodeStdPadded128ASM(enc.tables, dst, src) { return } encodeStdPaddedScalarPairs(enc.tables, dst, src) return } case 96, 192, 256: // SSE4.2-class kernels win these sizes when available (roughly 2x over // the scalar pair loop on GOAMD64=v2 hardware); keep the scalar route // for CPUs where the SIMD dispatcher would fall back anyway. if enc.kind == encodingStd && enc.padChar == StdPadding && !sseBase64Available() { encodeStdPaddedScalarPairs(enc.tables, dst, src) return } } enc.encodeNonEmpty(dst, src) } func (enc *Encoding) encodeNonEmpty(dst, src []byte) { srcLen := len(src) if srcLen <= maxSmallEncode && enc.kind == encodingStd && enc.padChar == StdPadding { if srcLen <= 2 { encodeTinyStdPadded12(enc.tables, dst, src) return } if srcLen < 16 { encodeTinyStdPadded(enc.tables, dst, src) return } encodeSmallStdPadded(enc.tables, dst, src) return } if srcLen < 16 { enc.encodeTiny(dst, src) return } if srcLen <= maxSmallEncode { enc.encodeSmall(dst, src) return } if srcLen == 64 && enc.kind == encodingStd && enc.padChar == StdPadding { encodeStdPadded64(enc.tables, dst, src) return } if srcLen == 128 && enc.kind == encodingStd && enc.padChar == StdPadding { if encodeStdPadded128ASM(enc.tables, dst, src) { return } } if enc.kind == encodingStd && enc.padChar == StdPadding && scalarOnlyCPU() { if srcLen == 320 || srcLen == 640 { if encodeStdPaddedScalarASM(enc.tables, dst, src) { return } encodeStdPaddedScalarPairs(enc.tables, dst, src) return } if srcLen >= 2048 { if encodeStdPaddedScalarASM(enc.tables, dst, src) { return } encodeStdPaddedScalar(enc.tables, dst, src) return } } if srcLen < minEncodeSSE42 { enc.encodeScalar(dst, src) return } if encodeSIMDWithAVX2Threshold(enc, dst, src, minEncodeAVX2Direct) { return } enc.encode(dst, src) } func (enc *Encoding) encode(dst, src []byte) { enc.encodeScalar(dst, src) } func (enc *Encoding) encodeAllocated(dst, src []byte) { srcLen := len(src) if srcLen <= maxSmallEncode && enc.kind == encodingStd && enc.padChar == StdPadding { if srcLen < 16 { encodeTinyStdPadded(enc.tables, dst, src) return } encodeSmallStdPadded(enc.tables, dst, src) return } if srcLen < 16 { enc.encodeTiny(dst, src) return } if srcLen <= maxSmallEncode { enc.encodeSmall(dst, src) return } if srcLen == 64 && enc.kind == encodingStd && enc.padChar == StdPadding { encodeStdPadded64(enc.tables, dst, src) return } if encodeSIMD(enc, dst, src) { return } enc.encodeScalar(dst, src) } func encodeTinyStdPadded12(t *encodingTables, dst, src []byte) { b0 := src[0] if len(src) == 1 { putUint32LE(dst, uint32(t.encQuad[int(b0>>2)<<6|int((b0&0x03)<<4)])|uint32('=')<<16|uint32('=')<<24) return } b1 := src[1] putUint32LE(dst, uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|uint32('=')<<24) } func encodeTinyStdPadded(t *encodingTables, dst, src []byte) { switch len(src) { case 1, 2: encodeTinyStdPadded12(t, dst, src) case 3: encodeQuantum(t, dst, src) case 4: encodeQuantum(t, dst, src) encodeTailStd(t, dst[4:], src[3:]) case 5: encodeQuantum(t, dst, src) encodeTailStd(t, dst[4:], src[3:]) case 6: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) case 7: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeTailStd(t, dst[8:], src[6:]) case 8: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeTailStd(t, dst[8:], src[6:]) default: encodeTinyStd9(t, dst, src) } } func (enc *Encoding) encodeTiny(dst, src []byte) { t := enc.tables switch len(src) { case 0: case 1: b0 := src[0] putUint16LE(dst, uint16(t.encQuad[int(b0>>2)<<6|int((b0&0x03)<<4)])) if enc.padChar == StdPadding { dst[2] = '=' dst[3] = '=' } else if enc.padChar != NoPadding { dst[2] = byte(enc.padChar) dst[3] = byte(enc.padChar) } case 2: b0, b1 := src[0], src[1] putUint16LE(dst, uint16(t.encQuad[int(b0)<<4|int(b1>>4)])) dst[2] = t.encode[(b1&0x0f)<<2] if enc.padChar == StdPadding { dst[3] = '=' } else if enc.padChar != NoPadding { dst[3] = byte(enc.padChar) } case 3: encodeQuantum(t, dst, src) case 4: encodeQuantum(t, dst, src) encodeTail(enc, dst[4:], src[3:]) case 5: encodeQuantum(t, dst, src) encodeTail(enc, dst[4:], src[3:]) case 6: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) case 7: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeTail(enc, dst[8:], src[6:]) case 8: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeTail(enc, dst[8:], src[6:]) default: if enc.kind == encodingStd && enc.padChar == StdPadding { encodeTinyStd9(t, dst, src) return } enc.encodeTinyGeneric9(dst, src) } } func encodeTinyStd9(t *encodingTables, dst, src []byte) { switch len(src) { case 9: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) case 10: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeTailStd(t, dst[12:], src[9:]) case 11: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeTailStd(t, dst[12:], src[9:]) case 12: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) case 13: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeTailStd(t, dst[16:], src[12:]) case 14: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeTailStd(t, dst[16:], src[12:]) case 15: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeQuantum(t, dst[16:], src[12:]) } } func (enc *Encoding) encodeTinyGeneric9(dst, src []byte) { t := enc.tables switch len(src) { case 9: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) case 10: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeTail(enc, dst[12:], src[9:]) case 11: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeTail(enc, dst[12:], src[9:]) case 12: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) case 13: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeTail(enc, dst[16:], src[12:]) case 14: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeTail(enc, dst[16:], src[12:]) case 15: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeQuantum(t, dst[16:], src[12:]) } } func (enc *Encoding) encodeSmall(dst, src []byte) { if enc.kind == encodingStd && enc.padChar == StdPadding { encodeSmallStdPadded(enc.tables, dst, src) return } enc.encodeSmallGeneric(dst, src) } func encodeSmallStdPadded(t *encodingTables, dst, src []byte) { switch len(src) { case 16: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeQuantum(t, dst[16:], src[12:]) encodeTailStd(t, dst[20:], src[15:]) case 24: encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeQuantum(t, dst[8:], src[6:]) encodeQuantum(t, dst[12:], src[9:]) encodeQuantum(t, dst[16:], src[12:]) encodeQuantum(t, dst[20:], src[15:]) encodeQuantum(t, dst[24:], src[18:]) encodeQuantum(t, dst[28:], src[21:]) case 32: encodeStdPadded32(t, dst, src) default: encodeStdPaddedScalar(t, dst, src) } } func encodeSmallStd16(t *encodingTables, dst, src []byte) { full := len(src) / 3 switch full { case 10: encodeQuantum(t, dst[36:], src[27:]) fallthrough case 9: encodeQuantum(t, dst[32:], src[24:]) fallthrough case 8: encodeQuantum(t, dst[28:], src[21:]) fallthrough case 7: encodeQuantum(t, dst[24:], src[18:]) fallthrough case 6: encodeQuantum(t, dst[20:], src[15:]) fallthrough case 5: encodeQuantum(t, dst[16:], src[12:]) fallthrough case 4: encodeQuantum(t, dst[12:], src[9:]) fallthrough case 3: encodeQuantum(t, dst[8:], src[6:]) fallthrough case 2: encodeQuantum(t, dst[4:], src[3:]) fallthrough case 1: encodeQuantum(t, dst, src) } if remAt := full * 3; remAt < len(src) { encodeTailStd(t, dst[full*4:], src[remAt:]) } } func (enc *Encoding) encodeSmallGeneric(dst, src []byte) { t := enc.tables full := len(src) / 3 switch full { case 10: encodeQuantum(t, dst[36:], src[27:]) fallthrough case 9: encodeQuantum(t, dst[32:], src[24:]) fallthrough case 8: encodeQuantum(t, dst[28:], src[21:]) fallthrough case 7: encodeQuantum(t, dst[24:], src[18:]) fallthrough case 6: encodeQuantum(t, dst[20:], src[15:]) fallthrough case 5: encodeQuantum(t, dst[16:], src[12:]) fallthrough case 4: encodeQuantum(t, dst[12:], src[9:]) fallthrough case 3: encodeQuantum(t, dst[8:], src[6:]) fallthrough case 2: encodeQuantum(t, dst[4:], src[3:]) fallthrough case 1: encodeQuantum(t, dst, src) } if remAt := full * 3; remAt < len(src) { encodeTail(enc, dst[full*4:], src[remAt:]) } } func encodeQuantum(t *encodingTables, dst, src []byte) { val := uint32(src[0])<<16 | uint32(src[1])<<8 | uint32(src[2]) putUint32LE(dst, t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) } func encodeTail(enc *Encoding, dst, src []byte) { if len(src) == 0 { return } t := enc.tables b0 := src[0] dst[0] = t.encode[b0>>2] if len(src) == 1 { dst[1] = t.encode[(b0&0x03)<<4] if enc.padChar != NoPadding { dst[2] = byte(enc.padChar) dst[3] = byte(enc.padChar) } return } b1 := src[1] dst[1] = t.encode[(b0&0x03)<<4|b1>>4] dst[2] = t.encode[(b1&0x0f)<<2] if enc.padChar != NoPadding { dst[3] = byte(enc.padChar) } } func encodeTailStd(t *encodingTables, dst, src []byte) { b0 := src[0] if len(src) == 1 { putUint32LE(dst, uint32(t.encQuad[int(b0>>2)<<6|int((b0&0x03)<<4)])|uint32('=')<<16|uint32('=')<<24) return } b1 := src[1] putUint32LE(dst, uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|uint32('=')<<24) } var encodedLenPaddedSmall = [maxSmallEncode + 1]uint8{ 0, 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16, 20, 20, 20, 24, 24, 24, 28, 28, 28, 32, 32, 32, 36, 36, 36, 40, 40, 40, 44, 44, } var encodedLenRawSmall = [maxSmallEncode + 1]uint8{ 0, 2, 3, 4, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18, 19, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 34, 35, 36, 38, 39, 40, 42, 43, } func (enc *Encoding) encodedLenSmall(n int) int { if enc.padChar == NoPadding { return int(encodedLenRawSmall[n]) } return int(encodedLenPaddedSmall[n]) } // AppendEncode appends the base64 encoded src to dst and returns the extended buffer. func (enc *Encoding) AppendEncode(dst, src []byte) []byte { srcLen := len(src) if srcLen == 0 { return dst } if enc.tables == nil { n := enc.EncodedLen(srcLen) oldLen := len(dst) if cap(dst)-oldLen < n { dst = slices.Grow(dst, n) } dst = dst[:oldLen+n] switch srcLen { case 8, 12, 15, 24: enc.Encode(dst[oldLen:], src) return dst } if srcLen <= maxSmallEncode { enc.encodeLazyCustomSmall(dst[oldLen:], src) } else { enc.encodeLazyCustom(dst[oldLen:], src) } return dst } return enc.appendEncodeNonEmpty(dst, src, srcLen) } func (enc *Encoding) appendEncodeNonEmpty(dst, src []byte, srcLen int) []byte { var n int if srcLen <= maxSmallEncode { n = enc.encodedLenSmall(srcLen) } else { n = enc.EncodedLen(srcLen) } oldLen := len(dst) if cap(dst)-oldLen < n { dst = slices.Grow(dst, n) } dst = dst[:oldLen+n] if srcLen == 16 && !enc.isStdPadded() { out := dst[oldLen:] t := enc.tables encodeQuantum(t, out, src) encodeQuantum(t, out[4:], src[3:]) encodeQuantum(t, out[8:], src[6:]) encodeQuantum(t, out[12:], src[9:]) encodeQuantum(t, out[16:], src[12:]) if enc.padChar == StdPadding { encodeTailStd(t, out[20:], src[15:]) } else { encodeTail(enc, out[20:], src[15:]) } return dst } if enc.isStdPadded() { switch srcLen { case 1, 2: encodeTinyStdPadded12(enc.tables, dst[oldLen:], src) return dst case 3: encodeQuantum(enc.tables, dst[oldLen:], src) return dst case 4: encodeStdPadded4(enc.tables, dst[oldLen:], src) return dst case 8: encodeStdPadded8(enc.tables, dst[oldLen:], src) return dst case 9, 10, 11, 12, 13, 14, 15: encodeTinyStd9(enc.tables, dst[oldLen:], src) return dst case 16, 24: encodeSmallStdPadded(enc.tables, dst[oldLen:], src) return dst case 32: encodeStdPadded32(enc.tables, dst[oldLen:], src) return dst } } if srcLen <= maxSmallEncode && enc.kind == encodingStd && enc.padChar == StdPadding { if srcLen < 16 { encodeTinyStdPadded(enc.tables, dst[oldLen:], src) } else if srcLen <= maxSmallEncode { encodeSmallStdPadded(enc.tables, dst[oldLen:], src) } else { enc.Encode(dst[oldLen:], src) } return dst } if srcLen <= 2 && enc.padChar != NoPadding { // A padded 1- or 2-byte input is exactly one 4-byte group; one combined // store skips the encodeTiny switch and its per-branch padding writes. t := enc.tables if srcLen == 1 { putUint32LE(dst[oldLen:], t.enc1[src[0]]|enc.padTail1) } else { b0, b1 := src[0], src[1] putUint32LE(dst[oldLen:], uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|enc.padTail2) } return dst } if srcLen < 16 { enc.encodeTiny(dst[oldLen:], src) } else if srcLen <= maxSmallEncode { enc.encodeSmall(dst[oldLen:], src) } else { enc.Encode(dst[oldLen:], src) } return dst } // EncodeToString returns the base64 encoding of src. func (enc *Encoding) EncodeToString(src []byte) string { srcLen := len(src) if srcLen == 0 { return "" } if uint(srcLen-4) <= 11 && enc.tables == stdEncodingTables && enc.padChar == StdPadding { t := enc.tables switch srcLen { case 4: return encodeStringStdPadded4Fast(t, src) case 5: return encodeStringStdPadded5Fast(t, src) case 6: return encodeStringStdPadded6Fast(t, src) case 7: return encodeStringStdPadded7Fast(t, src) case 8: return encodeStringStdPadded8Fast(t, src) case 9: return encodeStringStdPadded9Fast(t, src) case 10: return encodeStringStdPadded10Fast(t, src) case 11: return encodeStringStdPadded11Fast(t, src) case 12: return encodeStringStdPadded12Fast(t, src) case 13: return encodeStringStdPadded13Fast(t, src) case 14: return encodeStringStdPadded14Fast(t, src) default: return encodeStringStdPadded15Fast(t, src) } } if enc.tables == nil { if srcLen == 16 { alphabet := enc.customAlphabet() buf := new([24]byte) putUint32LE(buf[:], encodeAlphabetWord(alphabet, src[0], src[1], src[2])) putUint32LE(buf[4:], encodeAlphabetWord(alphabet, src[3], src[4], src[5])) putUint32LE(buf[8:], encodeAlphabetWord(alphabet, src[6], src[7], src[8])) putUint32LE(buf[12:], encodeAlphabetWord(alphabet, src[9], src[10], src[11])) putUint32LE(buf[16:], encodeAlphabetWord(alphabet, src[12], src[13], src[14])) b0 := src[15] v := uint32(alphabet[b0>>2]) | uint32(alphabet[(b0&0x03)<<4])<<8 if enc.padChar == NoPadding { putUint16LE(buf[20:], uint16(v)) return bytesToString(buf[:22]) } putUint32LE(buf[20:], v|enc.padTail1) return bytesToString(buf[:]) } if srcLen <= 8 { buf := make([]byte, enc.EncodedLen(srcLen)) enc.encodeLazyCustomSmall(buf, src) return bytesToString(buf) } buf := makeNoZero(enc.EncodedLen(srcLen)) enc.encodeLazyCustom(buf, src) return bytesToString(buf) } return enc.encodeToStringPublicNonEmpty(src, srcLen) } func (enc *Encoding) encodeToStringPublicNonEmpty(src []byte, srcLen int) string { if enc.padChar != StdPadding && enc.padChar != NoPadding && (enc.tables == stdEncodingTables || enc.tables == urlEncodingTables) { t := enc.tables switch srcLen { case 2: buf := new([4]byte) b0, b1 := src[0], src[1] putUint32LE(buf[:], uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|enc.padTail2) return bytesToString(buf[:]) case 3: return encodeStringStdPadded3Fast(t, src) case 4: buf := new([8]byte) encodeQuantum(t, buf[:], src) putUint32LE(buf[4:], t.enc1[src[3]]|enc.padTail1) return bytesToString(buf[:]) case 8: buf := new([12]byte) encodeQuantum(t, buf[:], src) encodeQuantum(t, buf[4:], src[3:]) b0, b1 := src[6], src[7] putUint32LE(buf[8:], uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|enc.padTail2) return bytesToString(buf[:]) case 16: buf := new([24]byte) encodeQuantum(t, buf[:], src) encodeQuantum(t, buf[4:], src[3:]) encodeQuantum(t, buf[8:], src[6:]) encodeQuantum(t, buf[12:], src[9:]) encodeQuantum(t, buf[16:], src[12:]) putUint32LE(buf[20:], t.enc1[src[15]]|enc.padTail1) return bytesToString(buf[:]) } } if enc.padChar == NoPadding && (enc.tables == stdEncodingTables || enc.tables == urlEncodingTables) { switch srcLen { case 8: return encodeStringStdPadded8Fast(enc.tables, src)[:11] case 16: return encodeStringStdPadded16Fast(enc.tables, src)[:22] } } if enc.isURLPadded() { switch srcLen { case 3: return encodeStringStdPadded3Fast(enc.tables, src) case 16: return encodeStringStdPadded16Fast(enc.tables, src) } } if enc.isStdPadded() { switch srcLen { case 1: return stdPadded1Strings[src[0]] case 2: return encodeStringStdPadded2Fast(enc.tables, src) case 3: return encodeStringStdPadded3(enc.tables, src) case 4: return encodeStringStdPadded4Fast(enc.tables, src) case 5: return encodeStringStdPadded5Fast(enc.tables, src) case 6: return encodeStringStdPadded6Fast(enc.tables, src) case 7: return encodeStringStdPadded7Fast(enc.tables, src) case 8: return encodeStringStdPadded8Fast(enc.tables, src) case 9, 10, 11, 12, 13, 14, 15: return encodeStringStdPadded9To15NoCache(enc.tables, src, srcLen) case 16: return encodeStringStdPadded16Fast(enc.tables, src) case 24: return encodeStringStdPadded24Fast(enc.tables, src) case 32: return encodeStringStdPadded32Fast(enc.tables, src) case 48: return encodeStringStdPadded48Fast(enc.tables, src) case 64: if s, ok := encodeStringStdMediumKnownNoCache(enc.tables, src); ok { return s } case 96: if sseBase64Available() { buf := makeNoZero(128) if encodeSSE42(enc, buf, src) { return bytesToString(buf) } } return encodeStringStdPadded96Fast(enc.tables, src) case 128: if s, ok := encodeStringStdMediumKnownNoCache(enc.tables, src); ok { return s } case 192: // The fixed full-quanta scalar path is faster than allocating and // entering SIMD at this size, even on AVX2-capable CPUs. return encodeStringStdPadded192Fast(enc.tables, src) } } return enc.encodeToStringNonEmpty(src) } func encodeStringStdPadded192Fast(t *encodingTables, src []byte) string { buf := makeNoZero(256) encodeFullQuantaScalar(t, buf, src) return bytesToString(buf) } func (enc *Encoding) encodeToStringNonEmpty(src []byte) string { srcLen := len(src) if srcLen <= maxSmallEncode { if enc.isURLPadded() { return encodeStringPaddedSmall(enc.tables, src) } if enc.kind == encodingStd && enc.padChar == StdPadding { switch { case srcLen == 1: return encodeStringStdPadded1Fast(enc.tables, src) case srcLen == 2: return encodeStringStdPadded2Fast(enc.tables, src) case srcLen == 3: return encodeStringStdPadded3(enc.tables, src) case srcLen == 4: return encodeStringStdPadded4Fast(enc.tables, src) case srcLen == 5: return encodeStringStdPadded5Fast(enc.tables, src) case srcLen == 6: return encodeStringStdPadded6Fast(enc.tables, src) case srcLen == 7: return encodeStringStdPadded7Fast(enc.tables, src) case srcLen == 8: return encodeStringStdPadded8Fast(enc.tables, src) case srcLen == 9: return encodeStringStdPadded9Fast(enc.tables, src) case srcLen == 10: return encodeStringStdPadded10Fast(enc.tables, src) case srcLen == 11: return encodeStringStdPadded11Fast(enc.tables, src) case srcLen == 12: return encodeStringStdPadded12Fast(enc.tables, src) case srcLen == 13: return encodeStringStdPadded13Fast(enc.tables, src) case srcLen == 14: return encodeStringStdPadded14Fast(enc.tables, src) case srcLen == 15: return encodeStringStdPadded15Fast(enc.tables, src) case srcLen == 16: return encodeStringStdPadded16Fast(enc.tables, src) case srcLen <= 18: buf := new([24]byte) encodeSmallStdPadded(enc.tables, buf[:], src) return bytesToString(buf[:]) case srcLen <= 21: buf := new([28]byte) encodeSmallStdPadded(enc.tables, buf[:], src) return bytesToString(buf[:]) case srcLen <= 24: buf := new([32]byte) encodeSmallStdPadded(enc.tables, buf[:], src) return bytesToString(buf[:]) default: n := int(encodedLenPaddedSmall[srcLen]) var buf [maxSmallEncodedPadded]byte encodeSmallStdPadded(enc.tables, buf[:], src) return string(buf[:n]) } } } if srcLen < 16 { if srcLen <= 2 && enc.padChar != NoPadding { // A padded 1- or 2-byte input always encodes to exactly 4 bytes; the // fixed-size buffer stays on the runtime tiny-allocator fast path and // one combined store with the precomputed padding mask fills it. t := enc.tables buf := new([4]byte) if srcLen == 1 { putUint32LE(buf[:], t.enc1[src[0]]|enc.padTail1) } else { b0, b1 := src[0], src[1] putUint32LE(buf[:], uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|enc.padTail2) } return bytesToString(buf[:]) } if srcLen <= 4 && enc.padChar == NoPadding { // Unpadded 1-4 byte inputs encode to exactly 2/3/4/6 bytes; inlining // the quantum and tail avoids the encodeTiny/encodeTail call chain. // The tables are per-encoding, so any alphabet is handled. t := enc.tables switch srcLen { case 1: b0 := src[0] buf := make([]byte, 2) buf[0] = t.encode[b0>>2] buf[1] = t.encode[(b0&0x03)<<4] return bytesToString(buf) case 2: b0, b1 := src[0], src[1] buf := make([]byte, 3) q := t.encQuad[int(b0)<<4|int(b1>>4)] buf[0] = byte(q) buf[1] = byte(q >> 8) buf[2] = t.encode[(b1&0x0f)<<2] return bytesToString(buf) case 3: buf := make([]byte, 4) val := uint32(src[0])<<16 | uint32(src[1])<<8 | uint32(src[2]) putUint32LE(buf, t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) return bytesToString(buf) default: buf := make([]byte, 6) val := uint32(src[0])<<16 | uint32(src[1])<<8 | uint32(src[2]) putUint32LE(buf, t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) b3 := src[3] buf[4] = t.encode[b3>>2] buf[5] = t.encode[(b3&0x03)<<4] return bytesToString(buf) } } buf := make([]byte, enc.encodedLenSmall(srcLen)) enc.encodeTiny(buf, src) return bytesToString(buf) } if srcLen <= maxSmallEncode { buf := makeNoZero(enc.encodedLenSmall(srcLen)) enc.encodeSmall(buf, src) return bytesToString(buf) } if enc.isStdPadded() && !encodeSIMDWillRun(enc, srcLen, minEncodeAVX2Alloc) { if s, ok := encodeStringStdMediumKnownNoCache(enc.tables, src); ok { return s } } if (enc.kind == encodingStd || enc.kind == encodingURL) && (enc.padChar == StdPadding || enc.padChar == NoPadding) && srcLen >= 512 && srcLen%3 == 0 && !encodeSIMDWillRun(enc, srcLen, minEncodeAVX2Alloc) { buf := makeNoZero(enc.EncodedLen(srcLen)) encodeFullQuantaScalar(enc.tables, buf, src) return bytesToString(buf) } if enc.kind == encodingStd && enc.padChar == StdPadding && !encodeSIMDWillRun(enc, srcLen, minEncodeAVX2Alloc) { buf := makeNoZero(enc.EncodedLen(srcLen)) encodeStdPaddedScalar(enc.tables, buf, src) return bytesToString(buf) } buf := makeNoZero(enc.EncodedLen(srcLen)) enc.encodeAllocated(buf, src) return bytesToString(buf) } func encodeStringStdMediumKnownNoCache(t *encodingTables, src []byte) (string, bool) { switch len(src) { case 64: return encodeStringStdPadded64Fast(t, src), true case 96: return encodeStringStdPadded96Fast(t, src), true case 128: buf := makeNoZero(172) encodeStdPaddedScalar(t, buf, src) return bytesToString(buf), true case 256: buf := makeNoZero(344) encodeStdPaddedScalar(t, buf, src) return bytesToString(buf), true case 512: buf := makeNoZero(684) encodeStdPaddedScalar(t, buf, src) return bytesToString(buf), true case 768: buf := makeNoZero(1024) encodeFullQuantaScalar(t, buf, src) return bytesToString(buf), true case 1024: buf := makeNoZero(1368) encodeStdPaddedScalar(t, buf, src) return bytesToString(buf), true case 1536: buf := makeNoZero(2048) encodeFullQuantaScalar(t, buf, src) return bytesToString(buf), true case 2048: buf := makeNoZero(2732) encodeStdPaddedScalar(t, buf, src) return bytesToString(buf), true } return "", false } func encodeStringStdPadded9To15NoCache(t *encodingTables, src []byte, n int) string { switch n { case 9: return encodeStringStdPadded9Fast(t, src) case 10: return encodeStringStdPadded10Fast(t, src) case 11: return encodeStringStdPadded11Fast(t, src) case 12: return encodeStringStdPadded12Fast(t, src) case 13: return encodeStringStdPadded13Fast(t, src) case 14: return encodeStringStdPadded14Fast(t, src) default: return encodeStringStdPadded15Fast(t, src) } } func encodeStringPaddedSmall(t *encodingTables, src []byte) string { switch srcLen := len(src); { case srcLen == 1: return encodeStringStdPadded1Fast(t, src) case srcLen == 2: return encodeStringStdPadded2Fast(t, src) case srcLen == 3: return encodeStringStdPadded3(t, src) case srcLen == 4: return encodeStringStdPadded4Fast(t, src) case srcLen == 5: return encodeStringStdPadded5Fast(t, src) case srcLen == 6: return encodeStringStdPadded6Fast(t, src) case srcLen == 7: return encodeStringStdPadded7Fast(t, src) case srcLen == 8: return encodeStringStdPadded8Fast(t, src) case srcLen == 9: return encodeStringStdPadded9Fast(t, src) case srcLen == 10: return encodeStringStdPadded10Fast(t, src) case srcLen == 11: return encodeStringStdPadded11Fast(t, src) case srcLen == 12: return encodeStringStdPadded12Fast(t, src) case srcLen == 13: return encodeStringStdPadded13Fast(t, src) case srcLen == 14: return encodeStringStdPadded14Fast(t, src) case srcLen == 15: return encodeStringStdPadded15Fast(t, src) case srcLen == 16: return encodeStringStdPadded16Fast(t, src) case srcLen <= 18: buf := new([24]byte) encodeSmallStdPadded(t, buf[:], src) return bytesToString(buf[:]) case srcLen <= 21: buf := new([28]byte) encodeSmallStdPadded(t, buf[:], src) return bytesToString(buf[:]) case srcLen <= 24: buf := new([32]byte) encodeSmallStdPadded(t, buf[:], src) return bytesToString(buf[:]) default: n := int(encodedLenPaddedSmall[srcLen]) var buf [maxSmallEncodedPadded]byte encodeSmallStdPadded(t, buf[:], src) return string(buf[:n]) } } func encodeStringStdPadded4To8NoZero(t *encodingTables, src []byte, srcLen int) string { buf := makeNoZero(int(encodedLenPaddedSmall[srcLen])) encodeStdPadded4To8Grouped(t, buf, src) return bytesToString(buf) } func encodeStdPadded4To8Grouped(t *encodingTables, dst, src []byte) { encodeQuantum(t, dst, src) switch len(src) { case 4, 5: encodeTailStd(t, dst[4:], src[3:]) case 6: encodeQuantum(t, dst[4:], src[3:]) case 7, 8: encodeQuantum(t, dst[4:], src[3:]) encodeTailStd(t, dst[8:], src[6:]) } } func encodeStringStdPadded1(t *encodingTables, src []byte) string { var buf [4]byte putUint32LE(buf[:], t.enc1[src[0]]|uint32('=')<<16|uint32('=')<<24) return string(buf[:]) } func encodeStringStdPadded2(t *encodingTables, src []byte) string { var buf [4]byte b0, b1 := src[0], src[1] putUint32LE(buf[:], uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|uint32('=')<<24) return string(buf[:]) } func encodeStringStdPadded3(t *encodingTables, src []byte) string { var buf [4]byte val := uint32(src[0])<<16 | uint32(src[1])<<8 | uint32(src[2]) putUint32LE(buf[:], t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) return string(buf[:]) } func encodeStringStdPadded4(t *encodingTables, src []byte) string { buf := make([]byte, 8) val := uint32(src[0])<<16 | uint32(src[1])<<8 | uint32(src[2]) putUint32LE(buf, t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) b0 := src[3] putUint32LE(buf[4:], uint32(t.encQuad[int(b0>>2)<<6|int((b0&0x03)<<4)])|uint32('=')<<16|uint32('=')<<24) return bytesToString(buf) } func encodeStringStdPadded5(t *encodingTables, src []byte) string { buf := new([8]byte) encodeQuantum(t, buf[:], src) encodeTailStd(t, buf[4:], src[3:]) return bytesToString(buf[:]) } func encodeStringStdPadded6(t *encodingTables, src []byte) string { buf := new([8]byte) encodeQuantum(t, buf[:], src) encodeQuantum(t, buf[4:], src[3:]) return bytesToString(buf[:]) } func encodeStringStdPadded7(t *encodingTables, src []byte) string { buf := new([12]byte) encodeQuantum(t, buf[:], src) encodeQuantum(t, buf[4:], src[3:]) encodeTailStd(t, buf[8:], src[6:]) return bytesToString(buf[:]) } func encodeStdPadded4(t *encodingTables, dst, src []byte) { encodeQuantum(t, dst, src) encodeTailStd(t, dst[4:], src[3:]) } func encodeStdPadded8(t *encodingTables, dst, src []byte) { encodeQuantum(t, dst, src) encodeQuantum(t, dst[4:], src[3:]) encodeTailStd(t, dst[8:], src[6:]) } func encodeStringStdPadded8(t *encodingTables, src []byte) string { var buf [12]byte val := uint32(src[0])<<16 | uint32(src[1])<<8 | uint32(src[2]) putUint32LE(buf[:], t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) val = uint32(src[3])<<16 | uint32(src[4])<<8 | uint32(src[5]) putUint32LE(buf[4:], t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) b0, b1 := src[6], src[7] putUint32LE(buf[8:], uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|uint32('=')<<24) return string(buf[:]) } func encodeStringStdPadded16(t *encodingTables, src []byte) string { buf := new([24]byte) val := uint32(src[0])<<16 | uint32(src[1])<<8 | uint32(src[2]) putUint32LE(buf[:], t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) val = uint32(src[3])<<16 | uint32(src[4])<<8 | uint32(src[5]) putUint32LE(buf[4:], t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) val = uint32(src[6])<<16 | uint32(src[7])<<8 | uint32(src[8]) putUint32LE(buf[8:], t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) val = uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11]) putUint32LE(buf[12:], t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) val = uint32(src[12])<<16 | uint32(src[13])<<8 | uint32(src[14]) putUint32LE(buf[16:], t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) b0 := src[15] putUint32LE(buf[20:], uint32(t.encQuad[int(b0>>2)<<6|int((b0&0x03)<<4)])|uint32('=')<<16|uint32('=')<<24) return bytesToString(buf[:]) } // EncodeToBytes returns the base64 encoding of src as a new byte slice. func (enc *Encoding) EncodeToBytes(src []byte) []byte { srcLen := len(src) if srcLen == 0 { return emptyBytes } if enc.tables == nil { alphabet := enc.customAlphabet() switch srcLen { case 1: b0 := src[0] c0, c1 := alphabet[b0>>2], alphabet[(b0&0x03)<<4] if enc.padChar == NoPadding { return []byte{c0, c1} } pad := byte(enc.padChar) return []byte{c0, c1, pad, pad} case 2: b0, b1 := src[0], src[1] c0 := alphabet[b0>>2] c1 := alphabet[(b0&0x03)<<4|b1>>4] c2 := alphabet[(b1&0x0f)<<2] if enc.padChar == NoPadding { return []byte{c0, c1, c2} } return []byte{c0, c1, c2, byte(enc.padChar)} case 3: b0, b1, b2 := src[0], src[1], src[2] return []byte{ alphabet[b0>>2], alphabet[(b0&0x03)<<4|b1>>4], alphabet[(b1&0x0f)<<2|b2>>6], alphabet[b2&0x3f], } case 8: b0, b1, b2 := src[0], src[1], src[2] b3, b4, b5 := src[3], src[4], src[5] b6, b7 := src[6], src[7] if enc.padChar == NoPadding { return []byte{ alphabet[b0>>2], alphabet[(b0&0x03)<<4|b1>>4], alphabet[(b1&0x0f)<<2|b2>>6], alphabet[b2&0x3f], alphabet[b3>>2], alphabet[(b3&0x03)<<4|b4>>4], alphabet[(b4&0x0f)<<2|b5>>6], alphabet[b5&0x3f], alphabet[b6>>2], alphabet[(b6&0x03)<<4|b7>>4], alphabet[(b7&0x0f)<<2], } } return []byte{ alphabet[b0>>2], alphabet[(b0&0x03)<<4|b1>>4], alphabet[(b1&0x0f)<<2|b2>>6], alphabet[b2&0x3f], alphabet[b3>>2], alphabet[(b3&0x03)<<4|b4>>4], alphabet[(b4&0x0f)<<2|b5>>6], alphabet[b5&0x3f], alphabet[b6>>2], alphabet[(b6&0x03)<<4|b7>>4], alphabet[(b7&0x0f)<<2], byte(enc.padChar), } case 12: buf := make([]byte, 16) putUint32LE(buf, encodeAlphabetWord(alphabet, src[0], src[1], src[2])) putUint32LE(buf[4:], encodeAlphabetWord(alphabet, src[3], src[4], src[5])) putUint32LE(buf[8:], encodeAlphabetWord(alphabet, src[6], src[7], src[8])) putUint32LE(buf[12:], encodeAlphabetWord(alphabet, src[9], src[10], src[11])) return buf } buf := make([]byte, enc.EncodedLen(srcLen)) enc.Encode(buf, src) return buf } if srcLen == 2 && enc.kind == encodingURL && enc.padChar == StdPadding { t := enc.tables b0, b1 := src[0], src[1] return []byte{ t.encode[b0>>2], t.encode[(b0&0x03)<<4|b1>>4], t.encode[(b1&0x0f)<<2], '=', } } if !enc.isStdPadded() { switch srcLen { case 1: return encodeBytesGeneric1(enc, src) case 2: return encodeBytesGeneric2(enc, src) case 3: return encodeBytesGeneric3(enc.tables, src) case 4: t := enc.tables n := 8 if enc.padChar == NoPadding { n = 6 } buf := make([]byte, n) encodeQuantum(t, buf, src) b0 := src[3] buf[4] = t.encode[b0>>2] buf[5] = t.encode[(b0&0x03)<<4] if n == 8 { pad := byte(enc.padChar) buf[6], buf[7] = pad, pad } return buf case 8: t := enc.tables n := 12 if enc.padChar == NoPadding { n = 11 } buf := make([]byte, n) encodeQuantum(t, buf, src) encodeQuantum(t, buf[4:], src[3:]) b0, b1 := src[6], src[7] buf[8] = t.encode[b0>>2] buf[9] = t.encode[(b0&0x03)<<4|b1>>4] buf[10] = t.encode[(b1&0x0f)<<2] if n == 12 { buf[11] = byte(enc.padChar) } return buf case 16: t := enc.tables n := 24 if enc.padChar == NoPadding { n = 22 } buf := make([]byte, n) encodeQuantum(t, buf, src) encodeQuantum(t, buf[4:], src[3:]) encodeQuantum(t, buf[8:], src[6:]) encodeQuantum(t, buf[12:], src[9:]) encodeQuantum(t, buf[16:], src[12:]) b0 := src[15] buf[20] = t.encode[b0>>2] buf[21] = t.encode[(b0&0x03)<<4] if n == 24 { pad := byte(enc.padChar) buf[22], buf[23] = pad, pad } return buf case 32: // encodeStdPadded32 is alphabet-agnostic (per-encoding tables); only // its final hardcoded '=' needs adjusting, so every padding mode can // share the fast quantum kernel. make(43) and make(44) land in the // same allocator sizeclass, so the NoPadding reslice costs nothing. buf := make([]byte, 44) encodeStdPadded32(enc.tables, buf, src) switch enc.padChar { case StdPadding: return buf case NoPadding: return buf[:43] default: buf[43] = byte(enc.padChar) return buf } } } if srcLen == 1 && enc.isStdPadded() { b0 := src[0] t := enc.tables return []byte{t.encode[b0>>2], t.encode[(b0&0x03)<<4], '=', '='} } if enc.isStdPadded() { t := enc.tables switch srcLen { case 2: b0, b1 := src[0], src[1] return []byte{ t.encode[b0>>2], t.encode[(b0&0x03)<<4|b1>>4], t.encode[(b1&0x0f)<<2], '=', } case 3: b0, b1, b2 := src[0], src[1], src[2] return []byte{ t.encode[b0>>2], t.encode[(b0&0x03)<<4|b1>>4], t.encode[(b1&0x0f)<<2|b2>>6], t.encode[b2&0x3f], } } } return enc.encodeToBytesNonEmptyPublic(src, srcLen) } func encodeBytesGeneric1(enc *Encoding, src []byte) []byte { t := enc.tables b0 := src[0] if enc.padChar == NoPadding { return []byte{t.encode[b0>>2], t.encode[(b0&0x03)<<4]} } buf := new([4]byte) putUint32LE(buf[:], t.enc1[b0]|enc.padTail1) return buf[:] } func encodeBytesGeneric2(enc *Encoding, src []byte) []byte { t := enc.tables b0, b1 := src[0], src[1] if enc.padChar == NoPadding { return []byte{ t.encode[b0>>2], t.encode[(b0&0x03)<<4|b1>>4], t.encode[(b1&0x0f)<<2], } } buf := new([4]byte) putUint32LE(buf[:], uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|enc.padTail2) return buf[:] } func encodeBytesGeneric3(t *encodingTables, src []byte) []byte { b0, b1, b2 := src[0], src[1], src[2] return []byte{ t.encode[b0>>2], t.encode[(b0&0x03)<<4|b1>>4], t.encode[(b1&0x0f)<<2|b2>>6], t.encode[b2&0x3f], } } func (enc *Encoding) encodeToBytesNonEmptyPublic(src []byte, srcLen int) []byte { if enc.isStdPadded() { switch srcLen { case 1: return encodeBytesStdPadded1Fast(enc.tables, src) case 2: return encodeBytesStdPadded2Fast(enc.tables, src) case 3: return encodeBytesStdPadded3Fast(enc.tables, src) case 4: t := enc.tables buf := make([]byte, 8) val := uint32(src[0])<<16 | uint32(src[1])<<8 | uint32(src[2]) putUint32LE(buf, t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) b0 := src[3] putUint32LE(buf[4:], uint32(t.encQuad[int(b0>>2)<<6|int((b0&0x03)<<4)])|uint32('=')<<16|uint32('=')<<24) return buf case 5: return encodeBytesStdPadded5Fast(enc.tables, src) case 6: return encodeBytesStdPadded6Fast(enc.tables, src) case 7: t := enc.tables buf := make([]byte, 12) val := uint32(src[0])<<16 | uint32(src[1])<<8 | uint32(src[2]) putUint32LE(buf, t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) val = uint32(src[3])<<16 | uint32(src[4])<<8 | uint32(src[5]) putUint32LE(buf[4:], t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) b0 := src[6] putUint32LE(buf[8:], uint32(t.encQuad[int(b0>>2)<<6|int((b0&0x03)<<4)])|uint32('=')<<16|uint32('=')<<24) return buf case 8: t := enc.tables buf := make([]byte, 12) val := uint32(src[0])<<16 | uint32(src[1])<<8 | uint32(src[2]) putUint32LE(buf, t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) val = uint32(src[3])<<16 | uint32(src[4])<<8 | uint32(src[5]) putUint32LE(buf[4:], t.encQuad[val>>12]|t.encQuad[val&0x0fff]<<16) b0, b1 := src[6], src[7] putUint32LE(buf[8:], uint32(t.encQuad[int(b0)<<4|int(b1>>4)])|uint32(t.encode[(b1&0x0f)<<2])<<16|uint32('=')<<24) return buf case 9: return encodeBytesStdPadded9Fast(enc.tables, src) case 10: return encodeBytesStdPadded10Fast(enc.tables, src) case 11: return encodeBytesStdPadded11Fast(enc.tables, src) case 12: return encodeBytesStdPadded12Fast(enc.tables, src) case 13: return encodeBytesStdPadded13Fast(enc.tables, src) case 14: return encodeBytesStdPadded14Fast(enc.tables, src) case 15: return encodeBytesStdPadded15Fast(enc.tables, src) case 16: buf := make([]byte, 24) encodeSmallStdPadded(enc.tables, buf, src) return buf case 24: buf := make([]byte, 32) encodeSmallStdPadded(enc.tables, buf, src) return buf case 32: buf := make([]byte, 44) encodeStdPadded32(enc.tables, buf, src) return buf } } return enc.encodeToBytesNonEmpty(src) } func (enc *Encoding) encodeToBytesNonEmpty(src []byte) []byte { srcLen := len(src) var buf []byte if srcLen <= maxSmallEncode && enc.kind == encodingStd && enc.padChar == StdPadding { buf = make([]byte, enc.encodedLenSmall(srcLen)) if srcLen < 16 { encodeTinyStdPadded(enc.tables, buf, src) } else { encodeSmallStdPadded(enc.tables, buf, src) } return buf } if srcLen < 16 { buf = make([]byte, enc.encodedLenSmall(srcLen)) enc.encodeTiny(buf, src) return buf } if srcLen <= maxSmallEncode { buf = make([]byte, enc.encodedLenSmall(srcLen)) enc.encodeSmall(buf, src) return buf } buf = make([]byte, enc.EncodedLen(srcLen)) enc.encodeAllocated(buf, src) return buf } // EncodeString returns the base64 encoding of src as a new byte slice. func (enc *Encoding) EncodeString(src string) []byte { return enc.EncodeToBytes(stringToBytes(src)) } // EncodeStringToString returns the base64 encoding of src as a string. func (enc *Encoding) EncodeStringToString(src string) string { return enc.EncodeToString(stringToBytes(src)) } func (enc *Encoding) encodeLazyCustom(dst, src []byte) { alphabet := enc.customAlphabet() si := 0 if len(src) >= 51 { si = encodeLazyCustomASMPrefix(dst, src, alphabet) } di := si / 3 * 4 for len(src)-si >= 12 { _ = src[si+11] _ = dst[di+15] putUint32LE(dst[di:], encodeAlphabetWord(alphabet, src[si], src[si+1], src[si+2])) putUint32LE(dst[di+4:], encodeAlphabetWord(alphabet, src[si+3], src[si+4], src[si+5])) putUint32LE(dst[di+8:], encodeAlphabetWord(alphabet, src[si+6], src[si+7], src[si+8])) putUint32LE(dst[di+12:], encodeAlphabetWord(alphabet, src[si+9], src[si+10], src[si+11])) si += 12 di += 16 } for len(src)-si >= 3 { putUint32LE(dst[di:], encodeAlphabetWord(alphabet, src[si], src[si+1], src[si+2])) si += 3 di += 4 } remaining := len(src) - si if remaining == 0 { return } b0 := src[si] dst[di] = alphabet[b0>>2] if remaining == 1 { dst[di+1] = alphabet[(b0&0x03)<<4] if enc.padChar != NoPadding { pad := byte(enc.padChar) dst[di+2], dst[di+3] = pad, pad } return } b1 := src[si+1] dst[di+1] = alphabet[(b0&0x03)<<4|b1>>4] dst[di+2] = alphabet[(b1&0x0f)<<2] if enc.padChar != NoPadding { dst[di+3] = byte(enc.padChar) } } func (enc *Encoding) encodeLazyCustomSmall(dst, src []byte) { alphabet := enc.customAlphabet() switch len(src) { case 1: b0 := src[0] v := uint32(alphabet[b0>>2]) | uint32(alphabet[(b0&0x03)<<4])<<8 if enc.padChar == NoPadding { putUint16LE(dst, uint16(v)) } else { putUint32LE(dst, v|enc.padTail1) } return case 2: b0, b1 := src[0], src[1] v := uint32(alphabet[b0>>2]) | uint32(alphabet[(b0&0x03)<<4|b1>>4])<<8 | uint32(alphabet[(b1&0x0f)<<2])<<16 if enc.padChar == NoPadding { putUint16LE(dst, uint16(v)) dst[2] = byte(v >> 16) } else { putUint32LE(dst, v|enc.padTail2) } return case 3: putUint32LE(dst, encodeAlphabetWord(alphabet, src[0], src[1], src[2])) return } fullQuanta := len(src) / 3 switch fullQuanta { case 10: putUint32LE(dst[36:], encodeAlphabetWord(alphabet, src[27], src[28], src[29])) fallthrough case 9: putUint32LE(dst[32:], encodeAlphabetWord(alphabet, src[24], src[25], src[26])) fallthrough case 8: putUint32LE(dst[28:], encodeAlphabetWord(alphabet, src[21], src[22], src[23])) fallthrough case 7: putUint32LE(dst[24:], encodeAlphabetWord(alphabet, src[18], src[19], src[20])) fallthrough case 6: putUint32LE(dst[20:], encodeAlphabetWord(alphabet, src[15], src[16], src[17])) fallthrough case 5: putUint32LE(dst[16:], encodeAlphabetWord(alphabet, src[12], src[13], src[14])) fallthrough case 4: putUint32LE(dst[12:], encodeAlphabetWord(alphabet, src[9], src[10], src[11])) fallthrough case 3: putUint32LE(dst[8:], encodeAlphabetWord(alphabet, src[6], src[7], src[8])) fallthrough case 2: putUint32LE(dst[4:], encodeAlphabetWord(alphabet, src[3], src[4], src[5])) fallthrough case 1: putUint32LE(dst, encodeAlphabetWord(alphabet, src[0], src[1], src[2])) } si := fullQuanta * 3 remaining := len(src) - si if remaining == 0 { return } di := fullQuanta * 4 b0 := src[si] dst[di] = alphabet[b0>>2] if remaining == 1 { dst[di+1] = alphabet[(b0&0x03)<<4] if enc.padChar != NoPadding { pad := byte(enc.padChar) dst[di+2], dst[di+3] = pad, pad } return } b1 := src[si+1] dst[di+1] = alphabet[(b0&0x03)<<4|b1>>4] dst[di+2] = alphabet[(b1&0x0f)<<2] if enc.padChar != NoPadding { dst[di+3] = byte(enc.padChar) } } func encodeAlphabetWord(alphabet *[64]byte, b0, b1, b2 byte) uint32 { return uint32(alphabet[b0>>2]) | uint32(alphabet[(b0&0x03)<<4|b1>>4])<<8 | uint32(alphabet[(b1&0x0f)<<2|b2>>6])<<16 | uint32(alphabet[b2&0x3f])<<24 }