/* * Copyright (c) 2008 - 2009 * Jonathan Schleifer <js@webkeks.org> * * All rights reserved. * * This file is part of libobjfw. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE included in * the packaging of this file. */ #import "config.h" #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <limits.h> #import "OFXMLFactory.h" #import "OFExceptions.h" #import "OFMacros.h" /* * We don't use OFString in this file for performance reasons! * * We already have a clue about how big the resulting string will get, so we * can prealloc and only resize when really necessary - OFString would always * resize when we append, which would be slow here. */ static inline void resize(char **str, size_t *len, size_t add, Class class) { char *str2; size_t len2; if (add > SIZE_MAX - *len) @throw [OFOutOfRangeException newWithClass: class]; len2 = *len + add; if ((str2 = realloc(*str, len2)) == NULL) { if (*str) free(*str); *str = NULL; @throw [OFNoMemException newWithClass: class andSize: len2]; } *str = str2; *len = len2; } static inline void append(char **str, size_t *len, size_t *pos, const char *add, Class class) { size_t add_len; add_len = strlen(add); resize(str, len, add_len, class); memcpy(*str + *pos, add, add_len); *pos += add_len; } @implementation OFXMLFactory + (char*)escapeCString: (const char*)s { char *ret; size_t i, len; len = strlen(s); if (SIZE_MAX - len < 1) @throw [OFOutOfRangeException newWithClass: self]; len++; if ((ret = malloc(len)) == NULL) @throw [OFNoMemException newWithClass: self andSize: len]; @try { for (i = 0; *s; s++) { switch (*s) { case '<': append(&ret, &len, &i, "<", self); break; case '>': append(&ret, &len, &i, ">", self); break; case '"': append(&ret, &len, &i, """, self); break; case '\'': append(&ret, &len, &i, "'", self); break; case '&': append(&ret, &len, &i, "&", self); break; default: ret[i++] = *s; break; } } } @catch (OFException *e) { free(ret); @throw e; } ret[i] = 0; return ret; } + (char*)createStanza: (const char*)name, ... { char *ret; va_list attrs; va_start(attrs, name); ret = [self createStanza: name withCloseTag: YES andAttributes: attrs andData: NULL]; va_end(attrs); return ret; } + (char*)createStanza: (const char*)name withData: (const char*)data, ... { char *ret; va_list attrs; va_start(attrs, data); ret = [self createStanza: name withCloseTag: YES andAttributes: attrs andData: data]; va_end(attrs); return ret; } + (char*)createStanza: (const char*)name withCloseTag: (BOOL)close andData: (const char*)data, ... { char *ret; va_list attrs; va_start(attrs, data); ret = [self createStanza: name withCloseTag: close andAttributes: attrs andData: data]; va_end(attrs); return ret; } + (char*)createStanza: (const char*)name withCloseTag: (BOOL)close andAttributes: (va_list)attrs andData: (const char*)data { char *arg, *val, *xml, *esc_val = NULL; size_t i, len; /* Start of tag */ len = strlen(name); if (SIZE_MAX - len < 3) @throw [OFOutOfRangeException newWithClass: self]; len += 3; if ((xml = malloc(len)) == NULL) @throw [OFNoMemException newWithClass: self andSize: len]; i = 0; xml[i++] = '<'; memcpy(xml + i, name, strlen(name)); i += strlen(name); @try { while ((arg = va_arg(attrs, char*)) != NULL && (val = va_arg(attrs, char*)) != NULL) { esc_val = NULL; /* Needed for our @catch */ esc_val = [self escapeCString: val]; resize(&xml, &len, 1 + strlen(arg) + 2 + strlen(esc_val) + 1, self); xml[i++] = ' '; memcpy(xml + i, arg, strlen(arg)); i += strlen(arg); xml[i++] = '='; xml[i++] = '\''; memcpy(xml + i, esc_val, strlen(esc_val)); i += strlen(esc_val); xml[i++] = '\''; free(esc_val); } /* End of tag */ if (close) { if (data == NULL) { resize(&xml, &len, 2 - 1, self); xml[i++] = '/'; xml[i++] = '>'; } else { resize(&xml, &len, 1 + strlen(data) + 2 + strlen(name) + 1 - 1, self); xml[i++] = '>'; memcpy(xml + i, data, strlen(data)); i += strlen(data); xml[i++] = '<'; xml[i++] = '/'; memcpy(xml + i, name, strlen(name)); i += strlen(name); xml[i++] = '>'; } } else xml[i++] = '>'; } @catch (OFException *e) { if (esc_val != NULL) free(esc_val); free(xml); @throw e; } xml[i] = 0; return xml; } + (char*)concatAndFreeCStrings: (char**)strs { char *ret; size_t i, len, pos; if (strs[0] == NULL) return NULL; len = strlen(*strs); if (SIZE_MAX - len < 1) @throw [OFOutOfRangeException newWithClass: self]; len++; if ((ret = malloc(len)) == NULL) @throw [OFNoMemException newWithClass: self andSize: len]; memcpy(ret, strs[0], len - 1); pos = len - 1; @try { for (i = 1; strs[i] != NULL; i++) append(&ret, &len, &pos, strs[i], self); for (i = 0; strs[i] != NULL; i++) free(strs[i]); } @catch (OFException *e) { free(ret); @throw e; } ret[pos] = 0; return ret; } @end