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 }