github.com/boki/go-xmp@v1.0.1/xmp/marshal.go (about)

     1  // Copyright (c) 2017-2018 Alexander Eichhorn
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  package xmp
    16  
    17  import (
    18  	"bytes"
    19  	"encoding"
    20  	"encoding/base64"
    21  	"encoding/xml"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"reflect"
    26  	"strconv"
    27  )
    28  
    29  type Marshaler interface {
    30  	MarshalXMP(e *Encoder, n *Node, model Model) error
    31  }
    32  
    33  type MarshalerAttr interface {
    34  	MarshalXMPAttr(e *Encoder, name xml.Name, n *Node) (Attr, error)
    35  }
    36  
    37  const (
    38  	Xpacket = 1 << iota
    39  	Xpadding
    40  	eMode = Xpacket | Xpadding
    41  )
    42  
    43  type Encoder struct {
    44  	e        *xml.Encoder
    45  	cw       *countWriter
    46  	root     *Node
    47  	version  Version
    48  	nsTagMap map[string]string
    49  	intNsMap map[string]*Namespace
    50  	extNsMap map[string]*Namespace
    51  	flags    int
    52  }
    53  
    54  var ErrOverflow = errors.New("xmp: document exceeds size limit")
    55  
    56  type countWriter struct {
    57  	n     int64
    58  	limit int64
    59  	w     io.Writer
    60  }
    61  
    62  func min(a, b int64) int64 {
    63  	if a < b {
    64  		return a
    65  	}
    66  	return b
    67  }
    68  
    69  func newCountWriter(w io.Writer) *countWriter {
    70  	return &countWriter{w: w}
    71  }
    72  
    73  func (w *countWriter) Write(b []byte) (int, error) {
    74  	if w.limit > 0 {
    75  		if w.n >= w.limit {
    76  			return 0, ErrOverflow
    77  		}
    78  		bLen := int64(len(b))
    79  		copied, err := io.CopyN(w.w, bytes.NewReader(b), min(w.limit-w.n, bLen))
    80  		w.n += copied
    81  		if err != nil {
    82  			return int(copied), err
    83  		}
    84  		if copied < bLen {
    85  			return int(copied), ErrOverflow
    86  		}
    87  		return int(copied), nil
    88  	} else {
    89  		n, err := w.w.Write(b)
    90  		w.n += int64(n)
    91  		return n, err
    92  	}
    93  }
    94  
    95  func NewEncoder(w io.Writer) *Encoder {
    96  	cw := newCountWriter(w)
    97  	return &Encoder{
    98  		e:        xml.NewEncoder(cw),
    99  		cw:       cw,
   100  		root:     NewNode(xml.Name{}),
   101  		nsTagMap: make(map[string]string),
   102  		intNsMap: make(map[string]*Namespace),
   103  		extNsMap: make(map[string]*Namespace),
   104  		flags:    Xpacket,
   105  	}
   106  }
   107  
   108  func (e *Encoder) SetMaxSize(size int64) {
   109  	e.cw.limit = size
   110  }
   111  
   112  func (e *Encoder) SetFlags(flags int) {
   113  	e.flags = flags & eMode
   114  }
   115  
   116  func (e *Encoder) Indent(prefix, indent string) {
   117  	e.e.Indent(prefix, indent)
   118  }
   119  
   120  func Marshal(d *Document) ([]byte, error) {
   121  	var b bytes.Buffer
   122  	if err := NewEncoder(&b).Encode(d); err != nil {
   123  		return nil, err
   124  	}
   125  	return b.Bytes(), nil
   126  }
   127  
   128  func MarshalIndent(d *Document, prefix, indent string) ([]byte, error) {
   129  	var b bytes.Buffer
   130  	enc := NewEncoder(&b)
   131  	enc.e.Indent(prefix, indent)
   132  	if err := enc.Encode(d); err != nil {
   133  		return nil, err
   134  	}
   135  	return b.Bytes(), nil
   136  }
   137  
   138  // encode to separate rdf:Description objects per namespace
   139  func (e *Encoder) Encode(d *Document) error {
   140  
   141  	if d == nil {
   142  		return nil
   143  	}
   144  
   145  	// sync individual models to establish correct XMP entries
   146  	if err := d.syncToXMP(); err != nil {
   147  		return err
   148  	}
   149  
   150  	// reset nodes and map
   151  	e.root = NewNode(xml.Name{})
   152  	defer e.root.Close()
   153  	e.nsTagMap = make(map[string]string)
   154  	e.intNsMap = d.intNsMap
   155  	e.extNsMap = d.extNsMap
   156  
   157  	// 1  build output node tree (model -> nodes+attr with one root node per
   158  	//    XMP namespace)
   159  	for _, n := range d.nodes {
   160  		// 1.1  encode the model (Note: models typically use multiple XMP namespaces)
   161  		//      so we generate wrapper nodes on the fly
   162  		if n.Model != nil {
   163  			if err := e.marshalValue(reflect.ValueOf(n.Model), nil, e.root, true); err != nil {
   164  				return err
   165  			}
   166  		}
   167  
   168  		// 1.2  merge external nodes (Note: all ext nodes collected under a
   169  		//      document node belong to the same namespace)
   170  		ns := e.findNs(n.XMLName)
   171  		if ns == nil {
   172  			return fmt.Errorf("xmp: missing namespace for model node %s", n.XMLName.Local)
   173  		}
   174  		node := e.root.Nodes.FindNode(ns)
   175  		if node == nil {
   176  			node = NewNode(n.XMLName)
   177  			e.root.AddNode(node)
   178  		}
   179  		node.Nodes = append(node.Nodes, copyNodes(n.Nodes)...)
   180  
   181  		// 1.3  merge external attributes (Note: all ext attr collected under a
   182  		//      document node belong to the same namespace)
   183  		node.Attr = append(node.Attr, n.Attr...)
   184  	}
   185  
   186  	// 2  collect root-node namespaces
   187  	for _, n := range e.root.Nodes {
   188  		l := make([]Attr, 0)
   189  		for _, ns := range n.Namespaces(d) {
   190  			l = append(l, ns.GetAttr())
   191  		}
   192  
   193  		// add the about attr
   194  		about := aboutAttr
   195  		about.Value = d.about
   196  		l = append(l, about)
   197  		n.Attr = append(l, n.Attr...)
   198  		n.XMLName = rdfDescription
   199  	}
   200  
   201  	// 3 remove empty root nodes
   202  	nl := make(NodeList, 0)
   203  	for _, n := range e.root.Nodes {
   204  		if len(n.Attr) <= 2 && len(n.Nodes) == 0 {
   205  			n.Close()
   206  			continue
   207  		}
   208  		nl = append(nl, n)
   209  	}
   210  	e.root.Nodes = nl
   211  
   212  	// 4  output XML
   213  
   214  	// 4.1 write packet header
   215  	if e.flags&Xpacket > 0 {
   216  		if _, err := e.cw.Write(xmp_packet_header); err != nil {
   217  			return err
   218  		}
   219  	}
   220  
   221  	// 4.2 add top-level XMP namespace and toolkit as attributes
   222  	start := xml.StartElement{
   223  		Name: xml.Name{Local: "x:xmpmeta"},
   224  		Attr: make([]xml.Attr, 0),
   225  	}
   226  	start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: "xmlns:x"}, Value: "adobe:ns:meta/"})
   227  	tk := d.toolkit
   228  	if tk == "" {
   229  		tk = XMP_TOOLKIT_VERSION
   230  	}
   231  	start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: "x:xmptk"}, Value: tk})
   232  	if err := e.e.EncodeToken(start); err != nil {
   233  		return err
   234  	}
   235  
   236  	// 4.3 add document tree
   237  	e.root.XMLName = xml.Name{Local: "rdf:RDF"}
   238  	e.root.Attr = []Attr{nsRDF.GetAttr()}
   239  	if err := e.e.Encode(e.root); err != nil {
   240  		return err
   241  	}
   242  
   243  	if err := e.e.EncodeToken(start.End()); err != nil {
   244  		return err
   245  	}
   246  	if err := e.e.Flush(); err != nil {
   247  		return err
   248  	}
   249  
   250  	// 4.4 write footer including optional padding
   251  	if e.flags&Xpacket > 0 {
   252  		if e.flags&Xpadding > 0 && e.cw.limit > 0 {
   253  			pad := e.cw.limit - e.cw.n - 20
   254  
   255  			for i := int64(0); i < pad; i++ {
   256  				if i%80 == 0 {
   257  					if _, err := e.cw.Write([]byte("\n")); err != nil {
   258  						return err
   259  					}
   260  				} else {
   261  					if _, err := e.cw.Write([]byte(" ")); err != nil {
   262  						return err
   263  					}
   264  				}
   265  			}
   266  		}
   267  
   268  		if _, err := e.cw.Write(xmp_packet_footer); err != nil {
   269  			return err
   270  		}
   271  	}
   272  
   273  	return nil
   274  }
   275  
   276  func (e *Encoder) EncodeElement(v interface{}, node *Node) error {
   277  	return e.marshalValue(reflect.ValueOf(v), nil, node, false)
   278  }
   279  
   280  func (e *Encoder) marshalValue(val reflect.Value, finfo *fieldInfo, node *Node, withWrapper bool) error {
   281  	// name := "-"
   282  	// if finfo != nil {
   283  	// 	name = finfo.name
   284  	// }
   285  	// log.Debugf("xmp: marshalValue %v %v %s\n", val.Kind(), val.Type(), name)
   286  
   287  	if !val.IsValid() {
   288  		return nil
   289  	}
   290  
   291  	// check empty
   292  	if finfo != nil && finfo.flags&fEmpty == 0 && isEmptyValue(val) {
   293  		// log.Debugf("xmp: skipping empty value for %s\n", name)
   294  		return nil
   295  	}
   296  
   297  	// Drill into interfaces and pointers.
   298  	// This can turn into an infinite loop given a cyclic chain,
   299  	// but it matches the Go 1 behavior.
   300  	for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
   301  		if val.IsNil() {
   302  			// log.Debugf("xmp: skipping nil value for %s\n", name)
   303  			return nil
   304  		}
   305  		val = val.Elem()
   306  	}
   307  
   308  	kind := val.Kind()
   309  	typ := val.Type()
   310  
   311  	// call marshaler interface
   312  	if val.CanInterface() && (finfo != nil && finfo.flags&fMarshal > 0 || typ.Implements(marshalerType)) {
   313  		// log.Debugf("xmp: marshalValue calling MarshalXMP on %v for %s\n", val.Type(), name)
   314  		return val.Interface().(Marshaler).MarshalXMP(e, node, nil)
   315  	}
   316  
   317  	if val.CanAddr() {
   318  		pv := val.Addr()
   319  		if pv.CanInterface() && (finfo != nil && finfo.flags&fMarshal > 0 || pv.Type().Implements(marshalerType)) {
   320  			// log.Debugf("xmp: marshalValue calling MarshalXMP on %v for %s\n", val.Type(), name)
   321  			return pv.Interface().(Marshaler).MarshalXMP(e, node, nil)
   322  		}
   323  	}
   324  
   325  	// Check for text marshaler and marshal as node value
   326  	if val.CanInterface() && (finfo != nil && finfo.flags&fTextMarshal > 0 || typ.Implements(textMarshalerType)) {
   327  		// log.Debugf("xmp: marshalValue calling MarshalText on %v for %s\n", val.Type(), name)
   328  		b, err := val.Interface().(encoding.TextMarshaler).MarshalText()
   329  		if err != nil || b == nil {
   330  			return err
   331  		}
   332  		node.Value = string(b)
   333  		return nil
   334  	}
   335  
   336  	if val.CanAddr() {
   337  		pv := val.Addr()
   338  		if pv.CanInterface() && (finfo != nil && finfo.flags&fTextMarshal > 0 || pv.Type().Implements(textMarshalerType)) {
   339  			// log.Debugf("xmp: marshalValue calling MarshalText on %v for %s\n", val.Type(), name)
   340  			b, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
   341  			if err != nil || b == nil {
   342  				return err
   343  			}
   344  			node.Value = string(b)
   345  			return nil
   346  		}
   347  	}
   348  
   349  	// XMP arrays require special treatment. Most arrays should have MarshalXML
   350  	// methods defined, but in case an extenstion developer forgets, we add this
   351  	// transparently, guessing the correct RDF array type from Go array/slice.
   352  	if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 {
   353  		atype := ArrayTypeOrdered
   354  		if kind == reflect.Array {
   355  			atype = ArrayTypeUnordered
   356  		}
   357  		// log.Debugf("xmp: marshalValue calling MarshalArray on %v for %s\n", typ, name)
   358  		return MarshalArray(e, node, atype, val.Interface())
   359  	}
   360  
   361  	// simple values are just fine
   362  	if node != nil && kind != reflect.Struct {
   363  		// log.Debugf("xmp: marshalValue adding simple value to node %s type %v\n", node.XMLName.Local, typ)
   364  		s, b, err := marshalSimple(typ, val)
   365  		if err != nil {
   366  			return err
   367  		}
   368  		if b != nil {
   369  			s = string(b)
   370  		}
   371  		node.Value = s
   372  		return nil
   373  	}
   374  
   375  	// handle structs
   376  	tinfo, err := getTypeInfo(typ, "xmp")
   377  	if err != nil {
   378  		return err
   379  	}
   380  
   381  	// encode struct attributes
   382  	for _, finfo := range tinfo.fields {
   383  		if finfo.flags&fOmit > 0 {
   384  			continue
   385  		}
   386  
   387  		if finfo.flags&fAttr == 0 {
   388  			continue
   389  		}
   390  
   391  		// version must always match
   392  		if !e.version.Between(finfo.minVersion, finfo.maxVersion) {
   393  			// log.Debugf("xmp: marshalValue attr field %s version %v - %v does not match %v\n", finfo.name, finfo.minVersion, finfo.maxVersion, e.version)
   394  			continue
   395  		}
   396  
   397  		fv := finfo.value(val)
   398  
   399  		if (fv.Kind() == reflect.Interface || fv.Kind() == reflect.Ptr) && fv.IsNil() {
   400  			// log.Debugf("xmp: marshalValue attr field %s is nil\n", finfo.name)
   401  			continue
   402  		}
   403  
   404  		if finfo.flags&fEmpty == 0 && isEmptyValue(fv) {
   405  			// log.Debugf("xmp: marshalValue attr field %s is empty\n", finfo.name)
   406  			continue
   407  		}
   408  
   409  		// find or create output node for storing the attribute/node contents
   410  		var dest *Node
   411  		if withWrapper || node == nil {
   412  			ns := e.findNs(NewName(finfo.name))
   413  			if ns == nil {
   414  				return fmt.Errorf("xmp: missing namespace for attr field %s", finfo.name)
   415  			}
   416  			dest = node.Nodes.FindNode(ns)
   417  			if dest == nil {
   418  				// log.Debugf("xmp: marshalValue creating new node for attr field %s type %s\n", finfo.name, ns.GetName())
   419  				dest = NewNode(ns.XMLName(""))
   420  				node.AddNode(dest)
   421  			}
   422  		} else {
   423  			dest = node
   424  		}
   425  
   426  		name := NewName(finfo.name)
   427  		if err := e.marshalAttr(dest, name, fv); err != nil {
   428  			return err
   429  		}
   430  	}
   431  
   432  	// encode struct fields
   433  	var haveField bool
   434  	for _, finfo := range tinfo.fields {
   435  		if finfo.flags&fOmit > 0 {
   436  			continue
   437  		}
   438  
   439  		if finfo.flags&fElement == 0 {
   440  			// log.Debugf("xmp: marshalValue field %s is not an element\n", finfo.name)
   441  			continue
   442  		}
   443  
   444  		// version must always match
   445  		if !e.version.Between(finfo.minVersion, finfo.maxVersion) {
   446  			// log.Debugf("xmp: marshalValue node field %s version %v - %v does not match %v\n", finfo.name, finfo.minVersion, finfo.maxVersion, e.version)
   447  			continue
   448  		}
   449  
   450  		fv := finfo.value(val)
   451  
   452  		if (fv.Kind() == reflect.Interface || fv.Kind() == reflect.Ptr) && fv.IsNil() {
   453  			// log.Debugf("xmp: marshalValue node field %s is nil\n", finfo.name)
   454  			continue
   455  		}
   456  
   457  		if finfo.flags&fEmpty == 0 && isEmptyValue(fv) {
   458  			// log.Debugf("xmp: marshalValue node field %s is empty\n", finfo.name)
   459  			continue
   460  		}
   461  
   462  		// find or create output node for storing the attribute/node contents
   463  		var dest *Node
   464  		if withWrapper || node == nil {
   465  			ns := e.findNs(NewName(finfo.name))
   466  			if ns == nil {
   467  				return fmt.Errorf("xmp: marshalValue missing namespace for %s", finfo.name)
   468  			}
   469  			dest = node.Nodes.FindNode(ns)
   470  			if dest == nil {
   471  				// log.Debugf("xmp: marshalValue creating new node for node field %s type %s\n", finfo.name, ns.GetName())
   472  				dest = NewNode(ns.XMLName(""))
   473  				node.AddNode(dest)
   474  			}
   475  		} else {
   476  			dest = node
   477  		}
   478  
   479  		// create a new node for this resource
   480  		resNode := NewNode(NewName(finfo.name))
   481  		dest.AddNode(resNode)
   482  
   483  		if err := e.marshalValue(fv, &finfo, resNode, false); err != nil {
   484  			return err
   485  		}
   486  		haveField = true
   487  	}
   488  
   489  	if haveField && node.XMLName != rdfDescription {
   490  		// for all kinds of structs add rdf:resource as node attribute
   491  		node.AddAttr(rdfResourceAttr)
   492  	}
   493  
   494  	return nil
   495  }
   496  
   497  func isEmptyValue(v reflect.Value) bool {
   498  	if v.CanInterface() && v.Type().Implements(zeroType) {
   499  		return v.Interface().(Zero).IsZero()
   500  	}
   501  
   502  	switch v.Kind() {
   503  	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
   504  		return v.Len() == 0
   505  	case reflect.Bool:
   506  		return !v.Bool()
   507  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   508  		return v.Int() == 0
   509  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   510  		return v.Uint() == 0
   511  	case reflect.Float32, reflect.Float64:
   512  		return v.Float() == 0
   513  	case reflect.Interface, reflect.Ptr:
   514  		return v.IsNil()
   515  	}
   516  	return false
   517  }
   518  
   519  func (e *Encoder) marshalAttr(node *Node, name xml.Name, val reflect.Value) error {
   520  	if val.CanInterface() && val.Type().Implements(attrMarshalerType) {
   521  		// log.Debugf("xmp: marshalAttr calling MarshalXmpAttr on %v for %s\n", val.Type(), name.Local)
   522  		attr, err := val.Interface().(MarshalerAttr).MarshalXMPAttr(e, name, node)
   523  		if err != nil {
   524  			return err
   525  		}
   526  		if attr.Name.Local != "" {
   527  			node.AddAttr(attr)
   528  		}
   529  		return nil
   530  	}
   531  
   532  	if val.CanAddr() {
   533  		pv := val.Addr()
   534  		if pv.CanInterface() && pv.Type().Implements(attrMarshalerType) {
   535  			// log.Debugf("xmp: marshalAttr calling MarshalXmpAttr on %v for %s\n", val.Type(), name.Local)
   536  			attr, err := pv.Interface().(MarshalerAttr).MarshalXMPAttr(e, name, node)
   537  			if err != nil {
   538  				return err
   539  			}
   540  			if attr.Name.Local != "" {
   541  				node.AddAttr(attr)
   542  			}
   543  			return nil
   544  		}
   545  	}
   546  
   547  	if val.CanInterface() && val.Type().Implements(textMarshalerType) {
   548  		// log.Debugf("xmp: marshalAttr calling MarshalText on %v for %s\n", val.Type(), name.Local)
   549  		b, err := val.Interface().(encoding.TextMarshaler).MarshalText()
   550  		if err != nil || b == nil {
   551  			return err
   552  		}
   553  		node.AddAttr(Attr{Name: name, Value: string(b)})
   554  		return nil
   555  	}
   556  
   557  	if val.CanAddr() {
   558  		pv := val.Addr()
   559  		if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
   560  			// log.Debugf("xmp: marshalAttr calling MarshalText on %v for %s\n", val.Type(), name.Local)
   561  			b, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
   562  			if err != nil || b == nil {
   563  				return err
   564  			}
   565  			node.AddAttr(Attr{Name: name, Value: string(b)})
   566  			return nil
   567  		}
   568  	}
   569  
   570  	// Dereference or skip nil pointer, interface values.
   571  	switch val.Kind() {
   572  	case reflect.Ptr, reflect.Interface:
   573  		if val.IsNil() {
   574  			// log.Debugf("xmp: marshalAttr field %s is nil\n", name.Local)
   575  			return nil
   576  		}
   577  		val = val.Elem()
   578  	}
   579  
   580  	s, b, err := marshalSimple(val.Type(), val)
   581  	if err != nil {
   582  		return err
   583  	}
   584  	if b != nil {
   585  		s = string(b)
   586  	}
   587  	node.AddAttr(Attr{Name: name, Value: s})
   588  	return nil
   589  }
   590  
   591  func marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) {
   592  	switch val.Kind() {
   593  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   594  		return strconv.FormatInt(val.Int(), 10), nil, nil
   595  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   596  		return strconv.FormatUint(val.Uint(), 10), nil, nil
   597  	case reflect.Float32, reflect.Float64:
   598  		return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil
   599  	case reflect.String:
   600  		return val.String(), nil, nil
   601  	case reflect.Bool:
   602  		return strconv.FormatBool(val.Bool()), nil, nil
   603  	case reflect.Array:
   604  		if typ.Elem().Kind() != reflect.Uint8 {
   605  			break
   606  		}
   607  		// [...]byte
   608  		var bytes []byte
   609  		if val.CanAddr() {
   610  			bytes = val.Slice(0, val.Len()).Bytes()
   611  		} else {
   612  			bytes = make([]byte, val.Len())
   613  			reflect.Copy(reflect.ValueOf(bytes), val)
   614  		}
   615  		return "", bytes, nil
   616  	case reflect.Slice:
   617  		if typ.Elem().Kind() != reflect.Uint8 {
   618  			break
   619  		}
   620  		// []byte
   621  		return "", val.Bytes(), nil
   622  	}
   623  	return "", nil, fmt.Errorf("xmp: no method for marshalling type %s (%v)\n", typ.String(), val.Kind())
   624  }
   625  
   626  func (e Encoder) _findNsByURI(uri string) *Namespace {
   627  	if v, ok := e.intNsMap[uri]; ok {
   628  		return v
   629  	}
   630  	if v, ok := e.extNsMap[uri]; ok {
   631  		return v
   632  	}
   633  	return nil
   634  }
   635  
   636  func (e Encoder) _findNsByPrefix(pre string) *Namespace {
   637  	for _, v := range e.intNsMap {
   638  		if v.GetName() == pre {
   639  			return v
   640  		}
   641  	}
   642  	for _, v := range e.extNsMap {
   643  		if v.GetName() == pre {
   644  			return v
   645  		}
   646  	}
   647  	if ns, err := NsRegistry.GetNamespace(pre); err == nil {
   648  		return ns
   649  	}
   650  	return nil
   651  }
   652  
   653  func (e Encoder) findNs(n xml.Name) *Namespace {
   654  	var ns *Namespace
   655  	if n.Space != "" {
   656  		ns = e._findNsByURI(n.Space)
   657  	}
   658  	if ns == nil {
   659  		ns = e._findNsByPrefix(getPrefix(n.Local))
   660  	}
   661  	return ns
   662  }
   663  
   664  func ToString(t interface{}) string {
   665  	val := reflect.Indirect(reflect.ValueOf(t))
   666  	if !val.IsValid() {
   667  		return ""
   668  	}
   669  	if val.Type().Implements(stringerType) {
   670  		return t.(fmt.Stringer).String()
   671  	}
   672  	if s, err := ToRawString(val.Interface()); err == nil {
   673  		return s
   674  	}
   675  	return fmt.Sprintf("%v", val.Interface())
   676  }
   677  
   678  func isBase64(s string) bool {
   679  	_, err := base64.StdEncoding.DecodeString(s)
   680  	return err == nil
   681  }
   682  
   683  func ToRawString(t interface{}) (string, error) {
   684  	val := reflect.Indirect(reflect.ValueOf(t))
   685  	typ := val.Type()
   686  	switch val.Kind() {
   687  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   688  		return strconv.FormatInt(val.Int(), 10), nil
   689  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   690  		return strconv.FormatUint(val.Uint(), 10), nil
   691  	case reflect.Float32, reflect.Float64:
   692  		return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil
   693  	case reflect.String:
   694  		return val.String(), nil
   695  	case reflect.Bool:
   696  		return strconv.FormatBool(val.Bool()), nil
   697  	case reflect.Array:
   698  		if typ.Elem().Kind() != reflect.Uint8 {
   699  			break
   700  		}
   701  		// [...]byte
   702  		var b []byte
   703  		if val.CanAddr() {
   704  			b = val.Slice(0, val.Len()).Bytes()
   705  		} else {
   706  			b = make([]byte, val.Len())
   707  			reflect.Copy(reflect.ValueOf(b), val)
   708  		}
   709  		if !isBase64(string(b)) {
   710  			return base64.StdEncoding.EncodeToString(b), nil
   711  		}
   712  		return string(b), nil
   713  	case reflect.Slice:
   714  		if typ.Elem().Kind() != reflect.Uint8 {
   715  			break
   716  		}
   717  		// []byte
   718  		b := val.Bytes()
   719  		if !isBase64(string(b)) {
   720  			return base64.StdEncoding.EncodeToString(b), nil
   721  		}
   722  		return string(b), nil
   723  	}
   724  	return "", fmt.Errorf("xmp: no method for converting type %s (%v) to string", typ.String(), val.Kind())
   725  }