1 /*	$NetBSD: string.c,v 1.2 2017/01/28 21:31:45 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  *
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * 3. Neither the name of the Institute nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #include "baselocl.h"
39 #include <string.h>
40 
41 static void
string_dealloc(void * ptr)42 string_dealloc(void *ptr)
43 {
44     heim_string_t s = ptr;
45     heim_string_free_f_t *deallocp;
46     heim_string_free_f_t dealloc;
47 
48     if (*(const char *)ptr != '\0')
49 	return;
50 
51     /* Possible string ref */
52     deallocp = _heim_get_isaextra(s, 0);
53     dealloc = *deallocp;
54     if (dealloc != NULL) {
55 	char **strp = _heim_get_isaextra(s, 1);
56 	dealloc(*strp);
57     }
58 }
59 
60 static int
string_cmp(void * a,void * b)61 string_cmp(void *a, void *b)
62 {
63     if (*(char *)a == '\0') {
64 	char **strp = _heim_get_isaextra(a, 1);
65 
66 	if (*strp != NULL)
67 	    a = *strp; /* a is a string ref */
68     }
69     if (*(char *)b == '\0') {
70 	char **strp = _heim_get_isaextra(b, 1);
71 
72 	if (*strp != NULL)
73 	    b = *strp; /* b is a string ref */
74     }
75     return strcmp(a, b);
76 }
77 
78 static unsigned long
string_hash(void * ptr)79 string_hash(void *ptr)
80 {
81     const char *s = ptr;
82     unsigned long n;
83 
84     for (n = 0; *s; ++s)
85 	n += *s;
86     return n;
87 }
88 
89 struct heim_type_data _heim_string_object = {
90     HEIM_TID_STRING,
91     "string-object",
92     NULL,
93     string_dealloc,
94     NULL,
95     string_cmp,
96     string_hash,
97     NULL
98 };
99 
100 /**
101  * Create a string object
102  *
103  * @param string the string to create, must be an utf8 string
104  *
105  * @return string object
106  */
107 
108 heim_string_t
heim_string_create(const char * string)109 heim_string_create(const char *string)
110 {
111     return heim_string_create_with_bytes(string, strlen(string));
112 }
113 
114 /**
115  * Create a string object without copying the source.
116  *
117  * @param string the string to referenced, must be UTF-8
118  * @param dealloc the function to use to release the referece to the string
119  *
120  * @return string object
121  */
122 
123 heim_string_t
heim_string_ref_create(const char * string,heim_string_free_f_t dealloc)124 heim_string_ref_create(const char *string, heim_string_free_f_t dealloc)
125 {
126     heim_string_t s;
127     heim_string_free_f_t *deallocp;
128 
129     s = _heim_alloc_object(&_heim_string_object, 1);
130     if (s) {
131 	const char **strp;
132 
133 	((char *)s)[0] = '\0';
134 	deallocp = _heim_get_isaextra(s, 0);
135 	*deallocp = dealloc;
136 	strp = _heim_get_isaextra(s, 1);
137 	*strp = string;
138     }
139     return s;
140 }
141 
142 /**
143  * Create a string object
144  *
145  * @param string the string to create, must be an utf8 string
146  * @param len the length of the string
147  *
148  * @return string object
149  */
150 
151 heim_string_t
heim_string_create_with_bytes(const void * data,size_t len)152 heim_string_create_with_bytes(const void *data, size_t len)
153 {
154     heim_string_t s;
155 
156     s = _heim_alloc_object(&_heim_string_object, len + 1);
157     if (s) {
158 	memcpy(s, data, len);
159 	((char *)s)[len] = '\0';
160     }
161     return s;
162 }
163 
164 /**
165  * Create a string object using a format string
166  *
167  * @param fmt format string
168  * @param ...
169  *
170  * @return string object
171  */
172 
173 heim_string_t
heim_string_create_with_format(const char * fmt,...)174 heim_string_create_with_format(const char *fmt, ...)
175 {
176     heim_string_t s;
177     char *str = NULL;
178     va_list ap;
179     int ret;
180 
181     va_start(ap, fmt);
182     ret = vasprintf(&str, fmt, ap);
183     va_end(ap);
184     if (ret < 0 || str == NULL)
185 	return NULL;
186 
187     s = heim_string_ref_create(str, string_dealloc);
188     if (s == NULL)
189 	free(str);
190     return s;
191 }
192 
193 /**
194  * Return the type ID of string objects
195  *
196  * @return type id of string objects
197  */
198 
199 heim_tid_t
heim_string_get_type_id(void)200 heim_string_get_type_id(void)
201 {
202     return HEIM_TID_STRING;
203 }
204 
205 /**
206  * Get the string value of the content.
207  *
208  * @param string the string object to get the value from
209  *
210  * @return a utf8 string
211  */
212 
213 const char *
heim_string_get_utf8(heim_string_t string)214 heim_string_get_utf8(heim_string_t string)
215 {
216     if (*(const char *)string == '\0') {
217 	const char **strp;
218 
219 	/* String ref */
220 	strp = _heim_get_isaextra(string, 1);
221 	if (*strp != NULL)
222 	    return *strp;
223     }
224     return (const char *)string;
225 }
226 
227 /*
228  *
229  */
230 
231 static void
init_string(void * ptr)232 init_string(void *ptr)
233 {
234     heim_dict_t *dict = ptr;
235     *dict = heim_dict_create(101);
236     heim_assert(*dict != NULL, "__heim_string_constant");
237 }
238 
239 heim_string_t
__heim_string_constant(const char * _str)240 __heim_string_constant(const char *_str)
241 {
242     static HEIMDAL_MUTEX mutex = HEIMDAL_MUTEX_INITIALIZER;
243     static heim_base_once_t once;
244     static heim_dict_t dict = NULL;
245     heim_string_t s, s2;
246 
247     heim_base_once_f(&once, &dict, init_string);
248     s = heim_string_create(_str);
249 
250     HEIMDAL_MUTEX_lock(&mutex);
251     s2 = heim_dict_get_value(dict, s);
252     if (s2) {
253 	heim_release(s);
254 	s = s2;
255     } else {
256 	_heim_make_permanent(s);
257 	heim_dict_set_value(dict, s, s);
258     }
259     HEIMDAL_MUTEX_unlock(&mutex);
260 
261     return s;
262 }
263