@@ -151,64 +151,103 @@ lyb_parse_union(const void *lyb_data, size_t lyb_data_len, uint32_t *type_idx, c
151151}
152152
153153/**
154- * @brief Store subvalue as a specific type.
154+ * @brief Store (and validate) subvalue as a specific type.
155155 *
156156 * @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.
159160 * @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.
161162 * @param[in] ctx_node Context node for prefix resolution.
162163 * @param[in] tree Data tree for resolving (validation).
163164 * @param[in,out] unres Global unres structure.
164165 * @param[out] err Error information on error.
165166 * @return LY_ERR value.
166167 */
167168static 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 )
171172{
172- LY_ERR ret ;
173+ LY_ERR rc = LY_SUCCESS ;
174+ struct lysc_type * type = type_u -> types [type_idx ];
173175 const void * value = NULL ;
174176 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 ;
176181
177182 * err = NULL ;
178183
179184 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+ }
181212 } else {
182213 value = subvalue -> original ;
183214 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 ;
184224 }
185225
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 ,
188227 subvalue -> ctx_node , & subvalue -> value , unres , err );
189- if ((ret != LY_SUCCESS ) && (ret != LY_EINCOMPLETE )) {
228+ if ((rc != LY_SUCCESS ) && (rc != LY_EINCOMPLETE )) {
190229 /* clear any leftover/freed garbage */
191230 memset (& subvalue -> value , 0 , sizeof subvalue -> value );
192- return ret ;
231+ return rc ;
193232 }
194233
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 */
200239 type -> plugin -> free (ctx , & subvalue -> value );
201240 }
202241 }
203242
204- return ret ;
243+ return rc ;
205244}
206245
207246/**
208247 * @brief Find the first valid type for a union value.
209248 *
210249 * @param[in] ctx libyang context.
211- * @param[in] types Sized array of union types .
250+ * @param[in] type_u Union type .
212251 * @param[in] subvalue Union subvalue structure.
213252 * @param[in] options The store options.
214253 * @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
220259 * @return LY_ERR value.
221260 */
222261static 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 ,
224263 uint32_t options , ly_bool resolve , const struct lyd_node * ctx_node , const struct lyd_node * tree ,
225264 uint32_t * type_idx , struct lys_glob_unres * unres , struct ly_err_item * * err )
226265{
@@ -233,43 +272,43 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type **types, struct lyd_v
233272
234273 * err = NULL ;
235274
236- if (!types || !LY_ARRAY_COUNT (types )) {
237- return LY_EINVAL ;
238- }
239-
240275 /* alloc errors */
241- errs = calloc (LY_ARRAY_COUNT (types ), sizeof * errs );
276+ errs = calloc (LY_ARRAY_COUNT (type_u -> types ), sizeof * errs );
242277 LY_CHECK_RET (!errs , LY_EMEM );
243278
244279 /* turn logging temporarily off */
245280 prev_lo = ly_temp_log_options (& temp_lo );
246281
247282 /* 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 );
250285 if ((ret == LY_SUCCESS ) || (ret == LY_EINCOMPLETE )) {
251286 break ;
252287 }
253288
254289 errs [u ] = e ;
255290 }
256291
257- if (u == LY_ARRAY_COUNT (types )) {
292+ if (u == LY_ARRAY_COUNT (type_u -> types )) {
258293 /* 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+ }
261300 if (msg_len == -1 ) {
262301 LY_CHECK_ERR_GOTO (!errs , ret = LY_EMEM , cleanup );
263302 }
264- for (u = 0 ; u < LY_ARRAY_COUNT (types ); ++ u ) {
303+ for (u = 0 ; u < LY_ARRAY_COUNT (type_u -> types ); ++ u ) {
265304 if (!errs [u ]) {
266305 /* no error for some reason */
267306 continue ;
268307 }
269308
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 );
271310 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 );
273312 }
274313
275314 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
278317 }
279318
280319cleanup :
281- for (u = 0 ; u < LY_ARRAY_COUNT (types ); ++ u ) {
320+ for (u = 0 ; u < LY_ARRAY_COUNT (type_u -> types ); ++ u ) {
282321 ly_err_free (errs [u ]);
283322 }
284323 free (errs );
@@ -334,7 +373,7 @@ lyb_fill_subvalue(const struct ly_ctx *ctx, struct lysc_type_union *type_u, cons
334373 }
335374
336375 /* 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 );
338377
339378 return ret ;
340379}
@@ -362,7 +401,7 @@ lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, c
362401 ret = lyb_fill_subvalue (ctx , type_u , value , value_len , prefix_data , subvalue , & options , unres , err );
363402 LY_CHECK_GOTO ((ret != LY_SUCCESS ) && (ret != LY_EINCOMPLETE ), cleanup );
364403 } else {
365- /* Store @p value to subvalue. */
404+ /* store value to subvalue */
366405 ret = union_subvalue_assignment (value , value_len , & subvalue -> original , & subvalue -> orig_len , & options );
367406 LY_CHECK_GOTO (ret , cleanup );
368407
@@ -372,7 +411,7 @@ lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, c
372411 LY_CHECK_GOTO (ret , cleanup );
373412
374413 /* 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 );
376415 LY_CHECK_GOTO ((ret != LY_SUCCESS ) && (ret != LY_EINCOMPLETE ), cleanup );
377416 }
378417
@@ -399,22 +438,31 @@ lyplg_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type
399438 struct lysc_type_union * type_u = (struct lysc_type_union * )type ;
400439 struct lyd_value_union * subvalue = storage -> subvalue ;
401440 uint32_t type_idx ;
441+ ly_bool validated = 0 ;
402442
403443 * err = NULL ;
404444
405445 /* 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 */
408448 subvalue -> value .realtype -> plugin -> free (ctx , & subvalue -> value );
409449
410450 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 */
412452 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 ) {
416464 /* 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 );
418466 LY_CHECK_RET (ret );
419467 }
420468
@@ -495,7 +543,7 @@ lyb_union_print(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct
495543 ctx = subvalue -> ctx_node -> module -> ctx ;
496544 }
497545 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 );
499547 ly_err_free (err );
500548 LY_CHECK_RET ((r != LY_SUCCESS ) && (r != LY_EINCOMPLETE ), NULL );
501549
0 commit comments