d28f005552
Fix limit for databases other than sqlite go mod tidy && go mod vendor Remove unneeded break statements Make everything work with the new xorm version Fix xorm logging Fix lint Fix redis init Fix using id field Fix database init for testing Change default database log level Add xorm logger Use const for postgres go mod tidy Merge branch 'master' into update/xorm # Conflicts: # go.mod # go.sum # vendor/modules.txt go mod vendor Fix loading fixtures for postgres Go mod vendor1 Update xorm to version 1 Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/323
237 lines
5.9 KiB
Go
237 lines
5.9 KiB
Go
// Copyright 2011 The Snappy-Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package snappy
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"io"
|
|
)
|
|
|
|
var (
|
|
// ErrCorrupt reports that the input is invalid.
|
|
ErrCorrupt = errors.New("snappy: corrupt input")
|
|
// ErrTooLarge reports that the uncompressed length is too large.
|
|
ErrTooLarge = errors.New("snappy: decoded block is too large")
|
|
// ErrUnsupported reports that the input isn't supported.
|
|
ErrUnsupported = errors.New("snappy: unsupported input")
|
|
|
|
errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length")
|
|
)
|
|
|
|
// DecodedLen returns the length of the decoded block.
|
|
func DecodedLen(src []byte) (int, error) {
|
|
v, _, err := decodedLen(src)
|
|
return v, err
|
|
}
|
|
|
|
// decodedLen returns the length of the decoded block and the number of bytes
|
|
// that the length header occupied.
|
|
func decodedLen(src []byte) (blockLen, headerLen int, err error) {
|
|
v, n := binary.Uvarint(src)
|
|
if n <= 0 || v > 0xffffffff {
|
|
return 0, 0, ErrCorrupt
|
|
}
|
|
|
|
const wordSize = 32 << (^uint(0) >> 32 & 1)
|
|
if wordSize == 32 && v > 0x7fffffff {
|
|
return 0, 0, ErrTooLarge
|
|
}
|
|
return int(v), n, nil
|
|
}
|
|
|
|
const (
|
|
decodeErrCodeCorrupt = 1
|
|
decodeErrCodeUnsupportedLiteralLength = 2
|
|
)
|
|
|
|
// Decode returns the decoded form of src. The returned slice may be a sub-
|
|
// slice of dst if dst was large enough to hold the entire decoded block.
|
|
// Otherwise, a newly allocated slice will be returned.
|
|
//
|
|
// The dst and src must not overlap. It is valid to pass a nil dst.
|
|
func Decode(dst, src []byte) ([]byte, error) {
|
|
dLen, s, err := decodedLen(src)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if dLen <= len(dst) {
|
|
dst = dst[:dLen]
|
|
} else {
|
|
dst = make([]byte, dLen)
|
|
}
|
|
switch decode(dst, src[s:]) {
|
|
case 0:
|
|
return dst, nil
|
|
case decodeErrCodeUnsupportedLiteralLength:
|
|
return nil, errUnsupportedLiteralLength
|
|
}
|
|
return nil, ErrCorrupt
|
|
}
|
|
|
|
// NewReader returns a new Reader that decompresses from r, using the framing
|
|
// format described at
|
|
// https://github.com/google/snappy/blob/master/framing_format.txt
|
|
func NewReader(r io.Reader) *Reader {
|
|
return &Reader{
|
|
r: r,
|
|
decoded: make([]byte, maxBlockSize),
|
|
buf: make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize),
|
|
}
|
|
}
|
|
|
|
// Reader is an io.Reader that can read Snappy-compressed bytes.
|
|
type Reader struct {
|
|
r io.Reader
|
|
err error
|
|
decoded []byte
|
|
buf []byte
|
|
// decoded[i:j] contains decoded bytes that have not yet been passed on.
|
|
i, j int
|
|
readHeader bool
|
|
}
|
|
|
|
// Reset discards any buffered data, resets all state, and switches the Snappy
|
|
// reader to read from r. This permits reusing a Reader rather than allocating
|
|
// a new one.
|
|
func (r *Reader) Reset(reader io.Reader) {
|
|
r.r = reader
|
|
r.err = nil
|
|
r.i = 0
|
|
r.j = 0
|
|
r.readHeader = false
|
|
}
|
|
|
|
func (r *Reader) readFull(p []byte, allowEOF bool) (ok bool) {
|
|
if _, r.err = io.ReadFull(r.r, p); r.err != nil {
|
|
if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) {
|
|
r.err = ErrCorrupt
|
|
}
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Read satisfies the io.Reader interface.
|
|
func (r *Reader) Read(p []byte) (int, error) {
|
|
if r.err != nil {
|
|
return 0, r.err
|
|
}
|
|
for {
|
|
if r.i < r.j {
|
|
n := copy(p, r.decoded[r.i:r.j])
|
|
r.i += n
|
|
return n, nil
|
|
}
|
|
if !r.readFull(r.buf[:4], true) {
|
|
return 0, r.err
|
|
}
|
|
chunkType := r.buf[0]
|
|
if !r.readHeader {
|
|
if chunkType != chunkTypeStreamIdentifier {
|
|
r.err = ErrCorrupt
|
|
return 0, r.err
|
|
}
|
|
r.readHeader = true
|
|
}
|
|
chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
|
|
if chunkLen > len(r.buf) {
|
|
r.err = ErrUnsupported
|
|
return 0, r.err
|
|
}
|
|
|
|
// The chunk types are specified at
|
|
// https://github.com/google/snappy/blob/master/framing_format.txt
|
|
switch chunkType {
|
|
case chunkTypeCompressedData:
|
|
// Section 4.2. Compressed data (chunk type 0x00).
|
|
if chunkLen < checksumSize {
|
|
r.err = ErrCorrupt
|
|
return 0, r.err
|
|
}
|
|
buf := r.buf[:chunkLen]
|
|
if !r.readFull(buf, false) {
|
|
return 0, r.err
|
|
}
|
|
checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
|
|
buf = buf[checksumSize:]
|
|
|
|
n, err := DecodedLen(buf)
|
|
if err != nil {
|
|
r.err = err
|
|
return 0, r.err
|
|
}
|
|
if n > len(r.decoded) {
|
|
r.err = ErrCorrupt
|
|
return 0, r.err
|
|
}
|
|
if _, err := Decode(r.decoded, buf); err != nil {
|
|
r.err = err
|
|
return 0, r.err
|
|
}
|
|
if crc(r.decoded[:n]) != checksum {
|
|
r.err = ErrCorrupt
|
|
return 0, r.err
|
|
}
|
|
r.i, r.j = 0, n
|
|
continue
|
|
|
|
case chunkTypeUncompressedData:
|
|
// Section 4.3. Uncompressed data (chunk type 0x01).
|
|
if chunkLen < checksumSize {
|
|
r.err = ErrCorrupt
|
|
return 0, r.err
|
|
}
|
|
buf := r.buf[:checksumSize]
|
|
if !r.readFull(buf, false) {
|
|
return 0, r.err
|
|
}
|
|
checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
|
|
// Read directly into r.decoded instead of via r.buf.
|
|
n := chunkLen - checksumSize
|
|
if n > len(r.decoded) {
|
|
r.err = ErrCorrupt
|
|
return 0, r.err
|
|
}
|
|
if !r.readFull(r.decoded[:n], false) {
|
|
return 0, r.err
|
|
}
|
|
if crc(r.decoded[:n]) != checksum {
|
|
r.err = ErrCorrupt
|
|
return 0, r.err
|
|
}
|
|
r.i, r.j = 0, n
|
|
continue
|
|
|
|
case chunkTypeStreamIdentifier:
|
|
// Section 4.1. Stream identifier (chunk type 0xff).
|
|
if chunkLen != len(magicBody) {
|
|
r.err = ErrCorrupt
|
|
return 0, r.err
|
|
}
|
|
if !r.readFull(r.buf[:len(magicBody)], false) {
|
|
return 0, r.err
|
|
}
|
|
for i := 0; i < len(magicBody); i++ {
|
|
if r.buf[i] != magicBody[i] {
|
|
r.err = ErrCorrupt
|
|
return 0, r.err
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
|
|
if chunkType <= 0x7f {
|
|
// Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
|
|
r.err = ErrUnsupported
|
|
return 0, r.err
|
|
}
|
|
// Section 4.4 Padding (chunk type 0xfe).
|
|
// Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
|
|
if !r.readFull(r.buf[:chunkLen], false) {
|
|
return 0, r.err
|
|
}
|
|
}
|
|
}
|