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 41static void 42string_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 60static int 61string_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 78static unsigned long 79string_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 89struct 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 108heim_string_t 109heim_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 123heim_string_t 124heim_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 151heim_string_t 152heim_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 173heim_string_t 174heim_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 199heim_tid_t 200heim_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 213const char * 214heim_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 231static void 232init_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 239heim_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