iks * iks_prepend_cdata (iks *x, const char *data, size_t len) { iks *y; if (!x || !data) return NULL; if (len == 0) len = strlen (data); y = iks_new_within (NULL, x->s); if (!y) return NULL; y->type = IKS_CDATA; IKS_CDATA_CDATA(y) = iks_stack_strdup (x->s, data, len); if (!IKS_CDATA_CDATA (y)) return NULL; IKS_CDATA_LEN (y) = len; if (x->prev) { x->prev->next = y; } else { IKS_TAG_CHILDREN (x->parent) = y; } y->prev = x->prev; x->prev = y; y->parent = x->parent; y->next = x; return y; }
iks * iks_insert_attrib (iks *x, const char *name, const char *value) { iks *y; if (!x) return NULL; y = IKS_TAG_ATTRIBS (x); while (y) { if (strcmp (name, IKS_ATTRIB_NAME (y)) == 0) break; y = y->next; } if (NULL == y) { if (!value) return NULL; y = iks_stack_alloc (x->s, sizeof (struct iks_attrib)); if (!y) return NULL; memset (y, 0, sizeof (struct iks_attrib)); y->type = IKS_ATTRIBUTE; y->s = x->s; IKS_ATTRIB_NAME (y) = iks_stack_strdup (x->s, name, 0); if (!IKS_ATTRIB_NAME (y)) return NULL; y->parent = x; if (!IKS_TAG_ATTRIBS (x)) IKS_TAG_ATTRIBS (x) = y; if (IKS_TAG_LAST_ATTRIB (x)) { IKS_TAG_LAST_ATTRIB (x)->next = y; y->prev = IKS_TAG_LAST_ATTRIB (x); } IKS_TAG_LAST_ATTRIB (x) = y; } if (value) { IKS_ATTRIB_VALUE (y) = iks_stack_strdup (x->s, value, 0); if (!IKS_ATTRIB_VALUE (y)) return NULL; } else { if (y->next) y->next->prev = y->prev; if (y->prev) y->prev->next = y->next; if (IKS_TAG_ATTRIBS (x) == y) IKS_TAG_ATTRIBS (x) = y->next; if (IKS_TAG_LAST_ATTRIB (x) == y) IKS_TAG_LAST_ATTRIB (x) = y->prev; } return y; }
iksid * iks_id_new (ikstack *s, const char *jid) { iksid *id; char *src, *tmp; /* FIXME: add jabber id validity checks to this function */ /* which characters are allowed in id parts? */ if (!jid) return NULL; id = iks_stack_alloc (s, sizeof (iksid)); if (!id) return NULL; memset (id, 0, sizeof (iksid)); /* skip scheme */ if (strncmp ("jabber:", jid, 7) == 0) jid += 7; id->full = iks_stack_strdup (s, jid, 0); src = id->full; /* split resource */ tmp = strchr (src, '/'); if (tmp) { id->partial = iks_stack_strdup (s, src, tmp - src); id->resource = tmp + 1; src = id->partial; } else { id->partial = src; } /* split user */ tmp = strchr (src, '@'); if (tmp) { id->user = iks_stack_strdup (s, src, tmp - src); src = ++tmp; } id->server = src; return id; }
char * iks_stack_strcat (ikstack *s, char *old, size_t old_len, const char *src, size_t src_len) { char *ret; ikschunk *c; if (!old) { return iks_stack_strdup (s, src, src_len); } if (0 == old_len) old_len = strlen (old); if (0 == src_len) src_len = strlen (src); for (c = s->data; c; c = c->next) { if (c->data + c->last == old) break; } if (!c) { c = find_space (s, s->data, old_len + src_len + 1); if (!c) return NULL; ret = c->data + c->used; c->last = c->used; c->used += old_len + src_len + 1; memcpy (ret, old, old_len); memcpy (ret + old_len, src, src_len); ret[old_len + src_len] = '\0'; return ret; } if (c->size - c->used > src_len) { ret = c->data + c->last; memcpy (ret + old_len, src, src_len); c->used += src_len; ret[old_len + src_len] = '\0'; } else { /* FIXME: decrease c->used before moving string to new place */ c = find_space (s, s->data, old_len + src_len + 1); if (!c) return NULL; c->last = c->used; ret = c->data + c->used; memcpy (ret, old, old_len); c->used += old_len; memcpy (c->data + c->used, src, src_len); c->used += src_len; c->data[c->used] = '\0'; c->used++; } return ret; }
iks * iks_new_within (const char *name, ikstack *s) { iks *x; size_t len; if (name) len = sizeof (struct iks_tag); else len = sizeof (struct iks_cdata); x = iks_stack_alloc (s, len); if (!x) return NULL; memset (x, 0, len); x->s = s; x->type = IKS_TAG; if (name) { IKS_TAG_NAME (x) = iks_stack_strdup (s, name, 0); if (!IKS_TAG_NAME (x)) return NULL; } return x; }
iks * iks_insert_cdata (iks *x, const char *data, size_t len) { iks *y; if(!x || !data) return NULL; if(len == 0) len = strlen (data); y = IKS_TAG_LAST_CHILD (x); if (y && y->type == IKS_CDATA) { IKS_CDATA_CDATA (y) = iks_stack_strcat (x->s, IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y), data, len); IKS_CDATA_LEN (y) += len; } else { y = iks_insert (x, NULL); if (!y) return NULL; y->type = IKS_CDATA; IKS_CDATA_CDATA (y) = iks_stack_strdup (x->s, data, len); if (!IKS_CDATA_CDATA (y)) return NULL; IKS_CDATA_LEN (y) = len; } return y; }
void * Stack::strdupStack( Stack *stack, const string src, size_t len ) { return iks_stack_strdup( stack->stack, src.c_str(), len ); }
// Note that "s" may be NULL, in which case strings are not allocated // from the stack, and in which case the caller is responsible for // freeing any returned string. char * iks_string (ikstack *s, iks *x) { size_t size; int level, dir; iks *y, *z; char *ret, *t; if (!x) return NULL; if (x->type == IKS_CDATA) { if (s) { return iks_stack_strdup (s, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x)); } else { ret = iks_malloc (IKS_CDATA_LEN (x)); memcpy (ret, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x)); return ret; } } size = 0; level = 0; dir = 0; y = x; while (1) { if (dir==0) { if (y->type == IKS_TAG) { size++; size += strlen (IKS_TAG_NAME (y)); for (z = IKS_TAG_ATTRIBS (y); z; z = z->next) { size += 4 + strlen (IKS_ATTRIB_NAME (z)) + escape_size (IKS_ATTRIB_VALUE (z), strlen (IKS_ATTRIB_VALUE (z))); } if (IKS_TAG_CHILDREN (y)) { size++; y = IKS_TAG_CHILDREN (y); level++; continue; } else { size += 2; } } else { size += escape_size (IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y)); } } z = y->next; if (z) { if (0 == level) { if (IKS_TAG_CHILDREN (y)) size += 3 + strlen (IKS_TAG_NAME (y)); break; } y = z; dir = 0; } else { y = y->parent; level--; if (level >= 0) size += 3 + strlen (IKS_TAG_NAME (y)); if (level < 1) break; dir = 1; } } if (s) ret = iks_stack_alloc (s, size + 1); else ret = iks_malloc (size + 1); if (!ret) return NULL; t = ret; level = 0; dir = 0; while (1) { if (dir==0) { if (x->type == IKS_TAG) { *t++ = '<'; t = my_strcat (t, IKS_TAG_NAME (x), 0); y = IKS_TAG_ATTRIBS (x); while (y) { *t++ = ' '; t = my_strcat (t, IKS_ATTRIB_NAME (y), 0); *t++ = '='; *t++ = '\''; t = escape (t, IKS_ATTRIB_VALUE (y), strlen (IKS_ATTRIB_VALUE (y))); *t++ = '\''; y = y->next; } if (IKS_TAG_CHILDREN (x)) { *t++ = '>'; x = IKS_TAG_CHILDREN (x); level++; continue; } else { *t++ = '/'; *t++ = '>'; } } else { t = escape (t, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x)); } } y = x->next; if (y) { if (0 == level) { if (IKS_TAG_CHILDREN (x)) { *t++ = '<'; *t++ = '/'; t = my_strcat (t, IKS_TAG_NAME (x), 0); *t++ = '>'; } break; } x = y; dir = 0; } else { x = x->parent; level--; if (level >= 0) { *t++ = '<'; *t++ = '/'; t = my_strcat (t, IKS_TAG_NAME (x), 0); *t++ = '>'; } if (level < 1) break; dir = 1; } } *t = '\0'; return ret; }