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 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 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 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 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 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 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 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 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 * 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 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 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