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