@@ -151,64 +151,103 @@ lyb_parse_union(const void *lyb_data, size_t lyb_data_len, uint32_t *type_idx, c
151
151
}
152
152
153
153
/**
154
- * @brief Store subvalue as a specific type.
154
+ * @brief Store (and validate) subvalue as a specific type.
155
155
*
156
156
* @param[in] ctx libyang context.
157
- * @param[in] type Specific union type to use for storing.
158
- * @param[in] subvalue Union subvalue structure.
157
+ * @param[in] type_u Union type.
158
+ * @param[in] type_idx Union type index to use for storing (and validating).
159
+ * @param[in,out] subvalue Union subvalue structure, its value needs to be filled.
159
160
* @param[in] options The store options.
160
- * @param[in] resolve Whether the value needs to be resolved ( validated by a callback) .
161
+ * @param[in] validate Whether the value needs to be validated.
161
162
* @param[in] ctx_node Context node for prefix resolution.
162
163
* @param[in] tree Data tree for resolving (validation).
163
164
* @param[in,out] unres Global unres structure.
164
165
* @param[out] err Error information on error.
165
166
* @return LY_ERR value.
166
167
*/
167
168
static LY_ERR
168
- union_store_type (const struct ly_ctx * ctx , struct lysc_type * type , struct lyd_value_union * subvalue , uint32_t options ,
169
- ly_bool resolve , const struct lyd_node * ctx_node , const struct lyd_node * tree , struct lys_glob_unres * unres ,
170
- struct ly_err_item * * err )
169
+ union_store_type (const struct ly_ctx * ctx , struct lysc_type_union * type_u , uint32_t type_idx , struct lyd_value_union * subvalue ,
170
+ uint32_t options , ly_bool validate , const struct lyd_node * ctx_node , const struct lyd_node * tree ,
171
+ struct lys_glob_unres * unres , struct ly_err_item * * err )
171
172
{
172
- LY_ERR ret ;
173
+ LY_ERR rc = LY_SUCCESS ;
174
+ struct lysc_type * type = type_u -> types [type_idx ];
173
175
const void * value = NULL ;
174
176
size_t value_len = 0 ;
175
- uint32_t opts ;
177
+ ly_bool dynamic = 0 ;
178
+ LY_VALUE_FORMAT format ;
179
+ void * prefix_data ;
180
+ uint32_t opts = 0 , ti ;
176
181
177
182
* err = NULL ;
178
183
179
184
if (subvalue -> format == LY_VALUE_LYB ) {
180
- lyb_parse_union (subvalue -> original , subvalue -> orig_len , NULL , & value , & value_len );
185
+ lyb_parse_union (subvalue -> original , subvalue -> orig_len , & ti , & value , & value_len );
186
+ if (ti != type_idx ) {
187
+ /* value of another type, first store the value properly and then use its JSON value for parsing */
188
+ rc = type_u -> types [ti ]-> plugin -> store (ctx , type_u -> types [ti ], value , value_len , LYPLG_TYPE_STORE_ONLY ,
189
+ subvalue -> format , subvalue -> prefix_data , subvalue -> hints , subvalue -> ctx_node , & subvalue -> value , unres , err );
190
+ if ((rc != LY_SUCCESS ) && (rc != LY_EINCOMPLETE )) {
191
+ /* clear any leftover/freed garbage */
192
+ memset (& subvalue -> value , 0 , sizeof subvalue -> value );
193
+ return rc ;
194
+ }
195
+
196
+ assert (subvalue -> value .realtype );
197
+ value = subvalue -> value .realtype -> plugin -> print (ctx , & subvalue -> value , LY_VALUE_JSON , NULL , & dynamic , & value_len );
198
+
199
+ /* to avoid leaks, free subvalue->value, but we need the value, which may be stored there */
200
+ if (!dynamic ) {
201
+ value = strndup (value , value_len );
202
+ dynamic = 1 ;
203
+ }
204
+ type_u -> types [ti ]-> plugin -> free (ctx , & subvalue -> value );
205
+
206
+ format = LY_VALUE_JSON ;
207
+ prefix_data = NULL ;
208
+ } else {
209
+ format = subvalue -> format ;
210
+ prefix_data = subvalue -> prefix_data ;
211
+ }
181
212
} else {
182
213
value = subvalue -> original ;
183
214
value_len = subvalue -> orig_len ;
215
+ format = subvalue -> format ;
216
+ prefix_data = subvalue -> prefix_data ;
217
+ }
218
+
219
+ if (options & LYPLG_TYPE_STORE_ONLY ) {
220
+ opts |= LYPLG_TYPE_STORE_ONLY ;
221
+ }
222
+ if (dynamic ) {
223
+ opts |= LYPLG_TYPE_STORE_DYNAMIC ;
184
224
}
185
225
186
- opts = (options & LYPLG_TYPE_STORE_ONLY ) ? LYPLG_TYPE_STORE_ONLY : 0 ;
187
- ret = type -> plugin -> store (ctx , type , value , value_len , opts , subvalue -> format , subvalue -> prefix_data , subvalue -> hints ,
226
+ rc = type -> plugin -> store (ctx , type , value , value_len , opts , format , prefix_data , subvalue -> hints ,
188
227
subvalue -> ctx_node , & subvalue -> value , unres , err );
189
- if ((ret != LY_SUCCESS ) && (ret != LY_EINCOMPLETE )) {
228
+ if ((rc != LY_SUCCESS ) && (rc != LY_EINCOMPLETE )) {
190
229
/* clear any leftover/freed garbage */
191
230
memset (& subvalue -> value , 0 , sizeof subvalue -> value );
192
- return ret ;
231
+ return rc ;
193
232
}
194
233
195
- if (resolve && (ret == LY_EINCOMPLETE )) {
196
- /* we need the value resolved */
197
- ret = type -> plugin -> validate (ctx , type , ctx_node , tree , & subvalue -> value , err );
198
- if (ret ) {
199
- /* resolve failed, we need to free the stored value */
234
+ if (validate && (rc == LY_EINCOMPLETE )) {
235
+ /* we need the value validated */
236
+ rc = type -> plugin -> validate (ctx , type , ctx_node , tree , & subvalue -> value , err );
237
+ if (rc ) {
238
+ /* validate failed, we need to free the stored value */
200
239
type -> plugin -> free (ctx , & subvalue -> value );
201
240
}
202
241
}
203
242
204
- return ret ;
243
+ return rc ;
205
244
}
206
245
207
246
/**
208
247
* @brief Find the first valid type for a union value.
209
248
*
210
249
* @param[in] ctx libyang context.
211
- * @param[in] types Sized array of union types .
250
+ * @param[in] type_u Union type .
212
251
* @param[in] subvalue Union subvalue structure.
213
252
* @param[in] options The store options.
214
253
* @param[in] resolve Whether the value needs to be resolved (validated by a callback).
@@ -220,7 +259,7 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type *type, struct lyd_va
220
259
* @return LY_ERR value.
221
260
*/
222
261
static LY_ERR
223
- union_find_type (const struct ly_ctx * ctx , struct lysc_type * * types , struct lyd_value_union * subvalue ,
262
+ union_find_type (const struct ly_ctx * ctx , struct lysc_type_union * type_u , struct lyd_value_union * subvalue ,
224
263
uint32_t options , ly_bool resolve , const struct lyd_node * ctx_node , const struct lyd_node * tree ,
225
264
uint32_t * type_idx , struct lys_glob_unres * unres , struct ly_err_item * * err )
226
265
{
@@ -233,43 +272,43 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type **types, struct lyd_v
233
272
234
273
* err = NULL ;
235
274
236
- if (!types || !LY_ARRAY_COUNT (types )) {
237
- return LY_EINVAL ;
238
- }
239
-
240
275
/* alloc errors */
241
- errs = calloc (LY_ARRAY_COUNT (types ), sizeof * errs );
276
+ errs = calloc (LY_ARRAY_COUNT (type_u -> types ), sizeof * errs );
242
277
LY_CHECK_RET (!errs , LY_EMEM );
243
278
244
279
/* turn logging temporarily off */
245
280
prev_lo = ly_temp_log_options (& temp_lo );
246
281
247
282
/* use the first usable subtype to store the value */
248
- for (u = 0 ; u < LY_ARRAY_COUNT (types ); ++ u ) {
249
- ret = union_store_type (ctx , types [ u ] , subvalue , options , resolve , ctx_node , tree , unres , & e );
283
+ for (u = 0 ; u < LY_ARRAY_COUNT (type_u -> types ); ++ u ) {
284
+ ret = union_store_type (ctx , type_u , u , subvalue , options , resolve , ctx_node , tree , unres , & e );
250
285
if ((ret == LY_SUCCESS ) || (ret == LY_EINCOMPLETE )) {
251
286
break ;
252
287
}
253
288
254
289
errs [u ] = e ;
255
290
}
256
291
257
- if (u == LY_ARRAY_COUNT (types )) {
292
+ if (u == LY_ARRAY_COUNT (type_u -> types )) {
258
293
/* create the full error */
259
- msg_len = asprintf (& msg , "Invalid union value \"%.*s\" - no matching subtype found:\n" ,
260
- (int )subvalue -> orig_len , (char * )subvalue -> original );
294
+ if (subvalue -> format == LY_VALUE_LYB ) {
295
+ msg_len = asprintf (& msg , "Invalid LYB union value - no matching subtype found:\n" );
296
+ } else {
297
+ msg_len = asprintf (& msg , "Invalid union value \"%.*s\" - no matching subtype found:\n" ,
298
+ (int )subvalue -> orig_len , (char * )subvalue -> original );
299
+ }
261
300
if (msg_len == -1 ) {
262
301
LY_CHECK_ERR_GOTO (!errs , ret = LY_EMEM , cleanup );
263
302
}
264
- for (u = 0 ; u < LY_ARRAY_COUNT (types ); ++ u ) {
303
+ for (u = 0 ; u < LY_ARRAY_COUNT (type_u -> types ); ++ u ) {
265
304
if (!errs [u ]) {
266
305
/* no error for some reason */
267
306
continue ;
268
307
}
269
308
270
- msg = ly_realloc (msg , msg_len + 4 + strlen (types [u ]-> plugin -> id ) + 2 + strlen (errs [u ]-> msg ) + 2 );
309
+ msg = ly_realloc (msg , msg_len + 4 + strlen (type_u -> types [u ]-> plugin -> id ) + 2 + strlen (errs [u ]-> msg ) + 2 );
271
310
LY_CHECK_ERR_GOTO (!msg , ret = LY_EMEM , cleanup );
272
- msg_len += sprintf (msg + msg_len , " %s: %s\n" , types [u ]-> plugin -> id , errs [u ]-> msg );
311
+ msg_len += sprintf (msg + msg_len , " %s: %s\n" , type_u -> types [u ]-> plugin -> id , errs [u ]-> msg );
273
312
}
274
313
275
314
ret = ly_err_new (err , LY_EVALID , LYVE_DATA , NULL , NULL , "%s" , msg );
@@ -278,7 +317,7 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type **types, struct lyd_v
278
317
}
279
318
280
319
cleanup :
281
- for (u = 0 ; u < LY_ARRAY_COUNT (types ); ++ u ) {
320
+ for (u = 0 ; u < LY_ARRAY_COUNT (type_u -> types ); ++ u ) {
282
321
ly_err_free (errs [u ]);
283
322
}
284
323
free (errs );
@@ -334,7 +373,7 @@ lyb_fill_subvalue(const struct ly_ctx *ctx, struct lysc_type_union *type_u, cons
334
373
}
335
374
336
375
/* use the specific type to store the value */
337
- ret = union_store_type (ctx , type_u -> types [ type_idx ] , subvalue , * options , 0 , NULL , NULL , unres , err );
376
+ ret = union_store_type (ctx , type_u , type_idx , subvalue , * options , 0 , NULL , NULL , unres , err );
338
377
339
378
return ret ;
340
379
}
@@ -362,7 +401,7 @@ lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, c
362
401
ret = lyb_fill_subvalue (ctx , type_u , value , value_len , prefix_data , subvalue , & options , unres , err );
363
402
LY_CHECK_GOTO ((ret != LY_SUCCESS ) && (ret != LY_EINCOMPLETE ), cleanup );
364
403
} else {
365
- /* Store @p value to subvalue. */
404
+ /* store value to subvalue */
366
405
ret = union_subvalue_assignment (value , value_len , & subvalue -> original , & subvalue -> orig_len , & options );
367
406
LY_CHECK_GOTO (ret , cleanup );
368
407
@@ -372,7 +411,7 @@ lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, c
372
411
LY_CHECK_GOTO (ret , cleanup );
373
412
374
413
/* use the first usable subtype to store the value */
375
- ret = union_find_type (ctx , type_u -> types , subvalue , options , 0 , NULL , NULL , NULL , unres , err );
414
+ ret = union_find_type (ctx , type_u , subvalue , options , 0 , NULL , NULL , NULL , unres , err );
376
415
LY_CHECK_GOTO ((ret != LY_SUCCESS ) && (ret != LY_EINCOMPLETE ), cleanup );
377
416
}
378
417
@@ -399,22 +438,31 @@ lyplg_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type
399
438
struct lysc_type_union * type_u = (struct lysc_type_union * )type ;
400
439
struct lyd_value_union * subvalue = storage -> subvalue ;
401
440
uint32_t type_idx ;
441
+ ly_bool validated = 0 ;
402
442
403
443
* err = NULL ;
404
444
405
445
/* because of types that do not store their own type as realtype (leafref), we are not able to call their
406
- * validate callback (there is no way to get the type TODO could be added to struct lyd_value_union), so
407
- * we have to perform union value storing again from scratch */
446
+ * validate callback (there is no way to get the type) but even if possible, the value may be invalid
447
+ * for the type, so we may have to perform union value storing again from scratch */
408
448
subvalue -> value .realtype -> plugin -> free (ctx , & subvalue -> value );
409
449
410
450
if (subvalue -> format == LY_VALUE_LYB ) {
411
- /* use the specific type to store the value */
451
+ /* use the specific type to store and validate the value */
412
452
lyb_parse_union (subvalue -> original , 0 , & type_idx , NULL , NULL );
413
- ret = union_store_type (ctx , type_u -> types [type_idx ], subvalue , 0 , 1 , ctx_node , tree , NULL , err );
414
- LY_CHECK_RET (ret );
415
- } else {
453
+ ret = union_store_type (ctx , type_u , type_idx , subvalue , 0 , 1 , ctx_node , tree , NULL , err );
454
+ if (ret ) {
455
+ /* validation failed, we need to try storing the value again */
456
+ ly_err_free (* err );
457
+ * err = NULL ;
458
+ } else {
459
+ validated = 1 ;
460
+ }
461
+ }
462
+
463
+ if (!validated ) {
416
464
/* use the first usable subtype to store the value */
417
- ret = union_find_type (ctx , type_u -> types , subvalue , 0 , 1 , ctx_node , tree , NULL , NULL , err );
465
+ ret = union_find_type (ctx , type_u , subvalue , 0 , 1 , ctx_node , tree , NULL , NULL , err );
418
466
LY_CHECK_RET (ret );
419
467
}
420
468
@@ -495,7 +543,7 @@ lyb_union_print(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct
495
543
ctx = subvalue -> ctx_node -> module -> ctx ;
496
544
}
497
545
subvalue -> value .realtype -> plugin -> free (ctx , & subvalue -> value );
498
- r = union_find_type (ctx , type_u -> types , subvalue , 0 , 0 , NULL , NULL , & type_idx , NULL , & err );
546
+ r = union_find_type (ctx , type_u , subvalue , 0 , 0 , NULL , NULL , & type_idx , NULL , & err );
499
547
ly_err_free (err );
500
548
LY_CHECK_RET ((r != LY_SUCCESS ) && (r != LY_EINCOMPLETE ), NULL );
501
549
0 commit comments