package pkg import ( "encoding/binary" "fmt" "io" "strconv" "strings" ) func Disassemble(r io.Reader, real bool, showHeader bool, force bool) (s string, err error) { var values [][2]string sb := new(strings.Builder) header := true for err == nil { if header { var kind uint64 var size uint64 hsb := new(strings.Builder) if kind, err = nextUint64(r); err != nil { break } if size, err = nextUint64(r); err != nil { break } for i := 0; uint64(i) < size; i++ { var did Checksum var dkind uint64 if dkind, err = nextUint64(r); err != nil { break } if did, err = nextIdent(r); err != nil { break } hsb.WriteString(fmt.Sprintf("\t\t\t%s\t%s\n", intToKind(dkind), Encode(did))) } header = false if showHeader { values = append(values, [2]string{"head", fmt.Sprintf("%s [\n%s]", intToKind(kind), hsb.String())}) } } var k uint32 if k, err = nextUint32(r); err != nil { break } kind := IRValueKind(k) switch kind { case IRKindEnd: var a uint32 if a, err = nextUint32(r); err != nil { break } if a&1 != 0 { var sum Checksum if sum, err = nextIdent(r); err != nil { break } values = append(values, [2]string{"end", Encode(sum)}) } else { values = append(values, [2]string{"end", ""}) } header = true continue case IRKindIdent: // discard ancillary if _, err = nextUint32(r); err != nil { break } var sum Checksum if sum, err = nextIdent(r); err != nil { break } values = append(values, [2]string{"id", Encode(sum)}) continue case IRKindUint32: var i uint32 if i, err = nextUint32(r); err != nil { break } values = append(values, [2]string{"int", strconv.FormatUint(uint64(i), 10)}) case IRKindString: var l uint32 if l, err = nextUint32(r); err != nil { break } s := make([]byte, l+(wordSize-(l)%wordSize)%wordSize) if _, err = r.Read(s); err != nil { break } values = append(values, [2]string{"str", fmt.Sprintf("\"%s\"", string(s[:l]))}) continue default: var i uint32 if i, err = nextUint32(r); err != nil { break } values = append(values, [2]string{fmt.Sprintf("$%x", uint32(kind)), strconv.FormatUint(uint64(i), 10)}) } } if err != io.EOF { return } err = nil for i := 0; i < len(values); i++ { sb.WriteString(fmt.Sprintf("%s\t\t%s\n", values[i][0], values[i][1])) } return sb.String(), err } func nextUint32(r io.Reader) (uint32, error) { i := make([]byte, 4) _, err := r.Read(i) if err != nil { return 0, err } return binary.LittleEndian.Uint32(i), nil } func nextUint64(r io.Reader) (uint64, error) { i := make([]byte, 8) _, err := r.Read(i) if err != nil { return 0, err } return binary.LittleEndian.Uint64(i), nil } func nextIdent(r io.Reader) (Checksum, error) { i := make([]byte, 48) if _, err := r.Read(i); err != nil { return Checksum{}, err } return Checksum(i), nil } func intToKind(i uint64) string { switch Kind(i) { case KindHTTPGet: return "http_get" case KindTar: return "tar" case KindExec: return "exec" case KindExecNet: return "exec_net" case KindFile: return "file" default: return fmt.Sprintf("$%d", i-KindCustomOffset) } }