Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_object_path.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Adaptive Framework Adaptive Object Path
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
14 #include "afw_internal.h"
15 
16 typedef enum {
17  impl_state_end,
18  impl_state_slash_before_adaptor_id,
19  impl_state_adaptor_id,
20  impl_state_after_adaptor_id,
21  impl_state_object_type_id,
22  impl_state_after_object_type_id,
23  impl_state_option_name,
24  impl_state_after_option_name,
25  impl_state_option_value,
26  impl_state_after_option_value,
27  impl_state_entity_object_id,
28  impl_state_entity_object_id_possible_second_asterisk,
29  impl_state_property_name,
30  impl_state_property_name_slash_or_end,
31  impl_state_expect_end
32 } impl_state;
33 
34 
35 /* Set normalized and entity path, if applicable. */
36 static void
37 impl_set_result_paths(
39  const afw_pool_t *p, afw_xctx_t *xctx)
40 {
41  afw_size_t path_len, len;
44 
45  /*
46  * If adaptor id, object type id, or object id are missing, just return.
47  */
48  if (parsed->adaptor_id.len == 0 ||
49  parsed->object_type_id.len == 0 ||
50  parsed->entity_object_id.len == 0)
51  {
52  return;
53  }
54 
55  /*
56  * Calculate len needed for normalized path. Note, entity path is a subset
57  * and will use the same memory.
58  */
59  path_len = 3 /* Slashes. */ +
60  afw_uri_encode_len(&parsed->adaptor_id,
61  AFW_URI_OCTET_UNRESERVED, xctx) +
62  afw_uri_encode_len(&parsed->object_type_id,
63  AFW_URI_OCTET_UNRESERVED, xctx) +
64  afw_uri_encode_len(&parsed->entity_object_id,
65  AFW_URI_OCTET_UNRESERVED, xctx);
66  parsed->entity_path.len = path_len;
67  for (name = parsed->first_property_name; name; name = name->next) {
68  path_len += name->property_name.len + 1 /* slash */;
69  }
70  parsed->normalized_path.len = path_len;
71 
72  /* Create path. */
73  s = afw_pool_malloc(p, path_len, xctx);
74  parsed->normalized_path.s = s;
75  parsed->entity_path.s = s;
76 
77  *s++ = '/';
78  path_len--;
79  len = afw_uri_encode_to_preallocated(s, path_len, &parsed->adaptor_id,
80  AFW_URI_OCTET_UNRESERVED, p, xctx);
81  path_len -= len;
82  s += len;
83 
84  *s++ = '/';
85  path_len--;
86  len = afw_uri_encode_to_preallocated(s, path_len, &parsed->object_type_id,
87  AFW_URI_OCTET_UNRESERVED, p, xctx);
88  path_len -= len;
89  s += len;
90 
91  *s++ = '/';
92  path_len--;
93  parsed->undecoded_object_id.s = s;
94  parsed->undecoded_object_id.len = path_len;
95  len = afw_uri_encode_to_preallocated(s, path_len, &parsed->entity_object_id,
96  AFW_URI_OCTET_UNRESERVED, p, xctx);
97  path_len -= len;
98  s += len;
99 
100  for (name = parsed->first_property_name; name; name = name->next) {
101  *s++ = '/';
102  path_len--;
103  len = afw_uri_encode_to_preallocated(s, path_len, &name->property_name,
104  AFW_URI_OCTET_UNRESERVED, p, xctx);
105  path_len -= len;
106  s += len;
107  }
108 }
109 
110 
111 
112 /* Parse an object path in specific pool. */
114 impl_object_path_parse(
115  const afw_utf8_t *path,
116  const afw_utf8_t *current_path,
117  const afw_object_options_t *default_options,
118  const afw_pool_t *p, afw_xctx_t *xctx)
119 {
120  afw_object_path_parsed_t *parsed;
121  afw_object_path_parsed_t *current_parsed;
122  afw_uri_parser_t parser;
123  impl_state state;
124  const afw_utf8_t *token;
125  afw_boolean_t is_reserved;
126  afw_boolean_t at_end;
127  const afw_utf8_t *name;
128  const afw_octet_t *c;
129  const afw_octet_t *prev_c;
133  afw_boolean_t has_asterisk;
134  afw_size_t len;
135 
136  if (!path || path->len == 0) return NULL;
137 
139  afw_uri_parser_initialize(&parser, path, p, xctx);
140  parsed->original_path.s = afw_memory_dup(path->s, path->len, p, xctx);
141  parsed->original_path.len = path->len;
142  prev_name = NULL;
143  relative_name = NULL;
144  name = NULL;
145 
146  /*
147  * If there is an asterisk in path, current_path is needed for
148  * substitution, so parse it if present.
149  */
150  current_parsed = NULL;
151  for (has_asterisk = false,
152  c = (const afw_octet_t *) path->s,
153  len = path->len;
154  len > 0;
155  c++, len--)
156  {
157  if (*c == '*') {
158  has_asterisk = true;
159  break;
160  }
161  }
162  if (has_asterisk) {
163  if (!current_path) {
164  parsed->contains_unresolved_substitutions = true;
165  }
166  else {
167  current_parsed = impl_object_path_parse(current_path, NULL, NULL,
168  p, xctx);
169  }
170  }
171 
172  /* If starts with '/', set state to slash before adaptor id. */
173  if (*(parser.c) == '/') {
174  state = impl_state_slash_before_adaptor_id;
175  }
176 
177  /*
178  * If not '/', use current path to get relative parts and start with
179  * entity object id.
180  */
181  else {
182  if (current_parsed) {
183  afw_memory_copy(&parsed->adaptor_id, &current_parsed->adaptor_id);
184  afw_memory_copy(&parsed->object_type_id, &current_parsed->object_type_id);
185  if (afw_utf8_equal(&parsed->adaptor_id, &afw_s_a_asterisk) ||
186  afw_utf8_equal(&parsed->object_type_id, &afw_s_a_asterisk))
187  {
188  parsed->contains_unresolved_substitutions = true;
189  }
190  }
191  else {
192  parsed->contains_unresolved_substitutions = true;
193  afw_memory_copy(&parsed->adaptor_id, &afw_s_a_asterisk);
194  afw_memory_copy(&parsed->object_type_id, &afw_s_a_asterisk);
195  }
196  state = impl_state_entity_object_id;
197  }
198 
199  /* Process tokens until end or error. */
200  while (state != impl_state_end) {
201 
202  /* Parse next token and set some variables for convenience. */
203  prev_c = parser.c;
204  afw_uri_parse_next_token(&parser, xctx);
205  token = &parser.token;
206  is_reserved = parser.is_reserved;
207  at_end = !token->s;
208  c = parser.c;
209 
210  /* Process based on state. */
211  switch (state) {
212 
213 
214  /* Initial state where token is a slash before adaptor id. */
215  case impl_state_slash_before_adaptor_id:
216  state = impl_state_adaptor_id;
217  break;
218 
219 
220  /* Token should be an adaptor id, '*', or end. */
221  case impl_state_adaptor_id:
222 
223  if (at_end) {
224  state = impl_state_end;
225  break;
226  }
227 
228  if (is_reserved) {
229  if (!afw_utf8_equal(token, &afw_s_a_asterisk)) {
230  goto error;
231  }
232 
233  if (!current_parsed ||
234  afw_utf8_equal(&current_parsed->adaptor_id,
235  &afw_s_a_asterisk))
236  {
237  parsed->contains_unresolved_substitutions = true;
238  parsed->adaptor_id.s = afw_s_a_asterisk.s;
239  parsed->adaptor_id.len = afw_s_a_asterisk.len;
240  }
241  else {
242  parsed->substituted_adaptor_id = true;
243  parsed->substitution_occurred = true;
244  afw_memory_copy(&parsed->adaptor_id,
245  &current_parsed->adaptor_id);
246  }
247  }
248 
249  else {
250  parsed->adaptor_id.s = token->s;
251  parsed->adaptor_id.len = token->len;
252  }
253 
254  state = impl_state_after_adaptor_id;
255  break;
256 
257 
258  /* After adaptor id is either '/' or end. */
259  case impl_state_after_adaptor_id:
260 
261  if (at_end) {
262  state = impl_state_end;
263  break;
264  }
265 
266  if (!is_reserved || !afw_utf8_equal(token, &afw_s_a_slash)) {
267  goto error;
268  }
269 
270  state = impl_state_object_type_id;
271  break;
272 
273 
274  /* Object type id, '*', or end. */
275  case impl_state_object_type_id:
276 
277  if (at_end) {
278  state = impl_state_end;
279  break;
280  }
281 
282  if (is_reserved) {
283  if (!afw_utf8_equal(token, &afw_s_a_asterisk)) {
284  goto error;
285  }
286  if (!current_parsed ||
287  afw_utf8_equal(&current_parsed->object_type_id,
288  &afw_s_a_asterisk))
289  {
290  parsed->contains_unresolved_substitutions = true;
291  parsed->object_type_id.s = afw_s_a_asterisk.s;
292  parsed->object_type_id.len = afw_s_a_asterisk.len;
293  }
294  else {
295  parsed->substituted_object_type_id = true;
296  parsed->substitution_occurred = true;
297  afw_memory_copy(&parsed->object_type_id,
298  &current_parsed->object_type_id);
299  }
300  }
301 
302  else {
303  parsed->object_type_id.s = token->s;
304  parsed->object_type_id.len = token->len;
305  }
306 
307  state = impl_state_after_object_type_id;
308  break;
309 
310 
311  /* After object type id can be '/', ';' followed by parms, or end. */
312  case impl_state_after_object_type_id:
313 
314  if (at_end) {
315  state = impl_state_end;
316  break;
317  }
318 
319  if (!is_reserved) {
320  goto error;
321  }
322 
323  if (afw_utf8_equal(token, &afw_s_a_slash)) {
324  state = impl_state_entity_object_id;
325  break;
326  }
327 
328  if (afw_utf8_equal(token, &afw_s_a_semicolon)) {
329  state = impl_state_option_name;
330  parsed->options_object =
331  afw_object_create(p, xctx);
332  break;
333  }
334 
335  goto error;
336 
337 
338  /* Option name. */
339  case impl_state_option_name:
340 
341  if (at_end || is_reserved) {
342  goto error;
343  }
344 
345  name = afw_utf8_create(token->s, token->len, p, xctx);
346  state = impl_state_after_option_name;
347  break;
348 
349 
350  /* After option name can be '=', '&', '/', or end. */
351  case impl_state_after_option_name:
352 
353  if (at_end ||
354  (is_reserved && !afw_utf8_equal(token, &afw_s_a_equal)))
355  {
356  afw_object_set_property(parsed->options_object,
357  name, afw_value_true, xctx);
358  }
359 
360  if (at_end) {
361  state = impl_state_end;
362  break;
363  }
364 
365  if (is_reserved) {
366 
367  if (afw_utf8_equal(token, &afw_s_a_equal)) {
368  state = impl_state_option_value;
369  break;
370  }
371 
372  if (afw_utf8_equal(token, &afw_s_a_ampersand)) {
373  state = impl_state_option_name;
374  break;
375  }
376 
377  if (afw_utf8_equal(token, &afw_s_a_slash)) {
378  state = impl_state_entity_object_id;
379  break;
380  }
381  }
382 
383  goto error;
384 
385 
386  /* Value for name '=' pair. */
387  case impl_state_option_value:
388 
389  if (at_end || is_reserved) {
390  goto error;
391  }
392 
393  afw_object_set_property_as_string(parsed->options_object,
394  name, token, xctx);
395 
396  state = impl_state_after_option_value;
397 
398  break;
399 
400 
401  /* After value in name '=' value pair can be '&', '/', or end. */
402  case impl_state_after_option_value:
403 
404  if (at_end) {
405  state = impl_state_end;
406  break;
407  }
408 
409  if (afw_utf8_equal(token, &afw_s_a_ampersand)) {
410  state = impl_state_option_name;
411  break;
412  }
413 
414  if (afw_utf8_equal(token, &afw_s_a_slash)) {
415  state = impl_state_entity_object_id;
416  break;
417  }
418 
419  goto error;
420 
421 
422  /* Entity object id can be '*' or entity object id. */
423  case impl_state_entity_object_id:
424 
425  if (at_end) {
426  state = impl_state_end;
427  break;
428  }
429 
430  if (is_reserved) {
431  if (!afw_utf8_equal(token, &afw_s_a_asterisk)) {
432  goto error;
433  }
434  if (!current_parsed ||
435  afw_utf8_equal(&current_parsed->entity_object_id,
436  &afw_s_a_asterisk))
437  {
438  parsed->contains_unresolved_substitutions = true;
439  parsed->entity_object_id.s = afw_s_a_asterisk.s;
440  parsed->entity_object_id.len = afw_s_a_asterisk.len;
441  }
442  else {
443  parsed->substituted_entity_object_id = true;
444  parsed->substitution_occurred = true;
445  afw_memory_copy(&parsed->entity_object_id,
446  &current_parsed->entity_object_id);
447  }
448  state =
449  impl_state_entity_object_id_possible_second_asterisk;
450  break;
451  }
452 
453  parsed->entity_object_id.s = token->s;
454  parsed->entity_object_id.len = token->len;
455  state = impl_state_property_name_slash_or_end;
456  break;
457 
458 
459  /*
460  * If entity object id starts with '*', another '*' means use all
461  * property names from object path.
462  */
463  case impl_state_entity_object_id_possible_second_asterisk:
464 
465  if (at_end) {
466  state = impl_state_end;
467  break;
468  }
469 
470  if (is_reserved && !afw_utf8_equal(token, &afw_s_a_slash))
471  {
472  if (!afw_utf8_equal(token, &afw_s_a_asterisk))
473  {
474  goto error;
475  }
476  parsed->substituted_entire_object_id = true;
477  if (!current_parsed ||
478  afw_utf8_equal(&current_parsed->entity_object_id,
479  &afw_s_a_asterisk))
480  {
481  parsed->contains_unresolved_substitutions = true;
482  parsed->entity_object_id.s = afw_s_a_asterisk.s;
483  parsed->entity_object_id.len = afw_s_a_asterisk.len;
484  }
485  else {
486  parsed->first_property_name = current_parsed->first_property_name;
487  for (curr_name = (afw_object_path_property_name_entry_t *)
488  parsed->first_property_name;
489  !parsed->contains_unresolved_substitutions && curr_name;
491  curr_name->next)
492  {
493  if (afw_utf8_starts_with(&curr_name->property_name,
494  &afw_s_a_asterisk))
495  {
496  parsed->contains_unresolved_substitutions = true;
497  }
498  }
499  }
500  state = impl_state_expect_end;
501  break;
502  }
503 
504  if (!afw_utf8_equal(token, &afw_s_a_slash)) {
505  goto error;
506  }
507 
508  state = impl_state_property_name;
509  break;
510 
511 
512  /* Property name. */
513  case impl_state_property_name:
514 
515  if (at_end) {
516  goto error;
517  }
518 
519  curr_name = afw_pool_calloc_type(p,
521  if (!prev_name) {
522  parsed->first_property_name = curr_name;
523  relative_name = (current_parsed)
525  current_parsed->first_property_name
526  : NULL;
527  }
528  else {
529  prev_name->next = curr_name;
530  if (relative_name) {
531  relative_name = (afw_object_path_property_name_entry_t *)
532  relative_name->next;
533  }
534  }
535 
536  if (is_reserved && !afw_utf8_equal(token, &afw_s_a_slash))
537  {
538 
539  if (!afw_utf8_equal(token, &afw_s_a_asterisk))
540  {
541  goto error;
542  }
543 
544  if (!current_parsed->first_property_name ||
545  !relative_name ||
546  afw_utf8_equal(&relative_name->property_name,
547  &afw_s_a_asterisk)
548  )
549  {
550  parsed->contains_unresolved_substitutions = true;
551  afw_memory_copy(&curr_name->property_name,
552  &afw_s_a_asterisk);
553  }
554 
555  else {
556  parsed->substituted_property_name = true;
557  parsed->substitution_occurred = true;
558  afw_memory_copy(&curr_name->property_name,
559  &relative_name->property_name);
560  }
561  }
562 
563  else {
564  afw_memory_copy(&curr_name->property_name, token);
565  }
566 
567  prev_name = curr_name;
568  state = impl_state_property_name_slash_or_end;
569  break;
570 
571 
572  /* After property name can be slash or end. */
573  case impl_state_property_name_slash_or_end:
574 
575  if (at_end) {
576  state = impl_state_end;
577  break;
578  }
579 
580  if (!afw_utf8_equal(token, &afw_s_a_slash))
581  {
582  goto error;
583  }
584 
585  state = impl_state_property_name;
586  break;
587 
588 
589  /* Expecting end. */
590  case impl_state_expect_end:
591 
592  if (!at_end) {
593  goto error;
594  }
595 
596  state = impl_state_end;
597  break;
598 
599 
600  /* State is not implemented. */
601  default:
602  AFW_THROW_ERROR_Z(general, "Internal error", xctx);
603  }
604  }
605 
606  /* Set normalized and entity path, if applicable. */
607  impl_set_result_paths(parsed, p, xctx);
608 
609  /* If options object, set options. */
610  if (parsed->options_object) {
611  parsed->options = afw_object_options_set_from_object(
612  default_options, parsed->options_object, p, xctx);
613  }
614  else if (default_options) {
615  parsed->options = default_options;
616  }
617 
618  /* Return parsed result. */
619  return parsed;
620 
621 error:
622  AFW_THROW_ERROR_FZ(general, xctx,
623  "Error parsing object path %" AFW_UTF8_FMT " at offset %d",
624  AFW_UTF8_FMT_ARG(parser.uri),
625  (int)(prev_c - (const afw_octet_t *)parser.uri->s));
626 }
627 
628 
629 AFW_DEFINE(const afw_value_t *)
631  const afw_object_t *object,
632  const afw_object_path_property_name_entry_t *first_property_name,
633  afw_xctx_t *xctx)
634 {
636  const afw_value_t *result;
637 
638  result = afw_object_get_property(object,
639  &first_property_name->property_name, xctx);
640 
641  for (name = first_property_name->next; name; name = name->next) {
642  result = afw_object_get_property(object,
643  &name->property_name, xctx);
644  if (!result) {
645  break;
646  }
647  }
648 
649  return result;
650 }
651 
652 
653 /* Parse an object path in specific pool. */
656  const afw_utf8_t *path,
657  const afw_utf8_t *current_path,
658  const afw_object_options_t *default_options,
659  const afw_pool_t *p,
660  afw_xctx_t *xctx)
661 {
662  return impl_object_path_parse(path, current_path, default_options,
663  p, xctx);
664 }
665 
666 
667 /* Parse simple path into ids. */
668 AFW_DEFINE(void)
670  const afw_utf8_t *path,
671  const afw_utf8_t * *adaptor_id,
672  const afw_utf8_t * *object_type_id,
673  const afw_utf8_t * *object_id,
674  const afw_pool_t *p,
675  afw_xctx_t *xctx)
676 {
677  const afw_utf8_octet_t *c;
678  const afw_utf8_octet_t *s;
679  afw_size_t len;
680 
681  *adaptor_id = NULL;
682  *object_type_id = NULL;
683  *object_id = NULL;
684 
685  len = path->len;
686  c = path->s;
687 
688  if (len-- <= 0 || *c++ != '/') {
689  goto error;
690  }
691 
692  for (s = c; len > 0 && *c != '/'; len--, c++);
693  if (len <= 0 || s == c) {
694  goto error;
695  }
696  *adaptor_id = afw_uri_decode_create(s, c - s, p, xctx);
697  len--;
698  c++;
699 
700  for (s = c; len > 0 && *c != '/'; len--, c++);
701  if (len <= 0 || s == c) {
702  goto error;
703  }
704  *object_type_id = afw_uri_decode_create(s, c - s, p, xctx);
705  c++;
706  len--;
707  if (len <= 0) {
708  goto error;
709  }
710 
711  *object_id = afw_uri_decode_create(c, len, p, xctx);
712 
713  return;
714 
715 error:
716  AFW_THROW_ERROR_FZ(general, xctx,
717  "Invalid path %" AFW_UTF8_FMT,
718  AFW_UTF8_FMT_ARG(path));
719 }
720 
721 
722 
723 /* Turn a parsed path into an object representation. */
724 AFW_DEFINE(const afw_object_t *)
726  const afw_object_path_parsed_t *parsed,
727  const afw_pool_t *p,
728  afw_xctx_t *xctx)
729 {
730  const afw_object_t *result;
731  const afw_list_t *list;
732  const afw_value_t *value;
734 
735  result = afw_object_create_managed(p, xctx);
736 
737  if (parsed->original_path.len > 0) {
739  &afw_s_originalPath, &parsed->original_path, xctx);
740  }
741 
742  if (parsed->normalized_path.len > 0) {
744  &afw_s_normalizedPath, &parsed->normalized_path, xctx);
745  }
746 
747  if (parsed->entity_path.len > 0) {
749  &afw_s_entityPath, &parsed->entity_path, xctx);
750  }
751 
752  if (parsed->adaptor_id.len > 0) {
754  &afw_s_adaptorId, &parsed->adaptor_id, xctx);
755  }
756 
757  if (parsed->object_type_id.len > 0) {
759  &afw_s_objectType, &parsed->object_type_id, xctx);
760  }
761 
762  if (parsed->entity_object_id.len > 0) {
764  &afw_s_entityObjectId, &parsed->entity_object_id, xctx);
765  }
766 
767  if (parsed->undecoded_object_id.len > 0) {
769  &afw_s_objectId, &parsed->undecoded_object_id, xctx);
770  }
771 
772  if (parsed->first_property_name) {
773  list = afw_list_of_create(
774  afw_data_type_string, p, xctx);
775  for (name = parsed->first_property_name; name; name = name->next) {
776  value = afw_value_create_string(&name->property_name,
777  p, xctx);
778  afw_list_add_value(list, value, xctx);
779  }
781  &afw_s_propertyTypes, list, xctx);
782  }
783 
784  if (parsed->options_object) {
786  &afw_s_optionsObject, parsed->options_object, xctx);
787  }
788 
789  if (parsed->substitution_occurred) {
791  &afw_s_substitutionOccurred, afw_value_true, xctx);
792  }
793 
794  if (parsed->substituted_adaptor_id) {
796  &afw_s_substitutedAdaptorId, afw_value_true, xctx);
797  }
798 
799  if (parsed->substituted_object_type_id) {
801  &afw_s_substitutedObjectTypeId, afw_value_true, xctx);
802  }
803 
804  if (parsed->substituted_entire_object_id) {
806  &afw_s_substitutedEntireObjectId, afw_value_true, xctx);
807  }
808 
809  if (parsed->substituted_entity_object_id) {
811  &afw_s_substitutedEntityObjectId, afw_value_true, xctx);
812  }
813 
814  if (parsed->substituted_property_name) {
816  &afw_s_substitutedPropertyName, afw_value_true, xctx);
817  }
818 
819  if (parsed->contains_unresolved_substitutions) {
821  &afw_s_containsUnresolvedSubstitutions, afw_value_true, xctx);
822  }
823 
824  return result;}
825 
826 
827 /* Determine if two parsed paths are equivalent. */
830  const afw_object_path_parsed_t *parsed1,
831  const afw_object_path_parsed_t *parsed2,
832  afw_xctx_t *xctx)
833 {
836 
837  if (parsed1->adaptor_id.len != parsed2->adaptor_id.len ||
838  (parsed1->adaptor_id.len != 0 &&
839  !afw_utf8_equal(&parsed1->adaptor_id, &parsed2->adaptor_id)))
840  {
841  goto not_equal;
842  }
843 
844  if (parsed1->object_type_id.len != parsed2->object_type_id.len ||
845  (parsed1->object_type_id.len != 0 &&
846  !afw_utf8_equal(&parsed1->object_type_id, &parsed2->object_type_id)))
847  {
848  goto not_equal;
849  }
850 
851  if (parsed1->entity_object_id.len != parsed2->entity_object_id.len ||
852  (parsed1->entity_object_id.len != 0 &&
854  &parsed1->entity_object_id, &parsed2->entity_object_id)))
855  {
856  goto not_equal;
857  }
858 
859  for (
860  name1 = parsed1->first_property_name,
861  name2 = parsed1->first_property_name;
862  ;
863  name1 = name1->next,
864  name2 = name2->next
865  )
866  {
867  if (!name1) {
868  if (name2) goto not_equal;
869  break;
870  }
871 
872  if (!name2) goto not_equal;
873 
874  if (!afw_utf8_equal(&name1->property_name, &name2->property_name)) {
875  goto not_equal;
876  }
877  }
878 
879  return true;
880 
881 not_equal:
882  return false;
883 }
884 
885 
886 /* Determine if two paths are equivalent. */
889  const afw_utf8_t *path1,
890  const afw_utf8_t *path2,
891  const afw_utf8_t *current_path,
892  const afw_pool_t *p,
893  afw_xctx_t *xctx)
894 {
895  const afw_object_path_parsed_t *parsed1;
896  const afw_object_path_parsed_t *parsed2;
897 
898  parsed1 = afw_object_path_parse(path1, current_path, NULL, p, xctx);
899  parsed2 = afw_object_path_parse(path2, current_path, NULL, p, xctx);
900  return afw_object_path_parsed_are_equivalent(parsed1, parsed2, xctx);
901 }
902 
903 
904 /* Construct an object path. */
905 AFW_DEFINE(const afw_utf8_t *)
907  const afw_utf8_t *adaptor_id,
908  const afw_utf8_t *object_type_id,
909  const afw_utf8_t *object_id,
910  const afw_pool_t *p,
911  afw_xctx_t *xctx)
912 {
913  const afw_utf8_t *path;
914 
915  /* URL encode each parameter if they are on asterisk. */
916  if (!afw_utf8_equal(adaptor_id, &afw_s_a_asterisk)) {
917  adaptor_id = afw_uri_encode(adaptor_id,
918  AFW_URI_OCTET_UNRESERVED, p, xctx);
919  }
920 
921  if (!afw_utf8_equal(object_type_id, &afw_s_a_asterisk)) {
922  object_type_id = afw_uri_encode(object_type_id,
923  AFW_URI_OCTET_UNRESERVED, p, xctx);
924  }
925 
926  if (object_id) {
927  if (!afw_utf8_equal(object_id, &afw_s_a_asterisk)) {
928  object_id = afw_uri_encode(object_id,
929  AFW_URI_OCTET_UNRESERVED, p, xctx);
930  }
931  path = afw_utf8_concat(p, xctx,
932  &afw_s_a_slash, adaptor_id,
933  &afw_s_a_slash, object_type_id,
934  &afw_s_a_slash, object_id,
935  NULL);
936  }
937  else {
938  path = afw_utf8_concat(p, xctx,
939  &afw_s_a_slash, adaptor_id,
940  &afw_s_a_slash, object_type_id,
941  NULL);
942  }
943 
944  return path;
945 
946 }
947 
948 
949 /* Construct the path for an embedded object. */
950 AFW_DEFINE(const afw_utf8_t *)
952  const afw_object_t *embedded_object,
953  const afw_pool_t *p,
954  afw_xctx_t *xctx)
955 {
956  const afw_object_t *object;
957  afw_size_t len;
958  const afw_utf8_t *entity_path;
959  const afw_utf8_octet_t *s;
960  afw_utf8_octet_t *c;
961  const afw_utf8_t *encoded;
962 
963  /* Determine length of embedded path. If not entity path, return NULL. */
964  for (len = 0, object = embedded_object;
965  object->meta.embedding_object;
966  object = object->meta.embedding_object)
967  {
968  len += afw_uri_encode_len(object->meta.id,
969  AFW_URI_OCTET_UNRESERVED, xctx) + 1;
970  }
971  entity_path = afw_object_meta_get_path(object, xctx);
972  if (!entity_path) {
973  return NULL;
974  }
975  len += entity_path->len;
976 
977  /* Construct embedded path. */
978  s = c = afw_pool_malloc(p, len, xctx);
979  memcpy(c, entity_path->s, entity_path->len);
980  c += len;
981  for (object = embedded_object;
982  object->meta.embedding_object;
983  object = object->meta.embedding_object)
984  {
985  encoded = afw_uri_encode(object->meta.id,
986  AFW_URI_OCTET_UNRESERVED, p, xctx);
987  c -= encoded->len;
988  memcpy(c, encoded->s, encoded->len);
989  c--;
990  *c = '/';
991  }
992 
993  /* Return embedded path. */
994  return afw_utf8_create(s, len, p, xctx);
995 }
996 
997 
998 
999 /* Construct a property name expression from property name list. */
1000 AFW_DEFINE(const afw_utf8_t *)
1003  const afw_pool_t *p,
1004  afw_xctx_t *xctx)
1005 {
1006  afw_utf8_octet_t *s;
1007  afw_size_t len;
1009  afw_utf8_t *result;
1010 
1012  for (len = 0, entry = first; entry; entry = entry->next) {
1013  len += entry->property_name.len + 1;
1014  }
1015  len--;
1016 
1017  result = afw_pool_malloc_type(p, afw_utf8_t, xctx);
1018  result->s = s = afw_pool_malloc(p, len, xctx);
1019  result->len = len;
1020 
1021  memcpy(s, first->property_name.s, first->property_name.len);
1022  s += first->property_name.len;
1023 
1024  for (entry = first->next; entry; entry = entry->next) {
1025  *s++ = '/';
1026  memcpy(s, entry->property_name.s, entry->property_name.len);
1027  s += entry->property_name.len;
1028  }
1029 
1030  return result;
1031 }
AFW_DEFINE(const afw_object_t *)
Adaptive Framework Core Internal.
afw_object_set_property_as_list(const afw_object_t *object, const afw_utf8_t *property_name, const afw_list_t *internal, afw_xctx_t *xctx)
Set property function for data type list values.
afw_object_set_property_as_object(const afw_object_t *object, const afw_utf8_t *property_name, const afw_object_t *internal, afw_xctx_t *xctx)
Set property function for data type object values.
afw_value_create_string(const afw_utf8_t *internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type string value.
afw_data_type_string
Data type struct for string.
afw_object_set_property_as_string(const afw_object_t *object, const afw_utf8_t *property_name, const afw_utf8_t *internal, afw_xctx_t *xctx)
Set property function for data type string values.
#define AFW_UTF8_FMT_ARG(A_STRING)
Convenience Macro for use with AFW_UTF8_FMT to specify arg.
Definition: afw_common.h:605
_Bool afw_boolean_t
Definition: afw_common.h:373
#define AFW_UTF8_FMT
Format string specifier used for afw_utf8_t.
Definition: afw_common.h:588
char afw_utf8_octet_t
8 bits of utf-8 codepoint.
Definition: afw_common.h:236
apr_size_t afw_size_t
size_t.
Definition: afw_common.h:151
unsigned char afw_octet_t
8 bits (unsigned).
Definition: afw_common.h:211
#define AFW_THROW_ERROR_FZ(code, xctx, format_z,...)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:319
#define AFW_THROW_ERROR_Z(code, message_z, xctx)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:283
afw_list_add_value(const afw_list_t *instance, const afw_value_t *value, afw_xctx_t *xctx)
Call method add_value of interface afw_list_setter.
Definition: afw_list.c:104
#define afw_list_of_create(data_type, p, xctx)
Create an list of a specific data type in memory.
Definition: afw_list.h:64
void * afw_memory_dup(const void *from, apr_size_t size, const afw_pool_t *p, afw_xctx_t *xctx)
Duplicate a block of memory into specified pool.
Definition: afw_memory.h:88
#define afw_memory_copy(to, from)
Copy to preallocated memory of same type.
Definition: afw_memory.h:39
#define afw_object_get_property(instance, property_name, xctx)
Call method get_property of interface afw_object.
afw_object_meta_get_path(const afw_object_t *instance, afw_xctx_t *xctx)
Get an object's path.
afw_object_options_set_from_object(const afw_object_options_t *initial_options, const afw_object_t *options_object, const afw_pool_t *p, afw_xctx_t *xctx)
Set object processing options from options object.
afw_object_path_property_name_list_get_property(const afw_object_t *object, const afw_object_path_property_name_entry_t *first_property_name, afw_xctx_t *xctx)
Get object property value using property names.
afw_object_path_parse(const afw_utf8_t *path, const afw_utf8_t *current_path, const afw_object_options_t *default_options, const afw_pool_t *p, afw_xctx_t *xctx)
Parse an object value path in specific pool.
afw_object_path_parsed_to_object(const afw_object_path_parsed_t *parsed, const afw_pool_t *p, afw_xctx_t *xctx)
Turn a parsed path into an object representation.
afw_object_path_make_property_name_expression(const afw_object_path_property_name_entry_t *first, const afw_pool_t *p, afw_xctx_t *xctx)
Construct a property name expression from property name list.
afw_object_path_make_for_embedded(const afw_object_t *embedded_object, const afw_pool_t *p, afw_xctx_t *xctx)
Construct the path for an embedded object.
afw_object_path_are_equivalent(const afw_utf8_t *path1, const afw_utf8_t *path2, const afw_utf8_t *current_path, const afw_pool_t *p, afw_xctx_t *xctx)
Determine if two paths are equivalent.
afw_object_path_make(const afw_utf8_t *adaptor_id, const afw_utf8_t *object_type_id, const afw_utf8_t *object_id, const afw_pool_t *p, afw_xctx_t *xctx)
Construct an object path in a specified pool.
afw_object_path_parsed_are_equivalent(const afw_object_path_parsed_t *parsed1, const afw_object_path_parsed_t *parsed2, afw_xctx_t *xctx)
Determine if two parsed paths are equivalent.
afw_object_path_parse_simple(const afw_utf8_t *path, const afw_utf8_t **adaptor_id, const afw_utf8_t **object_type_id, const afw_utf8_t **object_id, const afw_pool_t *p, afw_xctx_t *xctx)
Parse simple path into ids.
#define afw_object_create_managed(p, xctx)
Create an empty entity object in its own pool.
Definition: afw_object.h:913
#define afw_object_create(p, xctx)
Create an empty unmanaged object in memory.
Definition: afw_object.h:948
afw_object_set_property(const afw_object_t *instance, const afw_utf8_t *property_name, const afw_value_t *value, afw_xctx_t *xctx)
Set the value of an object's property.
Definition: afw_object.c:46
#define afw_pool_malloc(instance, size, xctx)
Call method malloc of interface afw_pool.
#define afw_pool_calloc_type(instance, type, xctx)
Macro to allocate cleared memory to hold type in pool.
Definition: afw_pool.h:167
#define afw_pool_malloc_type(instance, type, xctx)
Macro to allocate uncleared memory to hold type in pool.
Definition: afw_pool.h:182
afw_uri_parse_next_token(const afw_uri_parser_t *parser, afw_xctx_t *xctx)
Parse next token.
Definition: afw_uri.c:1175
afw_uri_decode_create(const afw_utf8_octet_t *s, afw_size_t len, const afw_pool_t *p, afw_xctx_t *xctx)
Create a URI decoded string.
Definition: afw_uri.c:1023
afw_uri_parser_initialize(afw_uri_parser_t *parser, const afw_utf8_t *uri, const afw_pool_t *p, afw_xctx_t *xctx)
Initialize a parser in specific pool.
Definition: afw_uri.c:1146
afw_size_t afw_uri_encode_len(const afw_utf8_t *string, afw_uri_octet_type_t mask, afw_xctx_t *xctx)
The length needed to URI encode a string.
Definition: afw_uri.c:762
afw_uri_encode(const afw_utf8_t *string, afw_uri_octet_type_t mask, const afw_pool_t *p, afw_xctx_t *xctx)
URI encode a string.
Definition: afw_uri.c:814
afw_uri_encode_to_preallocated(afw_utf8_octet_t *s, afw_size_t s_len, const afw_utf8_t *string, afw_uri_octet_type_t mask, const afw_pool_t *p, afw_xctx_t *xctx)
URI encode a string using supplied afw_utf8_t.
Definition: afw_uri.c:925
const afw_utf8_t * afw_utf8_concat(const afw_pool_t *p, afw_xctx_t *xctx,...)
Concatenate strings with result in specifed pool.
afw_boolean_t afw_utf8_equal(const afw_utf8_t *s1, const afw_utf8_t *s2)
Check to see if a string equals another string.
afw_boolean_t afw_utf8_starts_with(const afw_utf8_t *string, const afw_utf8_t *starts_with)
Check to see if a string starts with another string.
#define afw_utf8_create(s, len, p, xctx)
Create utf-8 string without copy unless necessary in pool specified.
Definition: afw_utf8.h:239
afw_value_true
Adaptive value true.
Definition: afw_value.h:348
Interface afw_list public struct.
const afw_utf8_t * id
Object id or property name.
Definition: afw_common.h:782
Struct for object processing options.
Typedef for parsed object path.
Property name path struct.
Interface afw_object public struct.
Interface afw_pool public struct.
URI parser typedef.
Definition: afw_uri.h:197
NFC normalized UTF-8 string.
Definition: afw_common.h:545
Interface afw_value public struct.
Interface afw_xctx public struct.