mirror of
https://github.com/wader/fq.git
synced 2024-12-26 15:02:28 +03:00
3b717c3ba4
Add toxml/fromxml for XML encoding, mighe be lossy on ordering fromxml has {seq:bool} to add #seq attributes to improve ordering toxml has {indent:number} to choose space indent depth Add tojson, same as in jq but also has {indent:number} options Add toyaml/fromyaml for YAML Add totoml/fromtoml for TOML Add tojq/fromjq for jq-flavored JSON (optional quotes for keys, comments and trailing commas support) Add tocsv/fromcsv for CSV formcvs takes {comma:string, comment:string} for custom separtor and comment character Rename/split hex into tohex/fromhex Rename/split base64 into tobase64/frombase64 tobase64/frombase64 takes {encoding:string} option for base64 flavour (std, url, rawstd, rawurl) Add to/from<format> urlpath, urlquery, url, xmlentities, base64, hex Add to<hash> md4, md5, sha1, sha256, sha512, sha3_224, sha3_256, sha3_384, sha3_512 Add to/from<encoding> iso8859-1, utf8, utf16, utf16le, utf16be
121 lines
2.4 KiB
Go
121 lines
2.4 KiB
Go
package interp
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/wader/fq/pkg/bitio"
|
|
"github.com/wader/fq/pkg/decode"
|
|
|
|
"github.com/wader/gojq"
|
|
)
|
|
|
|
// TODO: move things in funcs.go/jq elsewere
|
|
|
|
func init() {
|
|
functionRegisterFns = append(functionRegisterFns, func(i *Interp) []Function {
|
|
return []Function{
|
|
{"_hexdump", 1, 1, nil, i._hexdump},
|
|
|
|
{"nal_unescape", 0, 0, makeBinaryTransformFn(func(r io.Reader) (io.Reader, error) {
|
|
return &decode.NALUnescapeReader{Reader: r}, nil
|
|
}), nil},
|
|
|
|
{"aes_ctr", 1, 2, i.aesCtr, nil},
|
|
}
|
|
})
|
|
}
|
|
|
|
// transform to binary using fn
|
|
func makeBinaryTransformFn(fn func(r io.Reader) (io.Reader, error)) func(c any, a []any) any {
|
|
return func(c any, a []any) any {
|
|
inBR, err := toBitReader(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
r, err := fn(bitio.NewIOReader(inBR))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
outBuf := &bytes.Buffer{}
|
|
if _, err := io.Copy(outBuf, r); err != nil {
|
|
return err
|
|
}
|
|
|
|
outBR := bitio.NewBitReader(outBuf.Bytes(), -1)
|
|
|
|
bb, err := newBinaryFromBitReader(outBR, 8, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return bb
|
|
}
|
|
}
|
|
|
|
func (i *Interp) aesCtr(c any, a []any) any {
|
|
keyBytes, err := toBytes(a[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch len(keyBytes) {
|
|
case 16, 24, 32:
|
|
default:
|
|
return fmt.Errorf("key length should be 16, 24 or 32 bytes, is %d bytes", len(keyBytes))
|
|
}
|
|
|
|
block, err := aes.NewCipher(keyBytes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var ivBytes []byte
|
|
if len(a) >= 2 {
|
|
var err error
|
|
ivBytes, err = toBytes(a[1])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(ivBytes) != block.BlockSize() {
|
|
return fmt.Errorf("iv length should be %d bytes, is %d bytes", block.BlockSize(), len(ivBytes))
|
|
}
|
|
} else {
|
|
ivBytes = make([]byte, block.BlockSize())
|
|
}
|
|
|
|
br, err := toBitReader(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
buf := &bytes.Buffer{}
|
|
reader := &cipher.StreamReader{S: cipher.NewCTR(block, ivBytes), R: bitio.NewIOReader(br)}
|
|
if _, err := io.Copy(buf, reader); err != nil {
|
|
return err
|
|
}
|
|
|
|
bb, err := newBinaryFromBitReader(bitio.NewBitReader(buf.Bytes(), -1), 8, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return bb
|
|
}
|
|
|
|
func (i *Interp) _hexdump(c any, a []any) gojq.Iter {
|
|
opts := i.Options(a[0])
|
|
bv, err := toBinary(c)
|
|
if err != nil {
|
|
return gojq.NewIter(err)
|
|
}
|
|
if err := hexdump(i.evalInstance.output, bv, opts); err != nil {
|
|
return gojq.NewIter(err)
|
|
}
|
|
|
|
return gojq.NewIter()
|
|
}
|