2 * Copyright (c) 2007-2013 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
29 #include <mach/kern_return.h>
30 #include <mach/mach_init.h>
31 #include <mach/mach_vm.h>
32 #include <mach/vm_map.h>
33 #include <mach/vm_param.h>
34 #include <libkern/OSAtomic.h>
35 #include <asl_string.h>
36 #include <asl_private.h>
38 #define ASL_STRING_QUANTUM 256
39 static const char *cvis_7_13
= "abtnvfr";
42 asl_string_new(uint32_t encoding
)
44 asl_string_t
*str
= (asl_string_t
*)calloc(1, sizeof(asl_string_t
));
45 if (str
== NULL
) return NULL
;
47 str
->asl_type
= ASL_TYPE_STRING
;
50 str
->encoding
= encoding
;
51 str
->delta
= ASL_STRING_QUANTUM
;
52 if (encoding
& ASL_STRING_VM
) str
->delta
= PAGE_SIZE
;
56 if (encoding
& ASL_STRING_LEN
) asl_string_append_no_encoding(str
, " 0 ");
61 asl_string_retain(asl_string_t
*str
)
63 if (str
== NULL
) return NULL
;
65 OSAtomicIncrement32Barrier(&(str
->refcount
));
70 asl_string_release(asl_string_t
*str
)
72 if (str
== NULL
) return;
73 if (OSAtomicDecrement32Barrier(&(str
->refcount
)) != 0) return;
75 if (str
->encoding
& ASL_STRING_VM
)
77 vm_deallocate(mach_task_self(), (vm_address_t
)str
->buf
, str
->bufsize
);
88 asl_string_release_return_bytes(asl_string_t
*str
)
91 if (str
== NULL
) return NULL
;
93 if (OSAtomicDecrement32Barrier(&(str
->refcount
)) != 0)
95 /* string is still retained - copy buf */
96 if (str
->encoding
& ASL_STRING_VM
)
98 if (str
->bufsize
== 0) return NULL
;
100 vm_address_t
new = 0;
101 kern_return_t kstatus
= vm_allocate(mach_task_self(), &new, str
->bufsize
, TRUE
);
102 if (kstatus
!= KERN_SUCCESS
) return NULL
;
104 memcpy((void *)new, str
->buf
, str
->bufsize
);
109 if (str
->cursor
== 0) return NULL
;
110 return strdup(str
->buf
);
120 asl_string_bytes(asl_string_t
*str
)
122 if (str
== NULL
) return NULL
;
126 /* length includes trailing nul */
128 asl_string_length(asl_string_t
*str
)
130 if (str
== NULL
) return 0;
131 if (str
->cursor
== 0) return 0;
133 return str
->cursor
+ 1;
137 asl_string_allocated_size(asl_string_t
*str
)
139 if (str
== NULL
) return 0;
144 _asl_string_grow(asl_string_t
*str
, size_t len
)
148 if (str
== NULL
) return -1;
149 if (len
== 0) return 0;
151 if (str
->bufsize
== 0)
153 newlen
= ((len
+ str
->delta
- 1) / str
->delta
) * str
->delta
;
157 /* used size is (str->cursor + 1) including tailiing nul */
158 if (len
<= (str
->bufsize
- (str
->cursor
+ 1))) return 0;
160 /* really this is ((str->cursor + 1) + len + (str->delta - 1)) */
161 newlen
= ((str
->cursor
+ len
+ str
->delta
) / str
->delta
) * str
->delta
;
164 if (str
->encoding
& ASL_STRING_VM
)
166 kern_return_t kstatus
;
167 vm_address_t
new = 0;
169 kstatus
= vm_allocate(mach_task_self(), &new, newlen
, TRUE
);
170 if (kstatus
!= KERN_SUCCESS
)
177 if (str
->buf
!= NULL
)
179 memcpy((void *)new, str
->buf
, str
->bufsize
);
180 vm_deallocate(mach_task_self(), (vm_address_t
)str
->buf
, str
->bufsize
);
183 str
->buf
= (char *)new;
184 str
->bufsize
= newlen
;
188 str
->buf
= reallocf(str
->buf
, newlen
);
189 if (str
->buf
== NULL
)
196 str
->bufsize
= newlen
;
203 asl_string_append_char_no_encoding(asl_string_t
*str
, const char c
)
207 if (str
== NULL
) return NULL
;
210 if (str
->bufsize
== 0) len
++;
212 if (_asl_string_grow(str
, len
) < 0) return str
;
214 str
->buf
[str
->cursor
] = c
;
216 str
->buf
[str
->cursor
] = '\0';
218 if (str
->encoding
& ASL_STRING_LEN
)
221 snprintf(tmp
, sizeof(tmp
), "%10lu", str
->cursor
- 10);
222 memcpy(str
->buf
, tmp
, 10);
229 asl_string_append_no_encoding(asl_string_t
*str
, const char *app
)
233 if (str
== NULL
) return NULL
;
234 if (app
== NULL
) return str
;
236 applen
= strlen(app
);
238 if (str
->bufsize
== 0) len
++;
240 if (_asl_string_grow(str
, len
) < 0) return str
;
242 memcpy(str
->buf
+ str
->cursor
, app
, applen
);
244 str
->cursor
+= applen
;
245 str
->buf
[str
->cursor
] = '\0';
247 if (str
->encoding
& ASL_STRING_LEN
)
250 snprintf(tmp
, sizeof(tmp
), "%10lu", str
->cursor
- 10);
251 memcpy(str
->buf
, tmp
, 10);
257 static asl_string_t
*
258 asl_string_append_internal(asl_string_t
*str
, const char *app
, int encode_space
)
263 if (str
== NULL
) return NULL
;
264 if (app
== NULL
) return str
;
266 switch (str
->encoding
& ASL_ENCODE_MASK
)
268 case ASL_ENCODE_NONE
:
270 return asl_string_append_no_encoding(str
, app
);
272 case ASL_ENCODE_SAFE
:
274 /* minor encoding to reduce the likelyhood of spoof attacks */
277 for (p
= app
; *p
!= '\0'; p
++)
279 if ((*p
== 10) || (*p
== 13))
281 asl_string_append_no_encoding(str
, "\n\t");
285 asl_string_append_no_encoding(str
, "^H");
289 asl_string_append_char_no_encoding(str
, *p
);
297 for (p
= app
; *p
!= '\0'; p
++)
303 /* Meta chars get \M prefix */
306 /* except meta-space, which is \240 */
309 asl_string_append_no_encoding(str
, "\\240");
313 asl_string_append_no_encoding(str
, "\\M");
318 /* space is either ' ' or \s */
321 if (encode_space
== 0)
323 asl_string_append_char_no_encoding(str
, ' ');
327 asl_string_append_no_encoding(str
, "\\s");
332 if ((meta
== 0) && (x
== 92))
334 asl_string_append_no_encoding(str
, "\\\\");
338 /* [ and ] are escaped in ASL encoding */
339 if ((str
->encoding
& ASL_ENCODE_ASL
) && (meta
== 0) && ((*p
== 91) || (*p
== 93)))
341 if (*p
== '[') asl_string_append_no_encoding(str
, "\\[");
342 else asl_string_append_no_encoding(str
, "\\]");
351 asl_string_append_char_no_encoding(str
, '\\');
354 asl_string_append_no_encoding(str
, "^?");
358 /* 33-126 are printable (add a '-' prefix for meta) */
359 if ((x
>= 33) && (x
<= 126))
363 asl_string_append_char_no_encoding(str
, '-');
366 asl_string_append_char_no_encoding(str
, x
);
370 /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
371 if ((meta
== 0) && (x
>= 7) && (x
<= 13))
373 asl_string_append_char_no_encoding(str
, '\\');
374 asl_string_append_char_no_encoding(str
, cvis_7_13
[x
- 7]);
378 /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */
383 asl_string_append_char_no_encoding(str
, '\\');
386 asl_string_append_char_no_encoding(str
, '^');
387 asl_string_append_char_no_encoding(str
, 64 + x
);
391 asl_string_append_char_no_encoding(str
, x
);
398 for (p
= app
; *p
!= '\0'; p
++)
404 asl_string_append_no_encoding(str
, "&");
408 asl_string_append_no_encoding(str
, "<");
412 asl_string_append_no_encoding(str
, ">");
416 asl_string_append_no_encoding(str
, """);
420 asl_string_append_no_encoding(str
, "'");
425 snprintf(tmp
, sizeof(tmp
), "&#x%02hhx;", x
);
426 asl_string_append_no_encoding(str
, tmp
);
430 asl_string_append_char_no_encoding(str
, x
);
444 asl_string_append(asl_string_t
*str
, const char *app
)
446 return asl_string_append_internal(str
, app
, 0);
450 asl_string_append_asl_key(asl_string_t
*str
, const char *app
)
452 return asl_string_append_internal(str
, app
, 1);
456 asl_string_append_op(asl_string_t
*str
, uint32_t op
)
461 if (str
== NULL
) return NULL
;
463 if (op
== ASL_QUERY_OP_NULL
)
465 return asl_string_append_char_no_encoding(str
, '.');
469 if (op
& ASL_QUERY_OP_CASEFOLD
) opstr
[i
++] = 'C';
471 if (op
& ASL_QUERY_OP_REGEX
) opstr
[i
++] = 'R';
473 if (op
& ASL_QUERY_OP_NUMERIC
) opstr
[i
++] = 'N';
475 if (op
& ASL_QUERY_OP_PREFIX
)
477 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'S';
478 else opstr
[i
++] = 'A';
480 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'Z';
482 switch (op
& ASL_QUERY_OP_TRUE
)
484 case ASL_QUERY_OP_EQUAL
:
487 case ASL_QUERY_OP_GREATER
:
490 case ASL_QUERY_OP_GREATER_EQUAL
:
494 case ASL_QUERY_OP_LESS
:
497 case ASL_QUERY_OP_LESS_EQUAL
:
501 case ASL_QUERY_OP_NOT_EQUAL
:
504 case ASL_QUERY_OP_TRUE
:
513 return asl_string_append_char_no_encoding(str
, '.');
517 return asl_string_append_no_encoding(str
, opstr
);
521 asl_string_append_xml_tag(asl_string_t
*str
, const char *tag
, const char *s
)
523 asl_string_append_no_encoding(str
, "\t\t<");
524 asl_string_append_no_encoding(str
, tag
);
525 asl_string_append_no_encoding(str
, ">");
526 asl_string_append_internal(str
, s
, 0);
527 asl_string_append_no_encoding(str
, "</");
528 asl_string_append_no_encoding(str
, tag
);
529 asl_string_append_no_encoding(str
, ">\n");