2020-04-28 08:41:59 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base64"
|
|
|
|
"encoding/hex"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
|
2020-06-02 18:12:53 +00:00
|
|
|
"github.com/urfave/cli/v2"
|
2020-06-05 22:59:01 +00:00
|
|
|
"golang.org/x/xerrors"
|
2020-04-28 08:41:59 +00:00
|
|
|
|
2020-05-12 21:22:21 +00:00
|
|
|
"github.com/filecoin-project/go-bitfield"
|
2020-04-28 08:41:59 +00:00
|
|
|
rlepluslazy "github.com/filecoin-project/go-bitfield/rle"
|
|
|
|
)
|
|
|
|
|
|
|
|
var bitFieldCmd = &cli.Command{
|
|
|
|
Name: "bitfield",
|
|
|
|
Description: "analyze bitfields",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "enc",
|
|
|
|
Value: "base64",
|
|
|
|
Usage: "specify input encoding to parse",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Subcommands: []*cli.Command{
|
|
|
|
bitFieldRunsCmd,
|
|
|
|
bitFieldStatCmd,
|
2020-05-12 21:22:21 +00:00
|
|
|
bitFieldDecodeCmd,
|
2020-09-17 17:57:42 +00:00
|
|
|
bitFieldIntersectCmd,
|
2020-04-28 08:41:59 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var bitFieldRunsCmd = &cli.Command{
|
|
|
|
Name: "runs",
|
|
|
|
Description: "print bit runs in a bitfield",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "enc",
|
|
|
|
Value: "base64",
|
|
|
|
Usage: "specify input encoding to parse",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
var val string
|
|
|
|
if cctx.Args().Present() {
|
|
|
|
val = cctx.Args().Get(0)
|
|
|
|
} else {
|
|
|
|
b, err := ioutil.ReadAll(os.Stdin)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
val = string(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
var dec []byte
|
|
|
|
switch cctx.String("enc") {
|
|
|
|
case "base64":
|
|
|
|
d, err := base64.StdEncoding.DecodeString(val)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("decoding base64 value: %w", err)
|
|
|
|
}
|
|
|
|
dec = d
|
|
|
|
case "hex":
|
|
|
|
d, err := hex.DecodeString(val)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("decoding hex value: %w", err)
|
|
|
|
}
|
|
|
|
dec = d
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("unrecognized encoding: %s", cctx.String("enc"))
|
|
|
|
}
|
|
|
|
|
|
|
|
rle, err := rlepluslazy.FromBuf(dec)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("opening rle: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
rit, err := rle.RunIterator()
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("getting run iterator: %w", err)
|
|
|
|
}
|
|
|
|
var idx uint64
|
|
|
|
for rit.HasNext() {
|
|
|
|
r, err := rit.NextRun()
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("next run: %w", err)
|
|
|
|
}
|
|
|
|
if !r.Valid() {
|
|
|
|
fmt.Print("!INVALID ")
|
|
|
|
}
|
|
|
|
s := "TRUE "
|
|
|
|
if !r.Val {
|
|
|
|
s = "FALSE"
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Printf("@%d %s * %d\n", idx, s, r.Len)
|
|
|
|
|
|
|
|
idx += r.Len
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var bitFieldStatCmd = &cli.Command{
|
|
|
|
Name: "stat",
|
|
|
|
Description: "print bitfield stats",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "enc",
|
|
|
|
Value: "base64",
|
|
|
|
Usage: "specify input encoding to parse",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
var val string
|
|
|
|
if cctx.Args().Present() {
|
|
|
|
val = cctx.Args().Get(0)
|
|
|
|
} else {
|
|
|
|
b, err := ioutil.ReadAll(os.Stdin)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
val = string(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
var dec []byte
|
|
|
|
switch cctx.String("enc") {
|
|
|
|
case "base64":
|
|
|
|
d, err := base64.StdEncoding.DecodeString(val)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("decoding base64 value: %w", err)
|
|
|
|
}
|
|
|
|
dec = d
|
|
|
|
case "hex":
|
|
|
|
d, err := hex.DecodeString(val)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("decoding hex value: %w", err)
|
|
|
|
}
|
|
|
|
dec = d
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("unrecognized encoding: %s", cctx.String("enc"))
|
|
|
|
}
|
|
|
|
|
|
|
|
rle, err := rlepluslazy.FromBuf(dec)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("opening rle: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
rit, err := rle.RunIterator()
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("getting run iterator: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-04-29 18:06:05 +00:00
|
|
|
fmt.Printf("Raw length: %d bits (%d bytes)\n", len(dec)*8, len(dec))
|
2020-04-28 08:41:59 +00:00
|
|
|
|
|
|
|
var ones, zeros, oneRuns, zeroRuns, invalid uint64
|
|
|
|
|
|
|
|
for rit.HasNext() {
|
|
|
|
r, err := rit.NextRun()
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("next run: %w", err)
|
|
|
|
}
|
|
|
|
if !r.Valid() {
|
|
|
|
invalid++
|
|
|
|
}
|
|
|
|
if r.Val {
|
|
|
|
ones += r.Len
|
|
|
|
oneRuns++
|
|
|
|
} else {
|
|
|
|
zeros += r.Len
|
|
|
|
zeroRuns++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-28 19:36:58 +00:00
|
|
|
if _, err := rle.Count(); err != nil { // check overflows
|
|
|
|
fmt.Println("Error: ", err)
|
|
|
|
}
|
|
|
|
|
2020-04-28 08:41:59 +00:00
|
|
|
fmt.Printf("Decoded length: %d bits\n", ones+zeros)
|
|
|
|
fmt.Printf("\tOnes: %d\n", ones)
|
|
|
|
fmt.Printf("\tZeros: %d\n", zeros)
|
|
|
|
fmt.Printf("Runs: %d\n", oneRuns+zeroRuns)
|
|
|
|
fmt.Printf("\tOne Runs: %d\n", oneRuns)
|
|
|
|
fmt.Printf("\tZero Runs: %d\n", zeroRuns)
|
|
|
|
fmt.Printf("Invalid runs: %d\n", invalid)
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2020-05-12 21:22:21 +00:00
|
|
|
|
|
|
|
var bitFieldDecodeCmd = &cli.Command{
|
|
|
|
Name: "decode",
|
|
|
|
Description: "decode bitfield and print all numbers in it",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "enc",
|
|
|
|
Value: "base64",
|
|
|
|
Usage: "specify input encoding to parse",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: func(cctx *cli.Context) error {
|
2020-09-17 17:57:42 +00:00
|
|
|
rle, err := decode(cctx, 0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2020-05-12 21:22:21 +00:00
|
|
|
}
|
|
|
|
|
2020-09-17 17:57:42 +00:00
|
|
|
vals, err := rle.All(100000000000)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("getting all items: %w", err)
|
2020-05-12 21:22:21 +00:00
|
|
|
}
|
2020-09-17 17:57:42 +00:00
|
|
|
fmt.Println(vals)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2020-05-12 21:22:21 +00:00
|
|
|
|
2020-09-17 17:57:42 +00:00
|
|
|
var bitFieldIntersectCmd = &cli.Command{
|
|
|
|
Name: "intersect",
|
|
|
|
Description: "intersect 2 bitfields and print the resulting bitfield as base64",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "enc",
|
|
|
|
Value: "base64",
|
|
|
|
Usage: "specify input encoding to parse",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
b, err := decode(cctx, 1)
|
2020-05-12 21:22:21 +00:00
|
|
|
if err != nil {
|
2020-09-17 17:57:42 +00:00
|
|
|
return err
|
2020-05-12 21:22:21 +00:00
|
|
|
}
|
|
|
|
|
2020-09-17 17:57:42 +00:00
|
|
|
a, err := decode(cctx, 0)
|
2020-05-12 21:22:21 +00:00
|
|
|
if err != nil {
|
2020-09-17 17:57:42 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
o, err := bitfield.IntersectBitField(a, b)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("intersect: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
s, err := o.RunIterator()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2020-05-12 21:22:21 +00:00
|
|
|
}
|
2020-09-17 17:57:42 +00:00
|
|
|
|
|
|
|
bytes, err := rlepluslazy.EncodeRuns(s, []byte{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println(base64.StdEncoding.EncodeToString(bytes))
|
2020-05-12 21:22:21 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2020-09-17 17:57:42 +00:00
|
|
|
|
|
|
|
func decode(cctx *cli.Context, a int) (bitfield.BitField, error) {
|
|
|
|
var val string
|
|
|
|
if cctx.Args().Present() {
|
|
|
|
if a >= cctx.NArg() {
|
|
|
|
return bitfield.BitField{}, xerrors.Errorf("need more than %d args", a)
|
|
|
|
}
|
|
|
|
val = cctx.Args().Get(a)
|
|
|
|
} else {
|
|
|
|
if a > 0 {
|
|
|
|
return bitfield.BitField{}, xerrors.Errorf("need more than %d args", a)
|
|
|
|
}
|
|
|
|
b, err := ioutil.ReadAll(os.Stdin)
|
|
|
|
if err != nil {
|
|
|
|
return bitfield.BitField{}, err
|
|
|
|
}
|
|
|
|
val = string(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
var dec []byte
|
|
|
|
switch cctx.String("enc") {
|
|
|
|
case "base64":
|
|
|
|
d, err := base64.StdEncoding.DecodeString(val)
|
|
|
|
if err != nil {
|
|
|
|
return bitfield.BitField{}, fmt.Errorf("decoding base64 value: %w", err)
|
|
|
|
}
|
|
|
|
dec = d
|
|
|
|
case "hex":
|
|
|
|
d, err := hex.DecodeString(val)
|
|
|
|
if err != nil {
|
|
|
|
return bitfield.BitField{}, fmt.Errorf("decoding hex value: %w", err)
|
|
|
|
}
|
|
|
|
dec = d
|
|
|
|
default:
|
|
|
|
return bitfield.BitField{}, fmt.Errorf("unrecognized encoding: %s", cctx.String("enc"))
|
|
|
|
}
|
|
|
|
|
|
|
|
return bitfield.NewFromBytes(dec)
|
|
|
|
}
|