mirror of
https://github.com/darlinghq/darling-libxml2.git
synced 2025-02-01 07:51:55 +00:00
fixing some nodeinfo in entities problem raised by Glenn W. Bach
* parser.c: fixing some nodeinfo in entities problem raised by Glenn W. Bach * relaxng.c: implemented the first section 7.3 check * result/relaxng/*: updated the results Daniel
This commit is contained in:
parent
c5312d7c76
commit
44e1dd0027
@ -1,3 +1,10 @@
|
||||
Sat Feb 22 00:19:48 CET 2003 Daniel Veillard <daniel@veillard.com>
|
||||
|
||||
* parser.c: fixing some nodeinfo in entities problem raised
|
||||
by Glenn W. Bach
|
||||
* relaxng.c: implemented the first section 7.3 check
|
||||
* result/relaxng/*: updated the results
|
||||
|
||||
Fri Feb 21 18:12:19 CET 2003 Daniel Veillard <daniel@veillard.com>
|
||||
|
||||
* relaxng.c: fixed some problems in the previous commit
|
||||
|
13
parser.c
13
parser.c
@ -9685,6 +9685,10 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
|
||||
ctxt->loadsubset = oldctxt->loadsubset;
|
||||
ctxt->validate = oldctxt->validate;
|
||||
ctxt->external = oldctxt->external;
|
||||
ctxt->record_info = oldctxt->record_info;
|
||||
ctxt->node_seq.maximum = oldctxt->node_seq.maximum;
|
||||
ctxt->node_seq.length = oldctxt->node_seq.length;
|
||||
ctxt->node_seq.buffer = oldctxt->node_seq.buffer;
|
||||
} else {
|
||||
/*
|
||||
* Doing validity checking on chunk without context
|
||||
@ -9703,6 +9707,9 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
|
||||
}
|
||||
newDoc = xmlNewDoc(BAD_CAST "1.0");
|
||||
if (newDoc == NULL) {
|
||||
ctxt->node_seq.maximum = 0;
|
||||
ctxt->node_seq.length = 0;
|
||||
ctxt->node_seq.buffer = NULL;
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
return(-1);
|
||||
}
|
||||
@ -9717,6 +9724,9 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
|
||||
if (newDoc->children == NULL) {
|
||||
if (sax != NULL)
|
||||
ctxt->sax = oldsax;
|
||||
ctxt->node_seq.maximum = 0;
|
||||
ctxt->node_seq.length = 0;
|
||||
ctxt->node_seq.buffer = NULL;
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
newDoc->intSubset = NULL;
|
||||
newDoc->extSubset = NULL;
|
||||
@ -9809,6 +9819,9 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
|
||||
}
|
||||
if (sax != NULL)
|
||||
ctxt->sax = oldsax;
|
||||
ctxt->node_seq.maximum = 0;
|
||||
ctxt->node_seq.length = 0;
|
||||
ctxt->node_seq.buffer = NULL;
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
newDoc->intSubset = NULL;
|
||||
newDoc->extSubset = NULL;
|
||||
|
148
relaxng.c
148
relaxng.c
@ -234,6 +234,7 @@ typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
|
||||
struct _xmlRelaxNGInterleaveGroup {
|
||||
xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
|
||||
xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
|
||||
xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -592,6 +593,8 @@ xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
|
||||
if (group != NULL) {
|
||||
if (group->defs != NULL)
|
||||
xmlFree(group->defs);
|
||||
if (group->attrs != NULL)
|
||||
xmlFree(group->attrs);
|
||||
xmlFree(group);
|
||||
}
|
||||
}
|
||||
@ -2094,7 +2097,8 @@ xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
|
||||
/**
|
||||
* xmlRelaxNGGetElements:
|
||||
* @ctxt: a Relax-NG parser context
|
||||
* @def: the interleave definition
|
||||
* @def: the definition definition
|
||||
* @eora: gather elements (0) or attributes (1)
|
||||
*
|
||||
* Compute the list of top elements a definition can generate
|
||||
*
|
||||
@ -2102,16 +2106,25 @@ xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
|
||||
*/
|
||||
static xmlRelaxNGDefinePtr *
|
||||
xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
|
||||
xmlRelaxNGDefinePtr def) {
|
||||
xmlRelaxNGDefinePtr def,
|
||||
int eora) {
|
||||
xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
|
||||
int len = 0;
|
||||
int max = 0;
|
||||
|
||||
/*
|
||||
* Don't run that check in case of error. Infinite recursion
|
||||
* becomes possible.
|
||||
*/
|
||||
if (ctxt->nbErrors != 0)
|
||||
return(NULL);
|
||||
|
||||
parent = NULL;
|
||||
cur = def;
|
||||
while (cur != NULL) {
|
||||
if ((cur->type == XML_RELAXNG_ELEMENT) ||
|
||||
(cur->type == XML_RELAXNG_TEXT)) {
|
||||
if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
|
||||
(cur->type == XML_RELAXNG_TEXT))) ||
|
||||
((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
|
||||
if (ret == NULL) {
|
||||
max = 10;
|
||||
ret = (xmlRelaxNGDefinePtr *)
|
||||
@ -2160,7 +2173,7 @@ xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
|
||||
}
|
||||
}
|
||||
if (cur == def)
|
||||
return(ret);
|
||||
break;
|
||||
if (cur->next != NULL) {
|
||||
cur = cur->next;
|
||||
continue;
|
||||
@ -2178,11 +2191,93 @@ xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlRelaxNGCheckGroupAttrs:
|
||||
* @ctxt: a Relax-NG parser context
|
||||
* @def: the group definition
|
||||
*
|
||||
* Detects violations of rule 7.3
|
||||
*/
|
||||
static void
|
||||
xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
|
||||
xmlRelaxNGDefinePtr def) {
|
||||
xmlRelaxNGDefinePtr **list;
|
||||
xmlRelaxNGDefinePtr cur;
|
||||
int nbchild = 0, i, j, ret;
|
||||
|
||||
if ((def == NULL) ||
|
||||
((def->type != XML_RELAXNG_GROUP) &&
|
||||
(def->type != XML_RELAXNG_ELEMENT)))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Don't run that check in case of error. Infinite recursion
|
||||
* becomes possible.
|
||||
*/
|
||||
if (ctxt->nbErrors != 0)
|
||||
return;
|
||||
|
||||
cur = def->attrs;
|
||||
while (cur != NULL) {
|
||||
nbchild++;
|
||||
cur = cur->next;
|
||||
}
|
||||
cur = def->content;
|
||||
while (cur != NULL) {
|
||||
nbchild++;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
|
||||
sizeof(xmlRelaxNGDefinePtr *));
|
||||
if (list == NULL) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"Out of memory in group computation\n");
|
||||
ctxt->nbErrors++;
|
||||
return;
|
||||
}
|
||||
i = 0;
|
||||
cur = def->attrs;
|
||||
while (cur != NULL) {
|
||||
list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
|
||||
i++;
|
||||
cur = cur->next;
|
||||
}
|
||||
cur = def->content;
|
||||
while (cur != NULL) {
|
||||
list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
|
||||
i++;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
for (i = 0;i < nbchild;i++) {
|
||||
if (list[i] == NULL)
|
||||
continue;
|
||||
for (j = 0;j < i;j++) {
|
||||
if (list[j] == NULL)
|
||||
continue;
|
||||
ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
|
||||
if (ret == 0) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"Attributes conflicts in group\n");
|
||||
ctxt->nbErrors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0;i < nbchild;i++) {
|
||||
if (list[i] != NULL)
|
||||
xmlFree(list[i]);
|
||||
}
|
||||
xmlFree(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlRelaxNGComputeInterleaves:
|
||||
* @def: the interleave definition
|
||||
* @ctxt: a Relax-NG parser context
|
||||
* @node: the data node.
|
||||
* @name: the definition name
|
||||
*
|
||||
* A lot of work for preprocessing interleave definitions
|
||||
* is potentially needed to get a decent execution speed at runtime
|
||||
@ -2199,7 +2294,6 @@ xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
|
||||
xmlChar *name ATTRIBUTE_UNUSED) {
|
||||
xmlRelaxNGDefinePtr cur;
|
||||
|
||||
xmlRelaxNGDefinePtr *list = NULL;
|
||||
xmlRelaxNGPartitionPtr partitions = NULL;
|
||||
xmlRelaxNGInterleaveGroupPtr *groups = NULL;
|
||||
xmlRelaxNGInterleaveGroupPtr group;
|
||||
@ -2207,6 +2301,13 @@ xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
|
||||
int nbgroups = 0;
|
||||
int nbchild = 0;
|
||||
|
||||
/*
|
||||
* Don't run that check in case of error. Infinite recursion
|
||||
* becomes possible.
|
||||
*/
|
||||
if (ctxt->nbErrors != 0)
|
||||
return;
|
||||
|
||||
#ifdef DEBUG_INTERLEAVE
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlRelaxNGComputeInterleaves(%s)\n",
|
||||
@ -2232,11 +2333,11 @@ xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
|
||||
if (groups[nbgroups] == NULL)
|
||||
goto error;
|
||||
groups[nbgroups]->rule = cur;
|
||||
groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur);
|
||||
groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
|
||||
groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
|
||||
nbgroups++;
|
||||
cur = cur->next;
|
||||
}
|
||||
list = NULL;
|
||||
#ifdef DEBUG_INTERLEAVE
|
||||
xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
|
||||
#endif
|
||||
@ -2262,12 +2363,20 @@ xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
|
||||
"Element or text conflicts in interleave\n");
|
||||
ctxt->nbErrors++;
|
||||
}
|
||||
ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
|
||||
groups[j]->attrs);
|
||||
if (ret == 0) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"Attributes conflicts in interleave\n");
|
||||
ctxt->nbErrors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
partitions->groups = groups;
|
||||
|
||||
/*
|
||||
* Free Up the child list, and save the partition list back in the def
|
||||
* and save the partition list back in the def
|
||||
*/
|
||||
def->data = partitions;
|
||||
return;
|
||||
@ -2277,8 +2386,6 @@ error:
|
||||
ctxt->error(ctxt->userData,
|
||||
"Out of memory in interleave computation\n");
|
||||
ctxt->nbErrors++;
|
||||
if (list == NULL)
|
||||
xmlFree(list);
|
||||
if (groups != NULL) {
|
||||
for (i = 0;i < nbgroups;i++)
|
||||
if (groups[i] != NULL) {
|
||||
@ -4077,6 +4184,10 @@ xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
|
||||
ret = (xmlRelaxNGContentType) cur->depth + 15;
|
||||
}
|
||||
} else if (cur->type == XML_RELAXNG_ELEMENT) {
|
||||
/*
|
||||
* The 7.3 Attribute derivation rule for groups is plugged there
|
||||
*/
|
||||
xmlRelaxNGCheckGroupAttrs(ctxt, cur);
|
||||
if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
@ -4214,6 +4325,10 @@ xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
|
||||
else
|
||||
nflags = flags;
|
||||
ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
|
||||
/*
|
||||
* The 7.3 Attribute derivation rule for groups is plugged there
|
||||
*/
|
||||
xmlRelaxNGCheckGroupAttrs(ctxt, cur);
|
||||
} else if (cur->type == XML_RELAXNG_INTERLEAVE) {
|
||||
if (flags & XML_RELAXNG_IN_LIST) {
|
||||
if (ctxt->error != NULL)
|
||||
@ -4955,6 +5070,9 @@ xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
|
||||
xmlFree(name);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 4.16
|
||||
*/
|
||||
if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
|
||||
if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
|
||||
if (ctxt->error != NULL)
|
||||
@ -4967,6 +5085,9 @@ xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
|
||||
(cur != root)) {
|
||||
int oldflags = ctxt->flags;
|
||||
|
||||
/*
|
||||
* 4.16
|
||||
*/
|
||||
if ((cur->parent != NULL) &&
|
||||
(xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
|
||||
ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
|
||||
@ -4981,6 +5102,9 @@ xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
|
||||
goto skip_children;
|
||||
}
|
||||
} else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
|
||||
/*
|
||||
* 4.16
|
||||
*/
|
||||
if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
|
@ -1 +1 @@
|
||||
Unimplemented block at relaxng.c:6304
|
||||
Unimplemented block at relaxng.c:6428
|
||||
|
@ -1,4 +1,4 @@
|
||||
error detected at relaxng.c:6488
|
||||
error detected at relaxng.c:6612
|
||||
Expecting a namespace for element foo
|
||||
error detected at relaxng.c:7070
|
||||
error detected at relaxng.c:7194
|
||||
extra data on the document
|
||||
|
@ -1,4 +1,4 @@
|
||||
error detected at relaxng.c:6493
|
||||
error detected at relaxng.c:6617
|
||||
Expecting element foo has wrong namespace: expecting http://www.example.com
|
||||
error detected at relaxng.c:7070
|
||||
error detected at relaxng.c:7194
|
||||
extra data on the document
|
||||
|
@ -1,4 +1,4 @@
|
||||
error detected at relaxng.c:6493
|
||||
error detected at relaxng.c:6617
|
||||
Expecting element foo has wrong namespace: expecting http://www.example.com
|
||||
error detected at relaxng.c:7070
|
||||
error detected at relaxng.c:7194
|
||||
extra data on the document
|
||||
|
@ -1,4 +1,4 @@
|
||||
error detected at relaxng.c:6505
|
||||
error detected at relaxng.c:6629
|
||||
Expecting no namespace for element foo
|
||||
error detected at relaxng.c:7070
|
||||
error detected at relaxng.c:7194
|
||||
extra data on the document
|
||||
|
@ -1,4 +1,4 @@
|
||||
error detected at relaxng.c:6505
|
||||
error detected at relaxng.c:6629
|
||||
Expecting no namespace for element foo
|
||||
error detected at relaxng.c:7070
|
||||
error detected at relaxng.c:7194
|
||||
extra data on the document
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element addressBook: card
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element addressBook: card
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6712
|
||||
error detected at relaxng.c:6836
|
||||
Invalid attribute foo for element card
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6712
|
||||
error detected at relaxng.c:6836
|
||||
Invalid attribute b for element card
|
||||
|
@ -1 +1 @@
|
||||
Unimplemented block at relaxng.c:6304
|
||||
Unimplemented block at relaxng.c:6428
|
||||
|
@ -1,4 +1,4 @@
|
||||
error detected at relaxng.c:6480
|
||||
error detected at relaxng.c:6604
|
||||
Expecting element name, got email
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element card: email
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element addressBook: card
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:7070
|
||||
error detected at relaxng.c:7194
|
||||
extra data on the document
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6712
|
||||
error detected at relaxng.c:6836
|
||||
Invalid attribute preferredFormat for element card
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element preferredFormat: text
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6712
|
||||
error detected at relaxng.c:6836
|
||||
Invalid attribute preferredFormat for element card
|
||||
|
@ -1,6 +1,6 @@
|
||||
error detected at relaxng.c:5591
|
||||
error detected at relaxng.c:5715
|
||||
Internal: failed to validate type float
|
||||
error detected at relaxng.c:7002
|
||||
error detected at relaxng.c:7126
|
||||
error validating list
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element vector: text
|
||||
|
@ -1,6 +1,6 @@
|
||||
error detected at relaxng.c:5831
|
||||
error detected at relaxng.c:5955
|
||||
Extra data in list: 5.6
|
||||
error detected at relaxng.c:7002
|
||||
error detected at relaxng.c:7126
|
||||
error validating list
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element vector: text
|
||||
|
@ -1,4 +1,4 @@
|
||||
error detected at relaxng.c:5591
|
||||
error detected at relaxng.c:5715
|
||||
Internal: failed to validate type double
|
||||
error detected at relaxng.c:7002
|
||||
error detected at relaxng.c:7126
|
||||
error validating list
|
||||
|
@ -1,6 +1,6 @@
|
||||
error detected at relaxng.c:5831
|
||||
error detected at relaxng.c:5955
|
||||
Extra data in list: 5.6
|
||||
error detected at relaxng.c:7002
|
||||
error detected at relaxng.c:7126
|
||||
error validating list
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element path: text
|
||||
|
@ -1,6 +1,6 @@
|
||||
error detected at relaxng.c:5591
|
||||
error detected at relaxng.c:5715
|
||||
Internal: failed to validate type double
|
||||
error detected at relaxng.c:7002
|
||||
error detected at relaxng.c:7126
|
||||
error validating list
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element path: text
|
||||
|
@ -1,4 +1,4 @@
|
||||
Unimplemented block at relaxng.c:6304
|
||||
Unimplemented block at relaxng.c:6304
|
||||
error detected at relaxng.c:6699
|
||||
Unimplemented block at relaxng.c:6428
|
||||
Unimplemented block at relaxng.c:6428
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element head: meta
|
||||
|
@ -1,4 +1,4 @@
|
||||
error detected at relaxng.c:6640
|
||||
error detected at relaxng.c:6764
|
||||
Expecting an element, got empty
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element head: meta
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element head: base
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element addressBook: card
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element addressBook: card
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element addressBook: card
|
||||
|
@ -1,2 +1,2 @@
|
||||
error detected at relaxng.c:6699
|
||||
error detected at relaxng.c:6823
|
||||
Extra content for element addressBook: card
|
||||
|
Loading…
x
Reference in New Issue
Block a user