Использование метода Go base64.StdEncoding.Decode (): как выбрать размер целевого байтового фрагмента? - PullRequest
1 голос
/ 11 декабря 2019

Я хотел бы использовать Decode (https://golang.org/pkg/encoding/base64/#Encoding.Decode) для декодирования фрагмента байтов и задавался вопросом, учитывая сигнатуру этого метода,

func (enc *Encoding) Decode(dst, src []byte) (n int, err error)

, как выбрать размерdst кусок байтов должен быть достаточно большим, чтобы захватить вывод. Например, этот фрагмент (адаптированный из https://golang.org/pkg/encoding/base64/#Encoding.DecodeString)

package main

import (
    "encoding/base64"
    "fmt"
)

func main() {
    str := "c29tZSBkYXRhIHdpdGggACBhbmQg77u/"
    dst := make([]byte, 1024)
    _, err := base64.StdEncoding.Decode(dst, []byte(str))
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    fmt.Printf("%s\n", dst)
}

печатает

some data with  and 

Однако, если явыбирая размер dst слишком мал (например, 0), я получаю index out of range панику:

panic: runtime error: index out of range

goroutine 1 [running]:
encoding/base64.(*Encoding).decodeQuantum(0xc000084000, 0x1193018, 0x0, 0x0, 0xc000080f30, 0x20, 0x20, 0x4, 0x10, 0x10, ...)
    /usr/local/Cellar/go@1.12/1.12.12/libexec/src/encoding/base64/base64.go:352 +0x567
encoding/base64.(*Encoding).Decode(0xc000084000, 0x1193018, 0x0, 0x0, 0xc000080f30, 0x20, 0x20, 0xc000080f38, 0x105779d, 0x10b16e0)
    /usr/local/Cellar/go@1.12/1.12.12/libexec/src/encoding/base64/base64.go:500 +0x5aa
main.main()
    /Users/kurt/Documents/Scratch/base64_decode.go:11 +0xb4
exit status 2

Как выбрать размер dst в зависимости от размера src надежно декодировать ввод?

Ответы [ 2 ]

3 голосов
/ 11 декабря 2019

Вы должны использовать base64.DecodedLen, чтобы найти максимальный размер, необходимый для декодирования ввода, а затем использовать n, возвращаемый из Decode, чтобы узнать, как долго он действительно записывал в этот фрагмент.

0 голосов
/ 11 декабря 2019

После комментария jps и чтения на https://en.wikipedia.org/wiki/Base64,, поскольку вход кодируется в 8-битных байтах, а выход - в 6-битных (radix-64),вывод должен быть в 8/6 = 4/3 раза больше размера ввода. Так что это должно работать:

package main

import (
    "encoding/base64"
    "fmt"
)

func main() {
    str := "c29tZSBkYXRhIHdpdGggACBhbmQg77u/"
    dst := make([]byte, len(str)*len(str)/base64.StdEncoding.DecodedLen(len(str)))
    _, err := base64.StdEncoding.Decode(dst, []byte(str))
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    fmt.Printf("%s\n", dst)
}

на основе реализации DecodedLen(), которая при нормальных обстоятельствах возвращает продолжительность времени ввода 3/4:

// DecodedLen returns the maximum length in bytes of the decoded data
// corresponding to n bytes of base64-encoded data.
func (enc *Encoding) DecodedLen(n int) int {
    if enc.padChar == NoPadding {
        // Unpadded data may end with partial block of 2-3 characters.
        return n * 6 / 8
    }
    // Padded base64 should always be a multiple of 4 characters in length.
    return n / 4 * 3
}

В конце концов,тем не менее, я просто преобразовал входные данные в строку и использовал DecodeString(), поскольку это уже воплощает эту логику.

...