1 /*!
2  * \addtogroup UpnpString
3  *
4  * Due to its heavy use, this class is coded for efficiency, not for beauty.
5  * Do not use this as example to other classes. Please take a look at any
6  * other one.
7  *
8  * \todo Always alloc a minimum size like 64 bytes or so and when shrinking
9  * do not perform a new memory allocation.
10  *
11  * @{
12  *
13  * \file
14  *
15  * \brief UpnpString object implementation.
16  */
17 
18 #include "config.h"
19 
20 #include "UpnpString.h"
21 
22 #include <stdlib.h> /* for calloc(), free() */
23 #include <string.h> /* for strlen(), strdup() */
24 
25 #ifdef _WIN32
26 	#define strcasecmp stricmp
27 #else
28 	/* Other systems have strncasecmp */
29 #endif
30 
31 #ifndef UPNP_USE_MSVCPP
32 	#ifdef UPNP_USE_BCBPP
strnlen(const char * s,size_t n)33 		static size_t strnlen(const char *s, size_t n) { return strnlen_s(s, n); }
34 	#else
35 		/* VC has strnlen which is already included but with (potentially) different linkage */
36 		/* strnlen() is a GNU extension. */
37 		#if !HAVE_STRNLEN
strnlen(const char * s,size_t n)38 			static size_t strnlen(const char *s, size_t n)
39 			{
40 				const char *p = (const char *)memchr(s, 0, n);
41 				return p ? p - s : n;
42 			}
43 		#endif /* !HAVE_STRNLEN */
44 	#endif /* UPNP_USE_BCBPP */
45 #endif /* _WIN32 */
46 
47 /* strndup() is a GNU extension. */
48 #if !HAVE_STRNDUP || defined(_WIN32)
strndup(const char * __string,size_t __n)49 	static char *strndup(const char *__string, size_t __n)
50 	{
51 		size_t strsize = strnlen(__string, __n);
52 		char *newstr = (char *)malloc(strsize + 1);
53 		if (newstr == NULL)
54 			return NULL;
55 
56 		strncpy(newstr, __string, strsize);
57 		newstr[strsize] = 0;
58 
59 		return newstr;
60 	}
61 #endif /* HAVE_STRNDUP && !defined(_WIN32) */
62 
63 /*!
64  * \brief Internal implementation of the class UpnpString.
65  *
66  * \internal
67  */
68 struct SUpnpString
69 {
70 	/*! \brief Length of the string. */
71 	size_t m_length;
72 	/*! \brief Pointer to a dynamically allocated area that holds the NULL
73 	 * terminated string. */
74 	char *m_string;
75 };
76 
UpnpString_new()77 UpnpString *UpnpString_new()
78 {
79 	/* All bytes are zero, and so is the length of the string. */
80 	struct SUpnpString *p = calloc((size_t)1, sizeof (struct SUpnpString));
81 	if (p == NULL) {
82 		goto error_handler1;
83 	}
84 #if 0
85 	p->m_length = 0;
86 #endif
87 
88 	/* This byte is zero, calloc does initialize it. */
89 	p->m_string = calloc((size_t)1, (size_t)1);
90 	if (p->m_string == NULL) {
91 		goto error_handler2;
92 	}
93 
94 	return (UpnpString *)p;
95 
96 	/*free(p->m_string); */
97 error_handler2:
98 	free(p);
99 error_handler1:
100 	return NULL;
101 }
102 
UpnpString_delete(UpnpString * p)103 void UpnpString_delete(UpnpString *p)
104 {
105 	struct SUpnpString *q = (struct SUpnpString *)p;
106 
107 	if (!q) return;
108 
109 	q->m_length = (size_t)0;
110 
111 	free(q->m_string);
112 	q->m_string = NULL;
113 
114 	free(p);
115 }
116 
UpnpString_dup(const UpnpString * p)117 UpnpString *UpnpString_dup(const UpnpString *p)
118 {
119 	struct SUpnpString *q = calloc((size_t)1, sizeof (struct SUpnpString));
120 	if (q == NULL) {
121 		goto error_handler1;
122 	}
123 	q->m_length = ((struct SUpnpString *)p)->m_length;
124 	q->m_string = strdup(((struct SUpnpString *)p)->m_string);
125 	if (q->m_string == NULL) {
126 		goto error_handler2;
127 	}
128 
129 	return (UpnpString *)q;
130 
131 	/*free(q->m_string); */
132 error_handler2:
133 	free(q);
134 error_handler1:
135 	return NULL;
136 }
137 
UpnpString_assign(UpnpString * p,const UpnpString * q)138 void UpnpString_assign(UpnpString *p, const UpnpString *q)
139 {
140 	if (p != q) {
141 		UpnpString_set_String(p, UpnpString_get_String(q));
142 	}
143 }
144 
UpnpString_get_Length(const UpnpString * p)145 size_t UpnpString_get_Length(const UpnpString *p)
146 {
147 	return ((struct SUpnpString *)p)->m_length;
148 }
149 
UpnpString_set_Length(UpnpString * p,size_t n)150 void UpnpString_set_Length(UpnpString *p, size_t n)
151 {
152 	if (((struct SUpnpString *)p)->m_length > n) {
153 		((struct SUpnpString *)p)->m_length = n;
154 		/* No need to realloc now, will do later when needed. */
155 		((struct SUpnpString *)p)->m_string[n] = 0;
156 	}
157 }
158 
UpnpString_get_String(const UpnpString * p)159 const char *UpnpString_get_String(const UpnpString *p)
160 {
161 	return ((struct SUpnpString *)p)->m_string;
162 }
163 
UpnpString_set_String(UpnpString * p,const char * s)164 int UpnpString_set_String(UpnpString *p, const char *s)
165 {
166 	char *q = strdup(s);
167 	if (!q) goto error_handler1;
168 	free(((struct SUpnpString *)p)->m_string);
169 	((struct SUpnpString *)p)->m_length = strlen(q);
170 	((struct SUpnpString *)p)->m_string = q;
171 
172 error_handler1:
173 	return q != NULL;
174 }
175 
UpnpString_set_StringN(UpnpString * p,const char * s,size_t n)176 int UpnpString_set_StringN(UpnpString *p, const char *s, size_t n)
177 {
178 	char *q = strndup(s, n);
179 	if (!q) goto error_handler1;
180 	free(((struct SUpnpString *)p)->m_string);
181 	((struct SUpnpString *)p)->m_length = strlen(q);
182 	((struct SUpnpString *)p)->m_string = q;
183 
184 error_handler1:
185 	return q != NULL;
186 }
187 
UpnpString_clear(UpnpString * p)188 void UpnpString_clear(UpnpString *p)
189 {
190 	((struct SUpnpString *)p)->m_length = (size_t)0;
191 	/* No need to realloc now, will do later when needed. */
192 	((struct SUpnpString *)p)->m_string[0] = 0;
193 }
194 
UpnpString_cmp(UpnpString * p,UpnpString * q)195 int UpnpString_cmp(UpnpString *p, UpnpString *q)
196 {
197 	const char *cp = UpnpString_get_String(p);
198 	const char *cq = UpnpString_get_String(q);
199 
200 	return strcmp(cp, cq);
201 }
202 
UpnpString_casecmp(UpnpString * p,UpnpString * q)203 int UpnpString_casecmp(UpnpString *p, UpnpString *q)
204 {
205 	const char *cp = UpnpString_get_String(p);
206 	const char *cq = UpnpString_get_String(q);
207 
208 	return strcasecmp(cp, cq);
209 }
210 
211 /* @} UpnpString */
212