@@ -124,6 +124,74 @@ std::optional<var> JSONUtils::setPointer (const var& v,
124124 return {};
125125}
126126
127+ bool JSONUtils::updatePointer (var& v, String pointer, const var& newValue)
128+ {
129+ if (pointer.isEmpty ())
130+ return false ;
131+
132+ if (! pointer.startsWith (" /" ))
133+ {
134+ // This is not a well-formed JSON pointer
135+ jassertfalse;
136+ return {};
137+ }
138+
139+ const auto findResult = pointer.indexOfChar (1 , ' /' );
140+ const auto pos = findResult < 0 ? pointer.length () : findResult;
141+ const String head (pointer.begin () + 1 , pointer.begin () + pos);
142+ const String tail (pointer.begin () + pos, pointer.end ());
143+
144+ const auto unescaped = head.replace (" ~1" , " /" ).replace (" ~0" , " ~" );
145+
146+ if (auto * object = v.getDynamicObject ())
147+ {
148+ if (tail.isEmpty ())
149+ {
150+ object->setProperty (unescaped, newValue);
151+ return true ;
152+ }
153+
154+ auto v = object->getProperty (unescaped);
155+ return updatePointer (v, tail, newValue);
156+ }
157+ else if (auto * array = v.getArray ())
158+ {
159+ const auto index = [&]() -> size_t
160+ {
161+ if (unescaped == " -" )
162+ return (size_t ) array->size ();
163+
164+ if (unescaped == " 0" )
165+ return 0 ;
166+
167+ if (! unescaped.startsWith (" 0" ))
168+ return (size_t ) unescaped.getLargeIntValue ();
169+
170+ return std::numeric_limits<size_t >::max ();
171+ }();
172+
173+ if (tail.isEmpty ())
174+ {
175+ if (isPositiveAndBelow (index, array->size ()))
176+ {
177+ array->set (int (index), newValue);
178+ return true ;
179+ }
180+
181+ if (index == array->size ())
182+ {
183+ array->add (newValue);
184+ return true ;
185+ }
186+ }
187+
188+ auto v = (*array)[(int ) index];
189+ return updatePointer (v, tail, newValue);
190+ }
191+
192+ return false ;
193+ }
194+
127195var JSONUtils::getPointer (const var& v, String pointer, const var& defaultValue)
128196{
129197 if (pointer.isEmpty ())
0 commit comments