func wrapExtensions(file *descriptor.FileDescriptorProto) []*ExtensionDescriptor {
	sl := make([]*ExtensionDescriptor, len(file.Extension))
	for i, field := range file.Extension {
		sl[i] = &ExtensionDescriptor{common{file}, field, nil}
	}
	return sl
}
Return a slice of all the top-level ExtensionDescriptors defined within this file.
package generator
import (
	"bytes"
	"fmt"
	"go/parser"
	"go/printer"
	"go/token"
	"log"
	"os"
	"path"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"
	"code.google.com/p/goprotobuf/proto"
	descriptor "code.google.com/p/goprotobuf/protoc-gen-go/descriptor"
	plugin "code.google.com/p/goprotobuf/protoc-gen-go/plugin"
)
type Plugin interface {
	Name() string
	Init(g *Generator)
	Generate(file *FileDescriptor)
	GenerateImports(file *FileDescriptor)
}
var plugins []Plugin
func RegisterPlugin(p Plugin) {
	plugins = append(plugins, p)
}
type common struct {
	file *descriptor.FileDescriptorProto  
}
func (c *common) PackageName() string { return uniquePackageOf(c.file) }
func (c *common) File() *descriptor.FileDescriptorProto { return c.file }
type Descriptor struct {
	common
	*descriptor.DescriptorProto
	parent   *Descriptor             
	nested   []*Descriptor           
	ext      []*ExtensionDescriptor  
	typename []string                
	index    int                     
	path     string                  
	group    bool
}
func (d *Descriptor) TypeName() []string {
	if d.typename != nil {
		return d.typename
	}
	n := 0
	for parent := d; parent != nil; parent = parent.parent {
		n++
	}
	s := make([]string, n, n)
	for parent := d; parent != nil; parent = parent.parent {
		n--
		s[n] = parent.GetName()
	}
	d.typename = s
	return s
}
type EnumDescriptor struct {
	common
	*descriptor.EnumDescriptorProto
	parent   *Descriptor  
	typename []string     
	index    int          
	path     string       
}
func (e *EnumDescriptor) TypeName() (s []string) {
	if e.typename != nil {
		return e.typename
	}
	name := e.GetName()
	if e.parent == nil {
		s = make([]string, 1)
	} else {
		pname := e.parent.TypeName()
		s = make([]string, len(pname)+1)
		copy(s, pname)
	}
	s[len(s)-1] = name
	e.typename = s
	return s
}
func (e *EnumDescriptor) prefix() string {
	typeName := e.TypeName()
	ccPrefix := CamelCaseSlice(typeName[0:len(typeName)-1]) + "_"
	if e.parent == nil {
		ccPrefix = CamelCase(*e.Name) + "_"
	}
	return ccPrefix
}
func (e *EnumDescriptor) integerValueAsString(name string) string {
	for _, c := range e.Value {
		if c.GetName() == name {
			return fmt.Sprint(c.GetNumber())
		}
	}
	log.Fatal("cannot find value for enum constant")
	return ""
}
type ExtensionDescriptor struct {
	common
	*descriptor.FieldDescriptorProto
	parent *Descriptor  
}
func (e *ExtensionDescriptor) TypeName() (s []string) {
	name := e.GetName()
	if e.parent == nil {
		s = make([]string, 1)
	} else {
		pname := e.parent.TypeName()
		s = make([]string, len(pname)+1)
		copy(s, pname)
	}
	s[len(s)-1] = name
	return s
}
func (e *ExtensionDescriptor) DescName() string {
	typeName := e.TypeName()
	for i, s := range typeName {
		typeName[i] = CamelCase(s)
	}
	return "E_" + strings.Join(typeName, "_")
}
type ImportedDescriptor struct {
	common
	o Object
}
func (id *ImportedDescriptor) TypeName() []string { return id.o.TypeName() }
type FileDescriptor struct {
	*descriptor.FileDescriptorProto
	desc []*Descriptor           
	enum []*EnumDescriptor       
	ext  []*ExtensionDescriptor  
	imp  []*ImportedDescriptor   
	comments map[string]*descriptor.SourceCodeInfo_Location
	exported map[Object][]symbol
	index int  
}
func (d *FileDescriptor) PackageName() string { return uniquePackageOf(d.FileDescriptorProto) }
func (d *FileDescriptor) goPackageName() (name string, explicit bool) {
	if opts := d.Options; opts != nil {
		if pkg := opts.GetGoPackage(); pkg != "" {
			return pkg, true
		}
	}
	if pkg := d.GetPackage(); pkg != "" {
		return pkg, false
	}
	return baseName(d.GetName()), false
}
func (d *FileDescriptor) addExport(obj Object, sym symbol) {
	d.exported[obj] = append(d.exported[obj], sym)
}
type symbol interface {
	GenerateAlias(g *Generator, pkg string)
}
type messageSymbol struct {
	sym                         string
	hasExtensions, isMessageSet bool
	getters                     []getterSymbol
}
type getterSymbol struct {
	name     string
	typ      string
	typeName string  
	genType  bool    
}
func (ms *messageSymbol) GenerateAlias(g *Generator, pkg string) {
	remoteSym := pkg + "." + ms.sym
	g.P("type ", ms.sym, " ", remoteSym)
	g.P("func (m *", ms.sym, ") Reset() { (*", remoteSym, ")(m).Reset() }")
	g.P("func (m *", ms.sym, ") String() string { return (*", remoteSym, ")(m).String() }")
	g.P("func (*", ms.sym, ") ProtoMessage() {}")
	if ms.hasExtensions {
		g.P("func (*", ms.sym, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange ",
			"{ return (*", remoteSym, ")(nil).ExtensionRangeArray() }")
		g.P("func (m *", ms.sym, ") ExtensionMap() map[int32]", g.Pkg["proto"], ".Extension ",
			"{ return (*", remoteSym, ")(m).ExtensionMap() }")
		if ms.isMessageSet {
			g.P("func (m *", ms.sym, ") Marshal() ([]byte, error) ",
				"{ return (*", remoteSym, ")(m).Marshal() }")
			g.P("func (m *", ms.sym, ") Unmarshal(buf []byte) error ",
				"{ return (*", remoteSym, ")(m).Unmarshal(buf) }")
		}
	}
	for _, get := range ms.getters {
		if get.typeName != "" {
			g.RecordTypeUse(get.typeName)
		}
		typ := get.typ
		val := "(*" + remoteSym + ")(m)." + get.name + "()"
		if get.genType {
			rep := strings.HasPrefix(typ, "[]")
			if rep {
				typ = typ[2:]
			}
			star := typ[0] == '*'
			typ = typ[strings.Index(typ, ".")+1:]
			if star {
				typ = "*" + typ
			}
			if rep {
				ctyp := typ  
				if star {
					ctyp = "(" + typ + ")"
				}
				g.P("func (m *", ms.sym, ") ", get.name, "() []", typ, " {")
				g.In()
				g.P("o := ", val)
				g.P("if o == nil {")
				g.In()
				g.P("return nil")
				g.Out()
				g.P("}")
				g.P("s := make([]", typ, ", len(o))")
				g.P("for i, x := range o {")
				g.In()
				g.P("s[i] = ", ctyp, "(x)")
				g.Out()
				g.P("}")
				g.P("return s")
				g.Out()
				g.P("}")
				continue
			}
			val = "(" + typ + ")(" + val + ")"
		}
		g.P("func (m *", ms.sym, ") ", get.name, "() ", typ, " { return ", val, " }")
	}
}
type enumSymbol string
func (es enumSymbol) GenerateAlias(g *Generator, pkg string) {
	s := string(es)
	g.P("type ", s, " ", pkg, ".", s)
	g.P("var ", s, "_name = ", pkg, ".", s, "_name")
	g.P("var ", s, "_value = ", pkg, ".", s, "_value")
	g.P("func (x ", s, ") Enum() *", s, "{ return (*", s, ")((", pkg, ".", s, ")(x).Enum()) }")
	g.P("func (x ", s, ") String() string { return (", pkg, ".", s, ")(x).String() }")
	g.P("func (x *", s, ") UnmarshalJSON(data []byte) error { return (*", pkg, ".", s, ")(x).UnmarshalJSON(data) }")
}
type constOrVarSymbol struct {
	sym  string
	typ  string  
	cast string  
}
func (cs constOrVarSymbol) GenerateAlias(g *Generator, pkg string) {
	v := pkg + "." + cs.sym
	if cs.cast != "" {
		v = cs.cast + "(" + v + ")"
	}
	g.P(cs.typ, " ", cs.sym, " = ", v)
}
type Object interface {
	PackageName() string  
	TypeName() []string
	File() *descriptor.FileDescriptorProto
}
func uniquePackageOf(fd *descriptor.FileDescriptorProto) string {
	s, ok := uniquePackageName[fd]
	if !ok {
		log.Fatal("internal error: no package name defined for " + fd.GetName())
	}
	return s
}
type Generator struct {
	*bytes.Buffer
	Request  *plugin.CodeGeneratorRequest   
	Response *plugin.CodeGeneratorResponse  
	Param             map[string]string  
	PackageImportPath string             
	ImportPrefix      string             
	ImportMap         map[string]string  
	Pkg map[string]string  
	packageName      string             
	allFiles         []*FileDescriptor  
	genFiles         []*FileDescriptor  
	file             *FileDescriptor    
	usedPackages     map[string]bool    
	typeNameToObject map[string]Object  
	indent           string
}
func New() *Generator {
	g := new(Generator)
	g.Buffer = new(bytes.Buffer)
	g.Request = new(plugin.CodeGeneratorRequest)
	g.Response = new(plugin.CodeGeneratorResponse)
	return g
}
func (g *Generator) Error(err error, msgs ...string) {
	s := strings.Join(msgs, " ") + ":" + err.Error()
	log.Print("protoc-gen-go: error:", s)
	os.Exit(1)
}
func (g *Generator) Fail(msgs ...string) {
	s := strings.Join(msgs, " ")
	log.Print("protoc-gen-go: error:", s)
	os.Exit(1)
}
func (g *Generator) CommandLineParameters(parameter string) {
	g.Param = make(map[string]string)
	for _, p := range strings.Split(parameter, ",") {
		if i := strings.Index(p, "="); i < 0 {
			g.Param[p] = ""
		} else {
			g.Param[p[0:i]] = p[i+1:]
		}
	}
	g.ImportMap = make(map[string]string)
	for k, v := range g.Param {
		switch k {
		case "import_prefix":
			g.ImportPrefix = v
		case "import_path":
			g.PackageImportPath = v
		default:
			if len(k) > 0 && k[0] == 'M' {
				g.ImportMap[k[1:]] = v
			}
		}
	}
}
func (g *Generator) DefaultPackageName(obj Object) string {
	pkg := obj.PackageName()
	if pkg == g.packageName {
		return ""
	}
	return pkg + "."
}
var uniquePackageName = make(map[*descriptor.FileDescriptorProto]string)
var pkgNamesInUse = make(map[string]bool)
func RegisterUniquePackageName(pkg string, f *FileDescriptor) string {
	pkg = strings.Map(badToUnderscore, pkg)
	for i, orig := 1, pkg; pkgNamesInUse[pkg]; i++ {
		pkg = orig + strconv.Itoa(i)
	}
	pkgNamesInUse[pkg] = true
	if f != nil {
		uniquePackageName[f.FileDescriptorProto] = pkg
	}
	return pkg
}
var isGoKeyword = map[string]bool{
	"break":       true,
	"case":        true,
	"chan":        true,
	"const":       true,
	"continue":    true,
	"default":     true,
	"else":        true,
	"defer":       true,
	"fallthrough": true,
	"for":         true,
	"func":        true,
	"go":          true,
	"goto":        true,
	"if":          true,
	"import":      true,
	"interface":   true,
	"map":         true,
	"package":     true,
	"range":       true,
	"return":      true,
	"select":      true,
	"struct":      true,
	"switch":      true,
	"type":        true,
	"var":         true,
}
func (g *Generator) defaultGoPackage() string {
	p := g.PackageImportPath
	if i := strings.LastIndex(p, "/"); i >= 0 {
		p = p[i+1:]
	}
	if p == "" {
		return ""
	}
	p = strings.Map(badToUnderscore, p)
	if isGoKeyword[p] {
		p = "_" + p
	}
	if r, _ := utf8.DecodeRuneInString(p); unicode.IsDigit(r) {
		p = "_" + p
	}
	return p
}
func (g *Generator) SetPackageNames() {
	pkg, explicit := g.genFiles[0].goPackageName()
	for _, f := range g.genFiles {
		thisPkg, thisExplicit := f.goPackageName()
		if thisExplicit {
			if !explicit {
				pkg, explicit = thisPkg, true
			} else if thisPkg != pkg {
				g.Fail("inconsistent package names:", thisPkg, pkg)
			}
		}
	}
	if !explicit {
		p := g.defaultGoPackage()
		if p != "" {
			pkg, explicit = p, true
		}
	}
	if !explicit {
		for _, f := range g.genFiles {
			thisPkg, _ := f.goPackageName()
			if thisPkg != pkg {
				g.Fail("inconsistent package names:", thisPkg, pkg)
			}
		}
	}
	g.packageName = RegisterUniquePackageName(pkg, g.genFiles[0])
	g.Pkg = map[string]string{
		"math":  RegisterUniquePackageName("math", nil),
		"proto": RegisterUniquePackageName("proto", nil),
	}
AllFiles:
	for _, f := range g.allFiles {
		for _, genf := range g.genFiles {
			if f == genf {
				uniquePackageName[f.FileDescriptorProto] = g.packageName
				continue AllFiles
			}
		}
		pkg := f.GetPackage()
		if pkg == "" {
			pkg = baseName(*f.Name)
		}
		RegisterUniquePackageName(pkg, f)
	}
}
func (g *Generator) WrapTypes() {
	g.allFiles = make([]*FileDescriptor, len(g.Request.ProtoFile))
	for i, f := range g.Request.ProtoFile {
		descs := wrapDescriptors(f)
		g.buildNestedDescriptors(descs)
		enums := wrapEnumDescriptors(f, descs)
		exts := wrapExtensions(f)
		imps := wrapImported(f, g)
		fd := &FileDescriptor{
			FileDescriptorProto: f,
			desc:                descs,
			enum:                enums,
			ext:                 exts,
			imp:                 imps,
			exported:            make(map[Object][]symbol),
		}
		extractComments(fd)
		g.allFiles[i] = fd
	}
	g.genFiles = make([]*FileDescriptor, len(g.Request.FileToGenerate))
FindFiles:
	for i, fileName := range g.Request.FileToGenerate {
		for _, file := range g.allFiles {
			if fileName == file.GetName() {
				g.genFiles[i] = file
				file.index = i
				continue FindFiles
			}
		}
		g.Fail("could not find file named", fileName)
	}
	g.Response.File = make([]*plugin.CodeGeneratorResponse_File, len(g.genFiles))
}
func (g *Generator) buildNestedDescriptors(descs []*Descriptor) {
	for _, desc := range descs {
		if len(desc.NestedType) != 0 {
			desc.nested = make([]*Descriptor, len(desc.NestedType))
			n := 0
			for _, nest := range descs {
				if nest.parent == desc {
					desc.nested[n] = nest
					n++
				}
			}
			if n != len(desc.NestedType) {
				g.Fail("internal error: nesting failure for", desc.GetName())
			}
		}
	}
}
func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto, index int) *Descriptor {
	d := &Descriptor{
		common:          common{file},
		DescriptorProto: desc,
		parent:          parent,
		index:           index,
	}
	if parent == nil {
		d.path = fmt.Sprintf("%d,%d", messagePath, index)
	} else {
		d.path = fmt.Sprintf("%s,%d,%d", parent.path, messageMessagePath, index)
	}
	if parent != nil {
		parts := d.TypeName()
		if file.Package != nil {
			parts = append([]string{*file.Package}, parts...)
		}
		exp := "." + strings.Join(parts, ".")
		for _, field := range parent.Field {
			if field.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP && field.GetTypeName() == exp {
				d.group = true
				break
			}
		}
	}
	d.ext = make([]*ExtensionDescriptor, len(desc.Extension))
	for i, field := range desc.Extension {
		d.ext[i] = &ExtensionDescriptor{common{file}, field, d}
	}
	return d
}
func wrapDescriptors(file *descriptor.FileDescriptorProto) []*Descriptor {
	sl := make([]*Descriptor, 0, len(file.MessageType)+10)
	for i, desc := range file.MessageType {
		sl = wrapThisDescriptor(sl, desc, nil, file, i)
	}
	return sl
}
func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto, index int) []*Descriptor {
	sl = append(sl, newDescriptor(desc, parent, file, index))
	me := sl[len(sl)-1]
	for i, nested := range desc.NestedType {
		sl = wrapThisDescriptor(sl, nested, me, file, i)
	}
	return sl
}
func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto, index int) *EnumDescriptor {
	ed := &EnumDescriptor{
		common:              common{file},
		EnumDescriptorProto: desc,
		parent:              parent,
		index:               index,
	}
	if parent == nil {
		ed.path = fmt.Sprintf("%d,%d", enumPath, index)
	} else {
		ed.path = fmt.Sprintf("%s,%d,%d", parent.path, messageEnumPath, index)
	}
	return ed
}
func wrapEnumDescriptors(file *descriptor.FileDescriptorProto, descs []*Descriptor) []*EnumDescriptor {
	sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
	for i, enum := range file.EnumType {
		sl = append(sl, newEnumDescriptor(enum, nil, file, i))
	}
	for _, nested := range descs {
		for i, enum := range nested.EnumType {
			sl = append(sl, newEnumDescriptor(enum, nested, file, i))
		}
	}
	return sl
}