@@ -55,8 +55,8 @@ type partialDoc map[string]*lazyNode
55
55
type partialArray []* lazyNode
56
56
57
57
type container interface {
58
- get (key string ) (* lazyNode , error )
59
- set (key string , val * lazyNode ) error
58
+ get (key string , options * ApplyOptions ) (* lazyNode , error )
59
+ set (key string , val * lazyNode , options * ApplyOptions ) error
60
60
add (key string , val * lazyNode , options * ApplyOptions ) error
61
61
remove (key string , options * ApplyOptions ) error
62
62
}
@@ -376,7 +376,7 @@ Loop:
376
376
return false
377
377
}
378
378
379
- func findObject (pd * container , path string ) (container , string ) {
379
+ func findObject (pd * container , path string , options * ApplyOptions ) (container , string ) {
380
380
doc := * pd
381
381
382
382
split := strings .Split (path , "/" )
@@ -393,7 +393,7 @@ func findObject(pd *container, path string) (container, string) {
393
393
394
394
for _ , part := range parts {
395
395
396
- next , ok := doc .get (decodePatchKey (part ))
396
+ next , ok := doc .get (decodePatchKey (part ), options )
397
397
398
398
if next == nil || ok != nil {
399
399
return nil , ""
@@ -417,7 +417,7 @@ func findObject(pd *container, path string) (container, string) {
417
417
return doc , decodePatchKey (key )
418
418
}
419
419
420
- func (d * partialDoc ) set (key string , val * lazyNode ) error {
420
+ func (d * partialDoc ) set (key string , val * lazyNode , options * ApplyOptions ) error {
421
421
(* d )[key ] = val
422
422
return nil
423
423
}
@@ -427,7 +427,7 @@ func (d *partialDoc) add(key string, val *lazyNode, options *ApplyOptions) error
427
427
return nil
428
428
}
429
429
430
- func (d * partialDoc ) get (key string ) (* lazyNode , error ) {
430
+ func (d * partialDoc ) get (key string , options * ApplyOptions ) (* lazyNode , error ) {
431
431
v , ok := (* d )[key ]
432
432
if ! ok {
433
433
return v , errors .Wrapf (ErrMissing , "unable to get nonexistent key: %s" , key )
@@ -450,12 +450,22 @@ func (d *partialDoc) remove(key string, options *ApplyOptions) error {
450
450
451
451
// set should only be used to implement the "replace" operation, so "key" must
452
452
// be an already existing index in "d".
453
- func (d * partialArray ) set (key string , val * lazyNode ) error {
453
+ func (d * partialArray ) set (key string , val * lazyNode , options * ApplyOptions ) error {
454
454
idx , err := strconv .Atoi (key )
455
455
if err != nil {
456
456
return err
457
457
}
458
458
459
+ if idx < 0 {
460
+ if ! options .SupportNegativeIndices {
461
+ return errors .Wrapf (ErrInvalidIndex , "Unable to access invalid index: %d" , idx )
462
+ }
463
+ if idx < - len (* d ) {
464
+ return errors .Wrapf (ErrInvalidIndex , "Unable to access invalid index: %d" , idx )
465
+ }
466
+ idx += len (* d )
467
+ }
468
+
459
469
(* d )[idx ] = val
460
470
return nil
461
471
}
@@ -499,13 +509,23 @@ func (d *partialArray) add(key string, val *lazyNode, options *ApplyOptions) err
499
509
return nil
500
510
}
501
511
502
- func (d * partialArray ) get (key string ) (* lazyNode , error ) {
512
+ func (d * partialArray ) get (key string , options * ApplyOptions ) (* lazyNode , error ) {
503
513
idx , err := strconv .Atoi (key )
504
514
505
515
if err != nil {
506
516
return nil , err
507
517
}
508
518
519
+ if idx < 0 {
520
+ if ! options .SupportNegativeIndices {
521
+ return nil , errors .Wrapf (ErrInvalidIndex , "Unable to access invalid index: %d" , idx )
522
+ }
523
+ if idx < - len (* d ) {
524
+ return nil , errors .Wrapf (ErrInvalidIndex , "Unable to access invalid index: %d" , idx )
525
+ }
526
+ idx += len (* d )
527
+ }
528
+
509
529
if idx >= len (* d ) {
510
530
return nil , errors .Wrapf (ErrInvalidIndex , "Unable to access invalid index: %d" , idx )
511
531
}
@@ -560,7 +580,7 @@ func (p Patch) add(doc *container, op Operation, options *ApplyOptions) error {
560
580
ensurePathExists (doc , path , options )
561
581
}
562
582
563
- con , key := findObject (doc , path )
583
+ con , key := findObject (doc , path , options )
564
584
565
585
if con == nil {
566
586
return errors .Wrapf (ErrMissing , "add operation does not apply: doc is missing path: \" %s\" " , path )
@@ -598,7 +618,7 @@ func ensurePathExists(pd *container, path string, options *ApplyOptions) error {
598
618
return nil
599
619
}
600
620
601
- target , ok := doc .get (decodePatchKey (part ))
621
+ target , ok := doc .get (decodePatchKey (part ), options )
602
622
603
623
if target == nil || ok != nil {
604
624
@@ -661,7 +681,7 @@ func (p Patch) remove(doc *container, op Operation, options *ApplyOptions) error
661
681
return errors .Wrapf (ErrMissing , "remove operation failed to decode path" )
662
682
}
663
683
664
- con , key := findObject (doc , path )
684
+ con , key := findObject (doc , path , options )
665
685
666
686
if con == nil {
667
687
if options .AllowMissingPathOnRemove {
@@ -684,18 +704,18 @@ func (p Patch) replace(doc *container, op Operation, options *ApplyOptions) erro
684
704
return errors .Wrapf (err , "replace operation failed to decode path" )
685
705
}
686
706
687
- con , key := findObject (doc , path )
707
+ con , key := findObject (doc , path , options )
688
708
689
709
if con == nil {
690
710
return errors .Wrapf (ErrMissing , "replace operation does not apply: doc is missing path: %s" , path )
691
711
}
692
712
693
- _ , ok := con .get (key )
713
+ _ , ok := con .get (key , options )
694
714
if ok != nil {
695
715
return errors .Wrapf (ErrMissing , "replace operation does not apply: doc is missing key: %s" , path )
696
716
}
697
717
698
- err = con .set (key , op .value ())
718
+ err = con .set (key , op .value (), options )
699
719
if err != nil {
700
720
return errors .Wrapf (err , "error in remove for path: '%s'" , path )
701
721
}
@@ -709,13 +729,13 @@ func (p Patch) move(doc *container, op Operation, options *ApplyOptions) error {
709
729
return errors .Wrapf (err , "move operation failed to decode from" )
710
730
}
711
731
712
- con , key := findObject (doc , from )
732
+ con , key := findObject (doc , from , options )
713
733
714
734
if con == nil {
715
735
return errors .Wrapf (ErrMissing , "move operation does not apply: doc is missing from path: %s" , from )
716
736
}
717
737
718
- val , err := con .get (key )
738
+ val , err := con .get (key , options )
719
739
if err != nil {
720
740
return errors .Wrapf (err , "error in move for path: '%s'" , key )
721
741
}
@@ -730,7 +750,7 @@ func (p Patch) move(doc *container, op Operation, options *ApplyOptions) error {
730
750
return errors .Wrapf (err , "move operation failed to decode path" )
731
751
}
732
752
733
- con , key = findObject (doc , path )
753
+ con , key = findObject (doc , path , options )
734
754
735
755
if con == nil {
736
756
return errors .Wrapf (ErrMissing , "move operation does not apply: doc is missing destination path: %s" , path )
@@ -750,13 +770,13 @@ func (p Patch) test(doc *container, op Operation, options *ApplyOptions) error {
750
770
return errors .Wrapf (err , "test operation failed to decode path" )
751
771
}
752
772
753
- con , key := findObject (doc , path )
773
+ con , key := findObject (doc , path , options )
754
774
755
775
if con == nil {
756
776
return errors .Wrapf (ErrMissing , "test operation does not apply: is missing path: %s" , path )
757
777
}
758
778
759
- val , err := con .get (key )
779
+ val , err := con .get (key , options )
760
780
if err != nil && errors .Cause (err ) != ErrMissing {
761
781
return errors .Wrapf (err , "error in test for path: '%s'" , path )
762
782
}
@@ -783,13 +803,13 @@ func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64, op
783
803
return errors .Wrapf (err , "copy operation failed to decode from" )
784
804
}
785
805
786
- con , key := findObject (doc , from )
806
+ con , key := findObject (doc , from , options )
787
807
788
808
if con == nil {
789
809
return errors .Wrapf (ErrMissing , "copy operation does not apply: doc is missing from path: %s" , from )
790
810
}
791
811
792
- val , err := con .get (key )
812
+ val , err := con .get (key , options )
793
813
if err != nil {
794
814
return errors .Wrapf (err , "error in copy for from: '%s'" , from )
795
815
}
@@ -799,7 +819,7 @@ func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64, op
799
819
return errors .Wrapf (ErrMissing , "copy operation failed to decode path" )
800
820
}
801
821
802
- con , key = findObject (doc , path )
822
+ con , key = findObject (doc , path , options )
803
823
804
824
if con == nil {
805
825
return errors .Wrapf (ErrMissing , "copy operation does not apply: doc is missing destination path: %s" , path )
0 commit comments