github.com/boki/go-xmp@v1.0.1/xmp/path.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  	"encoding"
    19  	"fmt"
    20  	"reflect"
    21  	"sort"
    22  	"strconv"
    23  	"strings"
    24  )
    25  
    26  type Path string
    27  
    28  type PathValue struct {
    29  	Path      Path      `json:"path"`
    30  	Namespace string    `json:"namespace,omitempty"`
    31  	Value     string    `json:"value"`
    32  	Flags     SyncFlags `json:"flags,omitempty"`
    33  }
    34  
    35  type PathValueList []PathValue
    36  
    37  func (x *PathValueList) Add(p Path, v string) {
    38  	if v == "" {
    39  		return
    40  	}
    41  	*x = append(*x, PathValue{Path: p, Value: v})
    42  }
    43  
    44  func (x *PathValueList) AddFlags(p Path, v string, f SyncFlags) {
    45  	if v == "" {
    46  		return
    47  	}
    48  	*x = append(*x, PathValue{Path: p, Value: v, Flags: f})
    49  }
    50  
    51  func (x PathValueList) Find(p Path) *PathValue {
    52  	for _, v := range x {
    53  		if v.Path == p {
    54  			return &v
    55  		}
    56  	}
    57  	return nil
    58  }
    59  
    60  // assumes a sorted list
    61  func (x PathValueList) Unique() PathValueList {
    62  	l := make(PathValueList, 0, len(x))
    63  	var last Path
    64  	for _, v := range x {
    65  		if last != v.Path {
    66  			l = append(l, v)
    67  			last = v.Path
    68  		}
    69  	}
    70  	return l
    71  }
    72  
    73  func (x PathValueList) Diff(y PathValueList) PathValueList {
    74  	if len(x) == 0 {
    75  		return y
    76  	}
    77  	if len(y) == 0 {
    78  		return x
    79  	}
    80  	diff := make(PathValueList, 0, Max(len(x), len(y)))
    81  	for _, xv := range x {
    82  		yv := y.Find(xv.Path)
    83  		if yv == nil {
    84  			diff.AddFlags(xv.Path, xv.Value, DELETE)
    85  			continue
    86  		}
    87  		if yv.Value != xv.Value {
    88  			diff.AddFlags(xv.Path, xv.Value, REPLACE)
    89  		}
    90  	}
    91  	for _, yv := range y {
    92  		xv := x.Find(yv.Path)
    93  		if xv == nil {
    94  			diff.AddFlags(yv.Path, yv.Value, CREATE)
    95  		}
    96  	}
    97  	return diff
    98  }
    99  
   100  type byPath PathValueList
   101  
   102  func (l byPath) Len() int           { return len(l) }
   103  func (l byPath) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
   104  func (l byPath) Less(i, j int) bool { return l[i].Path.String() < l[j].Path.String() }
   105  
   106  type byValue PathValueList
   107  
   108  func (l byValue) Len() int           { return len(l) }
   109  func (l byValue) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
   110  func (l byValue) Less(i, j int) bool { return l[i].Value < l[j].Value }
   111  
   112  func (x Path) String() string {
   113  	return string(x)
   114  }
   115  
   116  func NewPath(prefix string, segments ...string) Path {
   117  	return Path(prefix + ":" + strings.Join(segments, "/"))
   118  }
   119  
   120  // ns:tagname/subtagname
   121  func (x Path) IsXmpPath() bool {
   122  	return strings.Index(string(x), ":") > -1
   123  }
   124  
   125  func (x Path) NamespacePrefix() string {
   126  	if i := strings.Index(string(x), ":"); i > -1 {
   127  		return string(x[:i])
   128  	}
   129  	return string(x)
   130  }
   131  
   132  func (x Path) Namespace(d *Document) (*Namespace, error) {
   133  	if i := strings.Index(string(x), ":"); i > -1 {
   134  		if ns := d.findNsByPrefix(string(x[:i])); ns != nil {
   135  			return ns, nil
   136  		}
   137  	}
   138  	return nil, fmt.Errorf("xmp: invalid path '%s'", x.String())
   139  }
   140  
   141  func (x Path) MatchNamespace(ns *Namespace) bool {
   142  	if ns == nil {
   143  		return false
   144  	}
   145  	if i := strings.Index(string(x), ":"); i > -1 {
   146  		return ns.GetName() == string(x[:i])
   147  	}
   148  	return false
   149  }
   150  
   151  func (x Path) Len() int {
   152  	s := string(x)
   153  	if i := strings.Index(s, ":"); i > -1 {
   154  		s = strings.TrimPrefix(s[i+1:], "/")
   155  		if len(s) > 0 {
   156  			return strings.Count(s, "/") + 1
   157  		}
   158  	}
   159  	return 0
   160  }
   161  
   162  func (x Path) Fields() []string {
   163  	s := string(x)
   164  	if i := strings.Index(s, ":"); i > -1 {
   165  		y := strings.TrimPrefix(s[i+1:], "/")
   166  		if len(y) > 0 {
   167  			return strings.Split(y, "/")
   168  		}
   169  	}
   170  	return nil
   171  }
   172  
   173  func (x Path) AppendIndex(i int) Path {
   174  	f := "%s[%d]"
   175  	if strings.HasSuffix(x.String(), "]") {
   176  		f = "%s/[%d]"
   177  	}
   178  	return Path(fmt.Sprintf(f, x.String(), i))
   179  }
   180  
   181  func (x Path) AppendIndexString(s string) Path {
   182  	f := "%s[%s]"
   183  	if strings.HasSuffix(x.String(), "]") {
   184  		f = "%s/[%s]"
   185  	}
   186  	return Path(fmt.Sprintf(f, x.String(), s))
   187  }
   188  
   189  func (x Path) Push(segment ...string) Path {
   190  	f := x.Fields()
   191  	f = append(f, segment...)
   192  	return NewPath(x.NamespacePrefix(), f...)
   193  }
   194  
   195  func (x Path) Pop() (string, Path) {
   196  	f := x.Fields()
   197  	switch l := len(f); l {
   198  	case 0:
   199  		return "", x
   200  	case 1:
   201  		return f[0], NewPath(x.NamespacePrefix())
   202  	default:
   203  		return f[l-1], NewPath(x.NamespacePrefix(), f[:l-1]...)
   204  	}
   205  }
   206  
   207  func (x Path) PopFront() (string, Path) {
   208  	switch f := x.Fields(); len(f) {
   209  	case 0:
   210  		return "", x
   211  	case 1:
   212  		seg := f[0]
   213  		ns := x.NamespacePrefix()
   214  		if hasPrefix(seg) {
   215  			ns = getPrefix(seg)
   216  			seg = stripPrefix(seg)
   217  		}
   218  		return seg, NewPath(ns)
   219  	default:
   220  		seg := f[0]
   221  		ns := x.NamespacePrefix()
   222  		if hasPrefix(seg) {
   223  			ns = getPrefix(seg)
   224  			seg = stripPrefix(seg)
   225  		}
   226  		return seg, NewPath(ns, f[1:]...)
   227  	}
   228  }
   229  
   230  func (x Path) PeekNamespacePrefix() string {
   231  	switch f := x.Fields(); len(f) {
   232  	case 0:
   233  		return x.NamespacePrefix()
   234  	default:
   235  		if hasPrefix(f[0]) {
   236  			return getPrefix(f[0])
   237  		}
   238  		return x.NamespacePrefix()
   239  	}
   240  }
   241  
   242  func (x *Path) UnmarshalText(data []byte) error {
   243  	p := Path(string(data))
   244  	if !p.IsXmpPath() {
   245  		return fmt.Errorf("xmp: invalid path '%s'", p.String())
   246  	}
   247  	*x = p
   248  	return nil
   249  }
   250  
   251  func (d *Document) GetPath(path Path) (string, error) {
   252  	if !path.IsXmpPath() {
   253  		return "", fmt.Errorf("xmp: invalid path '%s'", path.String())
   254  	}
   255  	ns, err := path.Namespace(d)
   256  	if err != nil {
   257  		return "", err
   258  	}
   259  	n := d.FindNode(ns)
   260  	if n == nil {
   261  		return "", fmt.Errorf("xmp: path '%s' not found", path.String())
   262  	}
   263  	if n.Model != nil {
   264  		if s, err := GetModelPath(n.Model, path); err == nil {
   265  			return s, nil
   266  		} else if err != errNotFound {
   267  			return "", fmt.Errorf("xmp: path '%s' error: %v", path.String(), err)
   268  		}
   269  	}
   270  	if v, err := n.GetPath(path); err != nil {
   271  		if err == errNotFound {
   272  			return "", fmt.Errorf("xmp: path '%s' not found", path.String())
   273  		} else {
   274  			return "", fmt.Errorf("xmp: path '%s' error: %v", path.String(), err)
   275  		}
   276  	} else {
   277  		return v, nil
   278  	}
   279  }
   280  
   281  func GetModelPath(v Model, path Path) (string, error) {
   282  	val := derefIndirect(v)
   283  	l := path.Len()
   284  	for n, walker := path.PopFront(); n != ""; n, walker = walker.PopFront() {
   285  		// fmt.Printf("%d name=%s walker=%s\n", l-walker.Len(), n, walker.String())
   286  		name, idx, lang := parsePathSegment(n)
   287  		if idx < -1 {
   288  			return "", fmt.Errorf("path field %d (%s): invalid index", l-walker.Len(), n)
   289  		}
   290  
   291  		finfo, err := findField(val, name, "xmp")
   292  		if err != nil {
   293  			return "", errNotFound
   294  			// return "", fmt.Errorf("path field %d (%s) not found: %v", i, name, err)
   295  		}
   296  
   297  		fv := finfo.value(val)
   298  		typ := fv.Type()
   299  
   300  		// ignore empty fields
   301  		if !fv.IsValid() {
   302  			return "", nil
   303  		}
   304  		if (fv.Kind() == reflect.Interface || fv.Kind() == reflect.Ptr) && fv.IsNil() {
   305  			return "", nil
   306  		}
   307  		if finfo.flags&fOmit > 0 || (finfo.flags&fEmpty == 0 && isEmptyValue(fv)) {
   308  			return "", nil
   309  		}
   310  
   311  		// Drill into interfaces and pointers.
   312  		for fv.Kind() == reflect.Interface || fv.Kind() == reflect.Ptr {
   313  			fv = fv.Elem()
   314  		}
   315  
   316  		// continue loop when field is a struct and we're not at the end yet
   317  		if fv.Kind() == reflect.Struct && walker.Len() > 0 {
   318  			val = fv
   319  			continue
   320  		}
   321  
   322  		// handle XMP array types
   323  		av := fv
   324  		isArray := false
   325  		if fv.CanInterface() && (finfo != nil && finfo.flags&fArray > 0 || typ.Implements(arrayType)) {
   326  			isArray = true
   327  		} else if fv.CanAddr() {
   328  			pv := fv.Addr()
   329  			if pv.CanInterface() && (finfo != nil && finfo.flags&fArray > 0 || pv.Type().Implements(arrayType)) {
   330  				av = pv
   331  				isArray = true
   332  			}
   333  		}
   334  
   335  		if isArray {
   336  			switch arr := av.Interface().(type) {
   337  			case ExtensionArray:
   338  				if walker.Len() == 0 || fv.Len() <= idx {
   339  					return "", errNotFound
   340  				}
   341  				ext := arr[idx]
   342  				name = walker.PeekNamespacePrefix()
   343  				node := ext.FindNodeByName(name)
   344  				if node == nil {
   345  					return "", errNotFound
   346  				}
   347  				if node.Model != nil {
   348  					val = reflect.Indirect(reflect.ValueOf(node.Model))
   349  					continue
   350  				}
   351  				return node.GetPath(walker)
   352  
   353  			case NamedExtensionArray:
   354  				node := arr.FindNodeByName(name)
   355  				if node == nil {
   356  					return "", errNotFound
   357  				}
   358  				return node.GetPath(walker)
   359  
   360  			case AltString:
   361  				if lang != "" {
   362  					return arr.Get(lang), nil
   363  				}
   364  				return arr.Default(), nil
   365  			default:
   366  				// sanitize array index
   367  				if idx < 0 {
   368  					idx = 0
   369  				}
   370  				if fv.Len() < idx {
   371  					return "", errNotFound
   372  				}
   373  				if walker.Len() > 0 {
   374  					if av.Len() <= idx {
   375  						return "", errNotFound
   376  					}
   377  					val = derefValue(av.Index(idx))
   378  					continue
   379  				} else {
   380  					if av.Len() <= idx {
   381  						return "", errNotFound
   382  					}
   383  					fv = derefValue(av.Index(idx))
   384  					typ = fv.Type()
   385  					finfo = nil
   386  				}
   387  			}
   388  		}
   389  
   390  		// Check for text marshaler and marshal as string
   391  		av = fv
   392  		isText := false
   393  		if fv.CanInterface() && (finfo != nil && finfo.flags&fTextMarshal > 0 || typ.Implements(textMarshalerType)) {
   394  			isText = true
   395  		} else if fv.CanAddr() {
   396  			pv := fv.Addr()
   397  			if pv.CanInterface() && (finfo != nil && finfo.flags&fTextMarshal > 0 || pv.Type().Implements(textMarshalerType)) {
   398  				av = pv
   399  				isText = true
   400  			}
   401  		}
   402  
   403  		if isText {
   404  			b, err := av.Interface().(encoding.TextMarshaler).MarshalText()
   405  			if err != nil || b == nil {
   406  				return "", err
   407  			}
   408  			return string(b), nil
   409  		}
   410  
   411  		// handle maps
   412  		if fv.Kind() == reflect.Map {
   413  			if finfo.flags&fFlat == 0 {
   414  				n, walker = walker.PopFront()
   415  				name, _, _ = parsePathSegment(n)
   416  			}
   417  			val := fv.MapIndex(reflect.ValueOf(name))
   418  			if !val.IsValid() {
   419  				return "", errNotFound
   420  			}
   421  			// process as simple value below
   422  			fv = val
   423  			typ = val.Type()
   424  		}
   425  
   426  		// simple values are just fine, but any other type (slice, array, struct)
   427  		// without textmarshaler will fail here
   428  		if s, b, err := marshalSimple(typ, fv); err != nil {
   429  			return "", err
   430  		} else {
   431  			if b != nil {
   432  				s = string(b)
   433  			}
   434  			return s, nil
   435  		}
   436  	}
   437  	return "", nil
   438  }
   439  
   440  func (d *Document) SetPath(desc PathValue) error {
   441  	flags := desc.Flags
   442  	path := desc.Path
   443  	value := desc.Value
   444  
   445  	if flags == 0 {
   446  		flags = DEFAULT
   447  	}
   448  	if !path.IsXmpPath() {
   449  		return fmt.Errorf("xmp: invalid path '%s'", path.String())
   450  	}
   451  
   452  	ns, err := path.Namespace(d)
   453  	if ns == nil || err != nil {
   454  		if desc.Namespace != "" {
   455  			ns = &Namespace{path.NamespacePrefix(), desc.Namespace, nil}
   456  			Register(ns)
   457  		} else {
   458  			return err
   459  		}
   460  	}
   461  
   462  	m := d.FindModel(ns)
   463  	n := d.FindNode(ns)
   464  	if m == nil && n == nil && flags&CREATE == 0 {
   465  		if flags&NOFAIL > 0 {
   466  			return nil
   467  		}
   468  		return fmt.Errorf("xmp: create flag required to make model for '%s'", path.String())
   469  	}
   470  	if m == nil {
   471  		m = ns.NewModel()
   472  		if m != nil {
   473  			n, _ = d.AddModel(m)
   474  		}
   475  	}
   476  	if m == nil && n == nil {
   477  		n = d.nodes.AddNode(NewNode(ns.RootName()))
   478  	}
   479  
   480  	// empty source will only be used with delete flag
   481  	if value == "" && flags&DELETE == 0 {
   482  		if flags&NOFAIL > 0 {
   483  			return nil
   484  		}
   485  		return fmt.Errorf("xmp: delete flag required for empty '%s'", path.String())
   486  	}
   487  
   488  	// delete model when only namespace is set
   489  	if path.Len() == 0 && flags&DELETE > 0 {
   490  		d.RemoveNamespace(ns)
   491  	}
   492  
   493  	// get current version of path value
   494  	var dest string
   495  	if m != nil {
   496  		dest, err = GetModelPath(m, path)
   497  	}
   498  	if m == nil || err == errNotFound {
   499  		dest, err = n.GetPath(path)
   500  	}
   501  	if err != nil {
   502  		return err
   503  	}
   504  
   505  	// skip when equal
   506  	if dest == value {
   507  		return nil
   508  	}
   509  
   510  	// empty destination values require create flag
   511  	if dest == "" && flags&(CREATE|APPEND|UNIQUE) == 0 {
   512  		if flags&NOFAIL > 0 {
   513  			return nil
   514  		}
   515  		return fmt.Errorf("xmp: create flag required to make new attribute at '%s'", path.String())
   516  	}
   517  
   518  	// existing destination values require replace/delete/append/unique flag
   519  	if dest != "" && flags&(REPLACE|DELETE|APPEND|UNIQUE) == 0 {
   520  		if flags&NOFAIL > 0 {
   521  			return nil
   522  		}
   523  		return fmt.Errorf("xmp: update flag required to change existing attribute at '%s'", path.String())
   524  	}
   525  
   526  	if m != nil {
   527  		if err = SetModelPath(m, path, value, flags); err != nil && err == errNotFound {
   528  			err = n.SetPath(path, value, flags)
   529  		}
   530  	} else {
   531  		err = n.SetPath(path, value, flags)
   532  	}
   533  	if err == nil {
   534  		d.SetDirty()
   535  	}
   536  
   537  	if flags&NOFAIL > 0 {
   538  		return nil
   539  	}
   540  	return err
   541  }
   542  
   543  func SetModelPath(v Model, path Path, value string, flags SyncFlags) error {
   544  	if flags == 0 {
   545  		flags = DEFAULT
   546  	}
   547  	if !path.IsXmpPath() {
   548  		return fmt.Errorf("xmp: invalid path '%s'", path.String())
   549  	}
   550  
   551  	val := derefIndirect(v)
   552  
   553  	l := path.Len()
   554  	for n, walker := path.PopFront(); n != ""; n, walker = walker.PopFront() {
   555  		name, idx, lang := parsePathSegment(n)
   556  		if idx < -1 {
   557  			return fmt.Errorf("path field %d (%s): invalid index", l-walker.Len(), n)
   558  		}
   559  
   560  		// using the short-form of name here to find attribute names across namespaces
   561  		// (e.g. some models use different namespace structs internally)
   562  		finfo, err := findField(val, name, "xmp")
   563  		if err != nil {
   564  			// special error is catched by caller to retry setting as raw node
   565  			return errNotFound
   566  		}
   567  
   568  		// allocate memory for pointer values in structs
   569  		fv := finfo.value(val)
   570  		if !fv.IsValid() {
   571  			return nil
   572  		}
   573  		if fv.Type().Kind() == reflect.Ptr && fv.IsNil() && fv.CanSet() {
   574  			fv.Set(reflect.New(fv.Type().Elem()))
   575  		}
   576  		fv = derefValue(fv)
   577  
   578  		// continue loop when field is a struct and we're not at the end
   579  		if fv.Kind() == reflect.Struct && walker.Len() > 0 {
   580  			val = fv
   581  			continue
   582  		}
   583  
   584  		// handle maps
   585  		if fv.Kind() == reflect.Map {
   586  			// use proper name depending on flattening
   587  			if finfo.flags&fFlat == 0 {
   588  				n, walker = walker.PopFront()
   589  				name, _, _ = parsePathSegment(n)
   590  			}
   591  
   592  			t := fv.Type()
   593  			if fv.IsNil() {
   594  				fv.Set(reflect.MakeMap(t))
   595  			}
   596  			switch t.Key().Kind() {
   597  			case reflect.String:
   598  			default:
   599  				return fmt.Errorf("map key type must be string")
   600  			}
   601  
   602  			switch {
   603  			case flags&DELETE > 0 && value == "":
   604  				// remove map value
   605  				fv.SetMapIndex(reflect.ValueOf(name), reflect.Zero(t.Elem()))
   606  				return nil
   607  			case flags&(REPLACE|CREATE) > 0 && value != "":
   608  				// set map value
   609  				switch t.Elem().Kind() {
   610  				case reflect.String:
   611  					fv.SetMapIndex(reflect.ValueOf(name), reflect.ValueOf(value).Convert(t.Elem()))
   612  				case reflect.Struct:
   613  					val = reflect.New(t.Elem()).Elem()
   614  					// FIXME: this recursion may not work as expected because the map
   615  					// value is not updated when set later on
   616  					fv.SetMapIndex(reflect.ValueOf(name), val)
   617  					continue
   618  				default:
   619  					// FIXME: this does not allow for struct pointers as map values
   620  					mval := reflect.New(t.Elem()).Elem()
   621  					if mval.Type().Kind() == reflect.Ptr && mval.IsNil() && mval.CanSet() {
   622  						mval.Set(reflect.New(mval.Type().Elem()))
   623  					}
   624  					if mval.CanInterface() && mval.Type().Implements(textUnmarshalerType) {
   625  						if err := mval.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value)); err != nil {
   626  							return err
   627  						}
   628  					} else if mval.CanAddr() {
   629  						pv := mval.Addr()
   630  						if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
   631  							if err := pv.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value)); err != nil {
   632  								return err
   633  							}
   634  						}
   635  					} else {
   636  						if err := setValue(mval, value); err != nil {
   637  							return err
   638  						}
   639  					}
   640  					fv.SetMapIndex(reflect.ValueOf(name), mval)
   641  					return nil
   642  				}
   643  			}
   644  			continue
   645  		}
   646  
   647  		// handle Slice/Array type fields as pointers to make them settable
   648  		av := fv
   649  		if fv.CanAddr() {
   650  			av = fv.Addr()
   651  		}
   652  		if av.CanInterface() && (finfo != nil && finfo.flags&fArray > 0 || av.Type().Implements(arrayType)) {
   653  			switch arr := av.Interface().(type) {
   654  			case *ExtensionArray:
   655  				// unwrap extension namespace and keep path remainder
   656  				name = walker.PeekNamespacePrefix()
   657  
   658  				// sanitize idx (it is -1 when no array index was specified)
   659  				if idx < 0 {
   660  					idx = 0
   661  				}
   662  
   663  				// add empty nodes up to idx if necessary
   664  				if l := len(*arr); l <= idx {
   665  					if flags&(CREATE|APPEND) == 0 && value != "" {
   666  						return fmt.Errorf("CREATE flag required to add extension %s on path %s", name, path)
   667  					}
   668  					// grow slice and fill with initialized nodes
   669  					for ; l <= idx; l++ {
   670  						*arr = append(*arr, (*Extension)(NewNode(EmptyName)))
   671  					}
   672  				}
   673  
   674  				// use the node at index
   675  				ext := (*arr)[idx]
   676  				node := (*Node)(ext)
   677  
   678  				// there is two types of extensions
   679  				if node.Name() != "" || node.FullName() == "rdf:Description" {
   680  					// Type 1: model and nodes on top-level (name not empty)
   681  					node = ext.FindNodeByName(name)
   682  					if node == nil {
   683  						if ns, err := GetNamespace(name); err == nil {
   684  							node.Model = ns.NewModel()
   685  						}
   686  					}
   687  					if node.Model != nil {
   688  						// FIXME: when the model does not contain the path we might
   689  						// want to store it as child node, however, the for{} loop
   690  						// allows no back-tracking on error
   691  						val = reflect.Indirect(reflect.ValueOf(node.Model))
   692  						continue
   693  					}
   694  					// store as child node
   695  					return node.SetPath(walker, value, flags)
   696  				} else {
   697  					// Type 2: models on child level (empty name); used for xmpMM:Pantry
   698  					child := node.Nodes.FindNodeByName(name)
   699  					if child == nil {
   700  						child = node.AddNode(NewNode(NewName(name)))
   701  					}
   702  					if child.Model == nil {
   703  						if ns, err := GetNamespace(name); err == nil {
   704  							child.Model = ns.NewModel()
   705  						}
   706  					}
   707  					if child.Model != nil {
   708  						// FIXME: when the model does not contain the path we might
   709  						// want to store it as extension model child node. however,
   710  						// the for{} loop allows no back-tracking on error
   711  						val = reflect.Indirect(reflect.ValueOf(child.Model))
   712  						continue
   713  					}
   714  					// store as child node
   715  					return child.SetPath(NewPath(name, walker.Fields()...), value, flags)
   716  				}
   717  
   718  			case *NamedExtensionArray:
   719  				// Named extensions do not contain models
   720  				// unwrap extension namespace and keep path remainder
   721  				name, walker = walker.PopFront()
   722  				node := arr.FindNodeByName(name)
   723  				if node == nil {
   724  					// create new extension node without model
   725  					if flags&(CREATE|APPEND) == 0 && value != "" {
   726  						return fmt.Errorf("CREATE flag required to add extension %s on path %s", name, path)
   727  					}
   728  					node = NewNode(NewName(name))
   729  					ext := (*Extension)(node)
   730  					fv.Set(reflect.Append(fv, reflect.ValueOf(ext)))
   731  				}
   732  				// store as child node
   733  				return node.SetPath(walker, value, flags)
   734  
   735  			case *AltString:
   736  				switch {
   737  				case flags&UNIQUE > 0 && value != "":
   738  					// append source when not exist
   739  					if !arr.AddUnique(lang, value) {
   740  						return fmt.Errorf("equal value exists for %s on path %s", name, path)
   741  					}
   742  				case flags&APPEND > 0 && value != "":
   743  					// append source value
   744  					arr.Add(lang, value)
   745  				case flags&(REPLACE|CREATE) > 0 && value != "":
   746  					// replace entire AltString with a new version
   747  					if lang != "" {
   748  						arr.Set(lang, value)
   749  					} else {
   750  						*arr = NewAltString(value)
   751  					}
   752  				case flags&DELETE > 0 && value == "":
   753  					// delete the entire AltString or just a specific language
   754  					if lang != "" {
   755  						arr.RemoveLang(lang)
   756  					} else {
   757  						fv.Set(reflect.Zero(fv.Type()))
   758  					}
   759  				}
   760  				return nil
   761  
   762  			default:
   763  				// deref the pointer
   764  				av = reflect.Indirect(av)
   765  				// are we at the end of the path?
   766  				if walker.Len() > 0 {
   767  					// sanitize idx (it is -1 when no array index was specified)
   768  					if idx < 0 {
   769  						idx = 0
   770  					}
   771  					// handle arrays along the path
   772  					if av.Len() <= idx {
   773  						if flags&DELETE > 0 && value == "" {
   774  							// would be deleting smth inside a non-existent element
   775  							return nil
   776  						}
   777  						if flags&(CREATE|APPEND) == 0 {
   778  							return fmt.Errorf("CREATE flag required to grow slice %s to index %d", name, idx)
   779  						}
   780  						if av.Kind() == reflect.Array {
   781  							return fmt.Errorf("array %s index %d out of bounds", name, idx)
   782  						}
   783  
   784  						// add empty items up to idx
   785  						// FIXME: when an error occurs later on, we cannot remove slice entry
   786  						growSlice(fv, idx)
   787  						val = reflect.New(fv.Type().Elem())
   788  						fv.Index(idx).Set(val.Elem())
   789  						val = derefValue(fv.Index(idx))
   790  
   791  						// unmarshal text
   792  						if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
   793  							return val.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value))
   794  						}
   795  
   796  						// recurse into struct
   797  						if reflect.Indirect(val).Kind() == reflect.Struct {
   798  							continue
   799  						}
   800  
   801  						// when reaching this, path is too long
   802  						return errNotFound
   803  					}
   804  
   805  					// recurse to next path segment using the value at slice index
   806  					val = derefValue(fv.Index(idx))
   807  					continue
   808  				}
   809  
   810  				// arrays are fixed size
   811  				if av.Kind() == reflect.Array {
   812  					if flags&REPLACE == 0 && value != "" {
   813  						return fmt.Errorf("REPLACE flag required for setting array value in %s", name)
   814  					}
   815  					if flags&DELETE == 0 && value == "" {
   816  						return fmt.Errorf("DELETE flag required to clear array value in %s", name)
   817  					}
   818  
   819  					// sanitize idx (it is -1 when no array index was specified)
   820  					if idx < 0 {
   821  						idx = 0
   822  					}
   823  					if av.Len() <= idx {
   824  						return fmt.Errorf("array %s index %d out of bounds", name, idx)
   825  					}
   826  
   827  					v := reflect.New(fv.Type().Elem())
   828  					if v.CanInterface() && v.Type().Implements(textUnmarshalerType) {
   829  						if err := v.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value)); err != nil {
   830  							return err
   831  						}
   832  					} else if err := setValue(v, value); err != nil {
   833  						return err
   834  					}
   835  					av.Index(idx).Set(v.Elem())
   836  					return nil
   837  				}
   838  
   839  				switch {
   840  				// case flags&UNIQUE > 0 && value != "" && idx > -1:
   841  				// ignore the unique flag when setting with absolute slice index
   842  				case flags&UNIQUE > 0 && value != "" && idx == -1:
   843  					// append if unique
   844  					for i, l := 0, fv.Len(); i < l; i++ {
   845  						v := derefValue(fv.Index(i))
   846  
   847  						isText := false
   848  						vv := v
   849  						if v.CanInterface() && v.Type().Implements(textMarshalerType) {
   850  							isText = true
   851  						} else if v.CanAddr() {
   852  							pv := v.Addr()
   853  							if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
   854  								vv = pv
   855  								isText = true
   856  							}
   857  						}
   858  
   859  						if isText {
   860  							b, err := vv.Interface().(encoding.TextMarshaler).MarshalText()
   861  							if err != nil || b == nil {
   862  								return err
   863  							}
   864  							if value == string(b) {
   865  								return fmt.Errorf("equal value exists for %s on path %s", name, path)
   866  							}
   867  						} else {
   868  							if s, b, err := marshalSimple(v.Type(), v); err != nil {
   869  								return err
   870  							} else {
   871  								if b != nil {
   872  									s = string(b)
   873  								}
   874  								if value == s {
   875  									return fmt.Errorf("equal value exists for %s on path %s", name, path)
   876  								}
   877  							}
   878  						}
   879  					}
   880  
   881  					v := reflect.New(fv.Type().Elem())
   882  					if v.CanInterface() && v.Type().Implements(textUnmarshalerType) {
   883  						if err := v.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value)); err != nil {
   884  							return err
   885  						}
   886  					} else if err := setValue(v, value); err != nil {
   887  						return err
   888  					}
   889  
   890  					fv.Set(reflect.Append(fv, v.Elem()))
   891  
   892  				case flags&APPEND > 0 && value != "" && idx == -1:
   893  					// always append
   894  					v := reflect.New(fv.Type().Elem())
   895  					if v.CanInterface() && v.Type().Implements(textUnmarshalerType) {
   896  						if err := v.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value)); err != nil {
   897  							return err
   898  						}
   899  					} else if err := setValue(v, value); err != nil {
   900  						return err
   901  					}
   902  
   903  					fv.Set(reflect.Append(fv, v.Elem()))
   904  
   905  				case flags&(REPLACE|CREATE) > 0 && value != "" && idx > -1:
   906  					// replace or create slice element at index
   907  					v := reflect.New(fv.Type().Elem())
   908  					if v.CanInterface() && v.Type().Implements(textUnmarshalerType) {
   909  						if err := v.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value)); err != nil {
   910  							return err
   911  						}
   912  					} else if err := setValue(v, value); err != nil {
   913  						return err
   914  					}
   915  					// optionally growing the slice
   916  					growSlice(fv, idx)
   917  					// overwrite current entry,
   918  					fv.Index(idx).Set(v.Elem())
   919  
   920  				case flags&(REPLACE|CREATE) > 0 && value != "" && idx == -1:
   921  					// replace entire slice with a single element
   922  					v := reflect.New(fv.Type().Elem())
   923  					if v.CanInterface() && v.Type().Implements(textUnmarshalerType) {
   924  						if err := v.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value)); err != nil {
   925  							return err
   926  						}
   927  					} else if err := setValue(v, value); err != nil {
   928  						return err
   929  					}
   930  					fv.Set(reflect.Zero(fv.Type()))
   931  					fv.Set(reflect.Append(fv, v.Elem()))
   932  
   933  				case flags&DELETE > 0 && value == "" && idx > -1:
   934  					// delete slice element at index
   935  					l := fv.Len()
   936  					if l <= idx {
   937  						return fmt.Errorf("slice %s index %d out of bounds", name, idx)
   938  					}
   939  					switch {
   940  					case idx == 0:
   941  						fv.Set(fv.Slice(1, l))
   942  					case idx == l-1:
   943  						fv.Set(fv.Slice(0, idx))
   944  					default:
   945  						fv.Set(reflect.AppendSlice(fv.Slice3(0, idx, l-1), fv.Slice(idx+1, l)))
   946  					}
   947  
   948  				case flags&DELETE > 0 && value == "" && idx == -1:
   949  					// delete the entire slice
   950  					fv.Set(reflect.Zero(fv.Type()))
   951  				default:
   952  					return fmt.Errorf("unsupported flag combination %v", flags)
   953  				}
   954  				return nil
   955  			}
   956  		}
   957  
   958  		// for simple values, check current value before replacing
   959  		if flags&REPLACE == 0 && value != "" && !isEmptyValue(fv) {
   960  			return fmt.Errorf("REPLACE flag required for overwriting value at %s on path %s", name, path)
   961  		}
   962  
   963  		// Text
   964  		if fv.CanAddr() {
   965  			pv := fv.Addr()
   966  			if pv.CanInterface() && (finfo != nil && finfo.flags&fTextUnmarshal > 0 || pv.Type().Implements(textUnmarshalerType)) {
   967  				return pv.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value))
   968  			}
   969  		}
   970  
   971  		// otherwise set simple value directly
   972  		return setValue(fv, value)
   973  	}
   974  	return nil
   975  }
   976  
   977  func (d *Document) ListPaths() (PathValueList, error) {
   978  	// sync individual models to establish correct XMP entries
   979  	if err := d.syncToXMP(); err != nil {
   980  		return nil, err
   981  	}
   982  	l := make(PathValueList, 0)
   983  	for _, v := range d.nodes {
   984  		if v.Model != nil {
   985  			if pvl, err := ListModelPaths(v.Model); err != nil {
   986  				return nil, err
   987  			} else {
   988  				l = append(l, pvl...)
   989  			}
   990  		}
   991  		r, err := v.ListPaths(NewPath(v.Name()))
   992  		if err != nil {
   993  			return nil, err
   994  		}
   995  		l = append(l, r...)
   996  	}
   997  	sort.Sort(byPath(l))
   998  	return l.Unique(), nil
   999  }
  1000  
  1001  func ListModelPaths(v Model) (PathValueList, error) {
  1002  	return listPaths(reflect.ValueOf(v), NewPath(v.Namespaces()[0].GetName()))
  1003  }
  1004  
  1005  func listPaths(val reflect.Value, path Path) (PathValueList, error) {
  1006  	if !val.IsValid() {
  1007  		return nil, nil
  1008  	}
  1009  
  1010  	if isEmptyValue(val) {
  1011  		return nil, nil
  1012  	}
  1013  
  1014  	for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
  1015  		if val.IsNil() {
  1016  			return nil, nil
  1017  		}
  1018  		val = val.Elem()
  1019  	}
  1020  
  1021  	typ := val.Type()
  1022  	tinfo, err := getTypeInfo(typ, "xmp")
  1023  	if err != nil {
  1024  		return nil, err
  1025  	}
  1026  
  1027  	pvl := make(PathValueList, 0)
  1028  
  1029  	// walk all fields
  1030  	for _, finfo := range tinfo.fields {
  1031  		fv := finfo.value(val)
  1032  
  1033  		if !fv.IsValid() {
  1034  			continue
  1035  		}
  1036  
  1037  		if (fv.Kind() == reflect.Interface || fv.Kind() == reflect.Ptr) && fv.IsNil() {
  1038  			continue
  1039  		}
  1040  
  1041  		if finfo.flags&fOmit > 0 || (finfo.flags&fEmpty == 0 && isEmptyValue(fv)) {
  1042  			continue
  1043  		}
  1044  
  1045  		// allow changing the namespace on first-level paths to support
  1046  		// multi-namespace models like exif, iptc and quicktime
  1047  		if path.Len() == 0 {
  1048  			ns := path.NamespacePrefix()
  1049  			realNs := getPrefix(finfo.name)
  1050  			if ns != realNs {
  1051  				path = NewPath(realNs)
  1052  			}
  1053  		}
  1054  
  1055  		fname := stripPrefix(finfo.name)
  1056  		if hasPrefix(finfo.name) && getPrefix(finfo.name) != path.NamespacePrefix() {
  1057  			fname = finfo.name
  1058  		}
  1059  
  1060  		// Drill into interfaces and pointers.
  1061  		for fv.Kind() == reflect.Interface || fv.Kind() == reflect.Ptr {
  1062  			fv = fv.Elem()
  1063  		}
  1064  		typ = fv.Type()
  1065  
  1066  		// handle XMP array types
  1067  		av := fv
  1068  		isArray := false
  1069  		if fv.CanInterface() && (finfo.flags&fArray > 0 || typ.Implements(arrayType)) {
  1070  			isArray = true
  1071  		} else if fv.CanAddr() {
  1072  			pv := fv.Addr()
  1073  			if pv.CanInterface() && (finfo.flags&fArray > 0 || pv.Type().Implements(arrayType)) {
  1074  				av = pv
  1075  				isArray = true
  1076  			}
  1077  		}
  1078  
  1079  		if isArray {
  1080  			switch arr := av.Interface().(type) {
  1081  			case ExtensionArray:
  1082  				for i, v := range arr {
  1083  					subpath := path.Push(fname).AppendIndex(i)
  1084  					// name := fmt.Sprintf("%s[%d]", fname, i)
  1085  					if v.Model != nil {
  1086  						if l, err := listPaths(reflect.ValueOf(v.Model), subpath); err != nil {
  1087  							return nil, err
  1088  						} else {
  1089  							pvl = append(pvl, l...)
  1090  						}
  1091  					}
  1092  					if v.XMLName.Local == "" || (*Node)(v).FullName() == "rdf:Description" {
  1093  						for _, child := range v.Nodes {
  1094  							if child.Model != nil {
  1095  								if l, err := listPaths(reflect.ValueOf(child.Model), subpath); err != nil {
  1096  									return nil, err
  1097  								} else {
  1098  									pvl = append(pvl, l...)
  1099  								}
  1100  							} else {
  1101  								if l, err := child.ListPaths(subpath); err != nil {
  1102  									return nil, err
  1103  								} else {
  1104  									pvl = append(pvl, l...)
  1105  								}
  1106  							}
  1107  						}
  1108  					} else {
  1109  						node := (*Node)(v)
  1110  						if l, err := node.ListPaths(subpath); err != nil {
  1111  							return nil, err
  1112  						} else {
  1113  							pvl = append(pvl, l...)
  1114  						}
  1115  					}
  1116  				}
  1117  			case NamedExtensionArray:
  1118  				for _, v := range arr {
  1119  					node := (*Node)(v)
  1120  					if l, err := node.ListPaths(path.Push(fname, node.Name())); err != nil {
  1121  						return nil, err
  1122  					} else {
  1123  						pvl = append(pvl, l...)
  1124  					}
  1125  				}
  1126  
  1127  			case AltString:
  1128  				// AltString types are always at the end of a path
  1129  				for _, v := range arr {
  1130  					pvl.Add(path.Push(fname).AppendIndexString(v.GetLang()), v.Value)
  1131  				}
  1132  			default:
  1133  				for i, l := 0, av.Len(); i < l; i++ {
  1134  					v := derefValue(av.Index(i))
  1135  
  1136  					// check for text marshaler
  1137  					isText := false
  1138  					vv := v
  1139  					if v.CanInterface() && v.Type().Implements(textMarshalerType) {
  1140  						isText = true
  1141  					} else if v.CanAddr() {
  1142  						pv := v.Addr()
  1143  						if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
  1144  							vv = pv
  1145  							isText = true
  1146  						}
  1147  					}
  1148  
  1149  					if isText {
  1150  						b, err := vv.Interface().(encoding.TextMarshaler).MarshalText()
  1151  						if err != nil || b == nil {
  1152  							return nil, err
  1153  						}
  1154  						pvl.Add(path.Push(fname).AppendIndex(i), string(b))
  1155  						continue
  1156  					}
  1157  
  1158  					switch v.Kind() {
  1159  					case reflect.Struct, reflect.Slice, reflect.Array:
  1160  						l, err := listPaths(v, path.Push(fname).AppendIndex(i))
  1161  						if err != nil {
  1162  							return nil, err
  1163  						}
  1164  						pvl = append(pvl, l...)
  1165  					default:
  1166  						if s, b, err := marshalSimple(v.Type(), v); err != nil {
  1167  							return nil, err
  1168  						} else {
  1169  							if b != nil {
  1170  								s = string(b)
  1171  							}
  1172  							pvl.Add(path.Push(fname).AppendIndex(i), s)
  1173  						}
  1174  					}
  1175  				}
  1176  			}
  1177  			continue
  1178  		}
  1179  
  1180  		// Check for text marshaler and marshal as string
  1181  		av = fv
  1182  		isText := false
  1183  		if fv.CanInterface() && (finfo.flags&fTextMarshal > 0 || typ.Implements(textMarshalerType)) {
  1184  			isText = true
  1185  		} else if fv.CanAddr() {
  1186  			pv := fv.Addr()
  1187  			if pv.CanInterface() && (finfo.flags&fTextMarshal > 0 || pv.Type().Implements(textMarshalerType)) {
  1188  				av = pv
  1189  				isText = true
  1190  			}
  1191  		}
  1192  
  1193  		if isText {
  1194  			b, err := av.Interface().(encoding.TextMarshaler).MarshalText()
  1195  			if err != nil || b == nil {
  1196  				return nil, err
  1197  			}
  1198  			pvl.Add(path.Push(fname), string(b))
  1199  			continue
  1200  		}
  1201  
  1202  		// continue iteration when field is a struct without text marshaler
  1203  		if fv.Kind() == reflect.Struct {
  1204  			l, err := listPaths(fv, path.Push(fname))
  1205  			if err != nil {
  1206  				return nil, err
  1207  			}
  1208  			pvl = append(pvl, l...)
  1209  			continue
  1210  		}
  1211  
  1212  		// handle maps
  1213  		if fv.Kind() == reflect.Map {
  1214  			for _, key := range fv.MapKeys() {
  1215  				// need a string representation of key and value here
  1216  				val := fv.MapIndex(key)
  1217  				ks, kb, kerr := marshalSimple(key.Type(), key)
  1218  				if kerr != nil {
  1219  					return nil, kerr
  1220  				}
  1221  				vs, vb, verr := marshalSimple(val.Type(), val)
  1222  				if verr != nil {
  1223  					return nil, verr
  1224  				}
  1225  				if kb != nil {
  1226  					ks = string(kb)
  1227  				}
  1228  				if vb != nil {
  1229  					vs = string(vb)
  1230  				}
  1231  				if finfo.flags&fFlat == 0 {
  1232  					pvl.Add(path.Push(fname, ks), vs)
  1233  				} else {
  1234  					pvl.Add(path.Push(ks), vs)
  1235  				}
  1236  			}
  1237  			continue
  1238  		}
  1239  
  1240  		// otherwise marshal as value
  1241  		if s, b, err := marshalSimple(typ, fv); err != nil {
  1242  			return nil, err
  1243  		} else {
  1244  			if b != nil {
  1245  				s = string(b)
  1246  			}
  1247  			pvl.Add(path.Push(fname), s)
  1248  		}
  1249  	}
  1250  
  1251  	sort.Sort(byPath(pvl))
  1252  	return pvl, nil
  1253  }
  1254  
  1255  func parsePathSegment(name string) (string, int, string) {
  1256  	var lang string
  1257  	var idx int = -1
  1258  	// split lang or array index from name, be safe with slice indexes
  1259  	if k := strings.Index(name, "["); k > 0 && len(name) > k+1 {
  1260  		s := strings.TrimSuffix(name[k+1:], "]")
  1261  		if len(s) == 0 {
  1262  			idx = 0
  1263  		} else if j, err := strconv.Atoi(s); err == nil {
  1264  			idx = j
  1265  		} else {
  1266  			lang = s
  1267  		}
  1268  		name = name[:k]
  1269  	}
  1270  	return name, idx, lang
  1271  }
  1272  
  1273  func growSlice(v reflect.Value, n int) {
  1274  	if v.Kind() != reflect.Slice {
  1275  		return
  1276  	}
  1277  	if l := v.Len(); l <= n {
  1278  		if v.Cap() <= n {
  1279  			ncap := Max(n*2, 4)
  1280  			nv := reflect.MakeSlice(v.Type(), l, ncap)
  1281  			reflect.Copy(nv, v)
  1282  			v.Set(nv)
  1283  		}
  1284  		v.SetLen(n + 1)
  1285  	}
  1286  }