func (ms *MozScanner) ScanObject() bool {
	value := ms.Value()
	ms.objectError = nil
	object := make(map[string]string)
	for value.Field != "CKA_CLASS" && ms.ScanValue() {
		value = ms.Value()
	}
	if err := ms.ScanValueError(); err != nil {
		ms.objectError = ms.valueError
		return false
	}
	if value.Field != "CKA_CLASS" {
		return false
	}
	object[value.Field] = value.Value
	for ms.ScanValue() {
		value = ms.Value()
		if value.Field == "CKA_CLASS" {
			ms.lastObject = object
			return true
		}
		object[value.Field] = value.Value
	}
	if err := ms.ScanValueError(); err != nil {
		ms.objectError = err
		return false
	}
	ms.lastObject = object
	return true
}
ScanObject repeatedly scans values to accumulate a complete object, which can be read
by calllng the Object method.
It returns false when no more objects can be read, either due to reaching EOF, or encountering
an error.  Errors can be read by calling ScanObjectError
package certparse
import (
	"bufio"
	"crypto/x509"
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
)
var (
	knownTrustLevels = []string{"CKT_NSS_TRUSTED_DELEGATOR", "CKT_NSS_MUST_VERIFY_TRUST", "CKT_NSS_NOT_TRUSTED"}
	trustedDelegator = "CKT_NSS_TRUSTED_DELEGATOR"
)
type Cert struct {
	Label string
	Data  []byte  
	Trust TrustLevel
	Cert  *x509.Certificate
}
type TrustLevel int
const (
	ServerTrustedDelegator TrustLevel = 1 << iota  
	EmailTrustedDelegator                          
	CodeTrustedDelegator                           
)
type MozValue struct {
	Field string
	Type  string
	Value string
}
type MozScanner struct {
	s             *bufio.Scanner
	ln            int
	skippedHeader bool
	lastValue     MozValue
	valueError    error
	lastObject    map[string]string
	objectError   error
}
func NewMozScanner(f io.Reader) *MozScanner {
	return &MozScanner{
		s: bufio.NewScanner(f),
	}
}
func (ms *MozScanner) skipHeader() error {
	for ms.s.Scan() {
		line := ms.s.Text()
		ms.ln++
		if line == "BEGINDATA" {
			ms.skippedHeader = true
			return nil
		}
	}
	return errors.New("BEGINDATA line not found in certdata input")
}
func (ms *MozScanner) LineNumber() int {
	return ms.ln
}
func (ms *MozScanner) ScanValue() bool {
	ms.valueError = nil
	if !ms.skippedHeader {
		if err := ms.skipHeader(); err != nil {
			ms.valueError = err
			return false
		}
	}
	var field, ftype, value string
	var err error
	for ms.s.Scan() {
		line := ms.s.Text()
		ms.ln++
		if len(line) == 0 || line[0] == '#' {
			continue
		}
		parts := strings.SplitN(line, " ", 3)
		if len(parts) < 2 {
			continue
		}
		field, ftype = parts[0], parts[1]
		switch {
		case ftype == "UTF8" && len(parts) > 2:
			value, err = strconv.Unquote(parts[2])
			if err != nil {
				value = parts[2][1 : len(parts[2])-1]  
			}
		case strings.HasPrefix(ftype, "MULTILINE"):
			switch mltype := ftype[len("MULTILINE_"):]; mltype {
			case "OCTAL":
				if value, err = ms.readMultilineOctal(); err != nil {
					ms.valueError = err
					return false
				}
			default:
				if _, err = ms.readMultilineGeneric(); err != nil {
					ms.valueError = err
					return false
				}
			}
		default:
			if len(parts) > 2 {
				value = parts[2]
			}
		}
		ms.lastValue = MozValue{Field: field, Type: ftype, Value: value}
		return true
	}
	return false
}
func (ms *MozScanner) ScanValueError() error {
	return ms.valueError
}
func (ms *MozScanner) Value() MozValue {
	return ms.lastValue
}
func (ms *MozScanner) readMultiline(process func(line string) error) error {
	for ms.s.Scan() {
		line := ms.s.Text()
		ms.ln++
		if line == "END" {
			return nil
		}
		if err := process(line); err != nil {
			return err
		}
	}
	return errors.New("unexpected EOF in multiline value")
}
func (ms *MozScanner) readMultilineGeneric() (value string, err error) {
	var v []string
	ms.readMultiline(func(line string) error {
		v = append(v, line)
		return nil
	})
	return strings.Join(v, "\n"), nil
}
func (ms *MozScanner) readMultilineOctal() (value string, err error) {
	var v []byte
	ms.readMultiline(func(line string) error {
		for i := 0; i < len(line); i += 4 {
			n, err := strconv.ParseInt(line[i+1:i+4], 8, 16)
			if err != nil {
				return err
			}
			v = append(v, byte(n))
		}
		return nil
	})
	return string(v), nil
}