| package gob |
| |
| // This file is not normally included in the gob package. Used only for debugging the package itself. |
| |
| import ( |
| "bytes" |
| "fmt" |
| "io" |
| "log" |
| "os" |
| ) |
| |
| // Debug prints a human-readable representation of the gob data read from r. |
| func Debug(r io.Reader) { NewDecoder(r).debug() } |
| |
| // debug is like Decode but just prints what it finds. It should be safe even for corrupted data. |
| func (dec *Decoder) debug() { |
| dec.state.err = nil |
| for { |
| // Read a count. |
| var nbytes uint64 |
| nbytes, dec.state.err = decodeUintReader(dec.r, dec.countBuf[0:]) |
| if dec.state.err != nil { |
| break |
| } |
| |
| // Allocate the buffer. |
| if nbytes > uint64(len(dec.buf)) { |
| dec.buf = make([]byte, nbytes+1000) |
| } |
| dec.state.b = bytes.NewBuffer(dec.buf[0:nbytes]) |
| |
| // Read the data |
| _, dec.state.err = io.ReadFull(dec.r, dec.buf[0:nbytes]) |
| if dec.state.err != nil { |
| if dec.state.err == os.EOF { |
| dec.state.err = io.ErrUnexpectedEOF |
| } |
| break |
| } |
| |
| // Receive a type id. |
| id := typeId(decodeInt(dec.state)) |
| if dec.state.err != nil { |
| break |
| } |
| |
| // Is it a new type? |
| if id < 0 { // 0 is the error state, handled above |
| // If the id is negative, we have a type. |
| fmt.Printf("new type id %d\n", -id) |
| dec.printType(-id) |
| if dec.state.err != nil { |
| break |
| } |
| continue |
| } |
| |
| fmt.Printf("type id %d\n", id) |
| // No, it's a value. |
| // Make sure the type has been defined already. |
| _, ok := dec.wireType[id] |
| if !ok { |
| dec.state.err = errBadType |
| break |
| } |
| fmt.Printf("\t%d bytes:\t% x\n", nbytes, dec.state.b.Bytes()) |
| dec.printData(0, id) |
| break |
| } |
| if dec.state.err != nil { |
| log.Stderr("debug:", dec.state.err) |
| } |
| } |
| |
| func (dec *Decoder) printType(id typeId) { |
| // Have we already seen this type? That's an error |
| if _, alreadySeen := dec.wireType[id]; alreadySeen { |
| dec.state.err = os.ErrorString("gob: duplicate type received") |
| return |
| } |
| |
| // Type: |
| wire := new(wireType) |
| dec.state.err = dec.decode(tWireType, wire) |
| if dec.state.err == nil { |
| printWireType(wire) |
| } |
| // Remember we've seen this type. |
| dec.wireType[id] = wire |
| } |
| |
| func printWireType(wire *wireType) { |
| switch { |
| case wire.array != nil: |
| printCommonType("array", &wire.array.commonType) |
| fmt.Printf("\tlen %d\n\telemid %d\n", wire.array.Len, wire.array.Elem) |
| case wire.slice != nil: |
| printCommonType("slice", &wire.slice.commonType) |
| fmt.Printf("\telemid %d\n", wire.slice.Elem) |
| case wire.strct != nil: |
| printCommonType("struct", &wire.strct.commonType) |
| for i, field := range wire.strct.field { |
| fmt.Printf("\tfield %d:\t%s\tid=%d\n", i, field.name, field.id) |
| } |
| } |
| } |
| |
| func printCommonType(kind string, common *commonType) { |
| fmt.Printf("\t%s %s\n\tid: %d\n", kind, common.name, common._id) |
| } |
| |
| func (dec *Decoder) printData(indent int, id typeId) { |
| if dec.state.err != nil { |
| return |
| } |
| // is it a builtin type? |
| _, ok := builtinIdToType[id] |
| if ok { |
| dec.printBuiltin(indent, id) |
| return |
| } |
| wire, ok := dec.wireType[id] |
| if !ok { |
| fmt.Printf("type id %d not defined\n", id) |
| return |
| } |
| switch { |
| case wire.array != nil: |
| dec.printArray(indent+1, wire) |
| case wire.slice != nil: |
| dec.printSlice(indent+1, wire) |
| case wire.strct != nil: |
| dec.printStruct(indent+1, wire) |
| } |
| } |
| |
| func (dec *Decoder) printArray(indent int, wire *wireType) { |
| elemId := wire.array.Elem |
| n := int(decodeUint(dec.state)) |
| for i := 0; i < n && dec.state.err == nil; i++ { |
| dec.printData(indent, elemId) |
| } |
| if n != wire.array.Len { |
| tab(indent) |
| fmt.Printf("(wrong length for array: %d should be %d)\n", n, wire.array.Len) |
| } |
| } |
| |
| func (dec *Decoder) printSlice(indent int, wire *wireType) { |
| elemId := wire.slice.Elem |
| n := int(decodeUint(dec.state)) |
| for i := 0; i < n && dec.state.err == nil; i++ { |
| dec.printData(indent, elemId) |
| } |
| } |
| |
| func (dec *Decoder) printBuiltin(indent int, id typeId) { |
| tab(indent) |
| switch id { |
| case tBool: |
| if decodeInt(dec.state) == 0 { |
| fmt.Printf("false") |
| } else { |
| fmt.Printf("true") |
| } |
| case tInt: |
| fmt.Printf("%d", decodeInt(dec.state)) |
| case tUint: |
| fmt.Printf("%d", decodeUint(dec.state)) |
| case tFloat: |
| fmt.Printf("%g", floatFromBits(decodeUint(dec.state))) |
| case tBytes: |
| b := make([]byte, decodeUint(dec.state)) |
| dec.state.b.Read(b) |
| fmt.Printf("% x", b) |
| case tString: |
| b := make([]byte, decodeUint(dec.state)) |
| dec.state.b.Read(b) |
| fmt.Printf("%q", b) |
| default: |
| fmt.Print("unknown") |
| } |
| fmt.Print("\n") |
| } |
| |
| func (dec *Decoder) printStruct(indent int, wire *wireType) { |
| strct := wire.strct |
| state := newDecodeState(dec.state.b) |
| state.fieldnum = -1 |
| for state.err == nil { |
| delta := int(decodeUint(state)) |
| if delta < 0 { |
| dec.state.err = os.ErrorString("gob decode: corrupted data: negative delta") |
| return |
| } |
| if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum |
| return |
| } |
| fieldnum := state.fieldnum + delta |
| if fieldnum < 0 || fieldnum >= len(strct.field) { |
| dec.state.err = os.ErrorString("field number out of range") |
| return |
| } |
| tab(indent) |
| fmt.Printf("field %d:\n", fieldnum) |
| dec.printData(indent+1, strct.field[fieldnum].id) |
| state.fieldnum = fieldnum |
| } |
| } |
| |
| func tab(indent int) { |
| for i := 0; i < indent; i++ { |
| fmt.Print("\t") |
| } |
| } |