2 * Copyright (c) 2007-2015 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_t
*asl_string_append_no_encoding_len(asl_string_t
*str
, const char *app
, size_t copylen
);
45 asl_string_new(uint32_t encoding
)
47 asl_string_t
*str
= (asl_string_t
*)calloc(1, sizeof(asl_string_t
));
48 if (str
== NULL
) return NULL
;
50 str
->asl_type
= ASL_TYPE_STRING
;
53 str
->encoding
= encoding
;
54 str
->delta
= ASL_STRING_QUANTUM
;
55 if (encoding
& ASL_STRING_VM
) str
->delta
= PAGE_SIZE
;
59 if (encoding
& ASL_STRING_LEN
) asl_string_append_no_encoding_len(str
, " 0 ", 11);
64 asl_string_retain(asl_string_t
*str
)
66 if (str
== NULL
) return NULL
;
68 OSAtomicIncrement32Barrier(&(str
->refcount
));
73 asl_string_release(asl_string_t
*str
)
75 if (str
== NULL
) return;
76 if (OSAtomicDecrement32Barrier(&(str
->refcount
)) != 0) return;
78 if (str
->encoding
& ASL_STRING_VM
)
80 vm_deallocate(mach_task_self(), (vm_address_t
)str
->buf
, str
->bufsize
);
91 asl_string_release_return_bytes(asl_string_t
*str
)
94 if (str
== NULL
) return NULL
;
96 if (str
->encoding
& ASL_STRING_LEN
)
99 snprintf(tmp
, sizeof(tmp
), "%10lu", str
->cursor
- 10);
100 memcpy(str
->buf
, tmp
, 10);
103 if (OSAtomicDecrement32Barrier(&(str
->refcount
)) != 0)
105 /* string is still retained - copy buf */
106 if (str
->encoding
& ASL_STRING_VM
)
108 if (str
->bufsize
== 0) return NULL
;
110 vm_address_t
new = 0;
111 kern_return_t kstatus
= vm_allocate(mach_task_self(), &new, str
->bufsize
, VM_FLAGS_ANYWHERE
| VM_MAKE_TAG(VM_MEMORY_ASL
));
112 if (kstatus
!= KERN_SUCCESS
) return NULL
;
114 memcpy((void *)new, str
->buf
, str
->bufsize
);
119 if (str
->cursor
== 0) return NULL
;
120 return strdup(str
->buf
);
130 asl_string_bytes(asl_string_t
*str
)
132 if (str
== NULL
) return NULL
;
134 if (str
->encoding
& ASL_STRING_LEN
)
137 snprintf(tmp
, sizeof(tmp
), "%10lu", str
->cursor
- 10);
138 memcpy(str
->buf
, tmp
, 10);
144 /* length includes trailing nul */
146 asl_string_length(asl_string_t
*str
)
148 if (str
== NULL
) return 0;
149 if (str
->cursor
== 0) return 0;
151 return str
->cursor
+ 1;
155 asl_string_allocated_size(asl_string_t
*str
)
157 if (str
== NULL
) return 0;
162 _asl_string_grow(asl_string_t
*str
, size_t len
)
166 if (str
== NULL
) return -1;
167 if (len
== 0) return 0;
169 if (str
->bufsize
== 0)
171 newlen
= ((len
+ str
->delta
- 1) / str
->delta
) * str
->delta
;
175 /* used size is (str->cursor + 1) including tailiing nul */
176 if (len
<= (str
->bufsize
- (str
->cursor
+ 1))) return 0;
178 /* really this is ((str->cursor + 1) + len + (str->delta - 1)) */
179 newlen
= ((str
->cursor
+ len
+ str
->delta
) / str
->delta
) * str
->delta
;
182 if (str
->encoding
& ASL_STRING_VM
)
184 kern_return_t kstatus
;
185 vm_address_t
new = 0;
187 kstatus
= vm_allocate(mach_task_self(), &new, newlen
, VM_FLAGS_ANYWHERE
| VM_MAKE_TAG(VM_MEMORY_ASL
));
188 if (kstatus
!= KERN_SUCCESS
)
195 if (str
->buf
!= NULL
)
197 memcpy((void *)new, str
->buf
, str
->bufsize
);
198 vm_deallocate(mach_task_self(), (vm_address_t
)str
->buf
, str
->bufsize
);
201 str
->buf
= (char *)new;
202 str
->bufsize
= newlen
;
206 str
->buf
= reallocf(str
->buf
, newlen
);
207 if (str
->buf
== NULL
)
214 str
->bufsize
= newlen
;
221 asl_string_append_char_no_encoding(asl_string_t
*str
, const char c
)
225 if (str
== NULL
) return NULL
;
228 if (str
->bufsize
== 0) len
++;
229 if (_asl_string_grow(str
, len
) < 0) return str
;
231 str
->buf
[str
->cursor
] = c
;
233 str
->buf
[str
->cursor
] = '\0';
239 asl_string_append_no_encoding_len(asl_string_t
*str
, const char *app
, size_t copylen
)
243 if (str
== NULL
) return NULL
;
244 if (app
== NULL
) return str
;
247 if (applen
== 0) applen
= strlen(app
);
250 if (str
->bufsize
== 0) len
++;
252 if (_asl_string_grow(str
, len
) < 0) return str
;
254 memcpy(str
->buf
+ str
->cursor
, app
, applen
);
256 str
->cursor
+= applen
;
257 str
->buf
[str
->cursor
] = '\0';
263 asl_string_append_no_encoding(asl_string_t
*str
, const char *app
)
265 return asl_string_append_no_encoding_len(str
, app
, 0);
268 static asl_string_t
*
269 asl_string_append_internal(asl_string_t
*str
, const char *app
, int encode_space
)
272 const uint8_t *s
, *p
;
275 if (str
== NULL
) return NULL
;
276 if (app
== NULL
) return str
;
278 switch (str
->encoding
& ASL_ENCODE_MASK
)
280 case ASL_ENCODE_NONE
:
282 return asl_string_append_no_encoding_len(str
, app
, 0);
284 case ASL_ENCODE_SAFE
:
286 /* minor encoding to reduce the likelyhood of spoof attacks */
292 for (p
= app
; *p
!= '\0'; p
++)
298 if (x
!= 0) y
= p
[1];
299 if (y
!= 0) z
= p
[2];
301 if ((x
== 10) || (x
== 13))
305 asl_string_append_no_encoding_len(str
, s
, copylen
);
310 asl_string_append_no_encoding_len(str
, "\n\t", 2);
316 asl_string_append_no_encoding_len(str
, s
, copylen
);
321 asl_string_append_no_encoding_len(str
, "^H", 2);
323 else if ((x
== 0xc2) && (y
== 0x85))
327 /* next line - format like newline */
330 asl_string_append_no_encoding_len(str
, s
, copylen
);
335 asl_string_append_no_encoding_len(str
, "\n\t", 2);
337 else if ((x
== 0xe2) && (y
== 0x80) && ((z
== 0xa8) || (z
== 0xa9)))
341 /* line separator or paragraph separator - format like newline */
344 asl_string_append_no_encoding_len(str
, s
, copylen
);
349 asl_string_append_no_encoding_len(str
, "\n\t", 2);
353 if (s
== NULL
) s
= p
;
358 if (copylen
> 0) asl_string_append_no_encoding_len(str
, s
, copylen
);
367 for (p
= app
; *p
!= '\0'; p
++)
373 /* Meta chars get \M prefix */
376 /* except meta-space, which is \240 */
381 asl_string_append_no_encoding_len(str
, s
, copylen
);
386 asl_string_append_no_encoding_len(str
, "\\240", 4);
392 asl_string_append_no_encoding_len(str
, s
, copylen
);
397 asl_string_append_no_encoding_len(str
, "\\M", 2);
402 /* space is either ' ' or \s */
405 if (encode_space
== 0)
407 if (s
== NULL
) s
= p
;
414 asl_string_append_no_encoding_len(str
, s
, copylen
);
419 asl_string_append_no_encoding_len(str
, "\\s", 2);
424 if ((meta
== 0) && (x
== 92))
428 asl_string_append_no_encoding_len(str
, s
, copylen
);
433 asl_string_append_no_encoding_len(str
, "\\\\", 2);
437 /* [ and ] are escaped in ASL encoding */
438 if ((str
->encoding
& ASL_ENCODE_ASL
) && (meta
== 0) && ((*p
== 91) || (*p
== 93)))
442 asl_string_append_no_encoding_len(str
, s
, copylen
);
447 if (*p
== '[') asl_string_append_no_encoding_len(str
, "\\[", 2);
448 else asl_string_append_no_encoding_len(str
, "\\]", 2);
459 asl_string_append_no_encoding_len(str
, s
, copylen
);
464 asl_string_append_char_no_encoding(str
, '\\');
469 asl_string_append_no_encoding_len(str
, s
, copylen
);
474 asl_string_append_no_encoding_len(str
, "^?", 2);
478 /* 33-126 are printable (add a '-' prefix for meta) */
479 if ((x
>= 33) && (x
<= 126))
485 asl_string_append_no_encoding_len(str
, s
, copylen
);
490 asl_string_append_char_no_encoding(str
, '-');
491 asl_string_append_char_no_encoding(str
, x
);
495 if (s
== NULL
) s
= p
;
501 /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
502 if ((meta
== 0) && (x
>= 7) && (x
<= 13))
506 asl_string_append_no_encoding_len(str
, s
, copylen
);
511 asl_string_append_char_no_encoding(str
, '\\');
512 asl_string_append_char_no_encoding(str
, cvis_7_13
[x
- 7]);
516 /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */
523 asl_string_append_no_encoding_len(str
, s
, copylen
);
528 asl_string_append_char_no_encoding(str
, '\\');
533 asl_string_append_no_encoding_len(str
, s
, copylen
);
538 asl_string_append_char_no_encoding(str
, '^');
539 asl_string_append_char_no_encoding(str
, 64 + x
);
543 if (s
== NULL
) s
= p
;
549 asl_string_append_no_encoding_len(str
, s
, copylen
);
561 for (p
= app
; *p
!= '\0'; p
++)
569 asl_string_append_no_encoding_len(str
, s
, copylen
);
574 asl_string_append_no_encoding_len(str
, "&", 5);
580 asl_string_append_no_encoding_len(str
, s
, copylen
);
585 asl_string_append_no_encoding_len(str
, "<", 4);
591 asl_string_append_no_encoding_len(str
, s
, copylen
);
596 asl_string_append_no_encoding_len(str
, ">", 4);
602 asl_string_append_no_encoding_len(str
, s
, copylen
);
607 asl_string_append_no_encoding_len(str
, """, 6);
613 asl_string_append_no_encoding_len(str
, s
, copylen
);
618 asl_string_append_no_encoding_len(str
, "'", 6);
624 asl_string_append_no_encoding_len(str
, s
, copylen
);
630 snprintf(tmp
, sizeof(tmp
), "&#x%02hhx;", x
);
631 asl_string_append_no_encoding_len(str
, tmp
, 6);
635 if (s
== NULL
) s
= p
;
642 asl_string_append_no_encoding_len(str
, s
, copylen
);
659 asl_string_append(asl_string_t
*str
, const char *app
)
661 return asl_string_append_internal(str
, app
, 0);
665 asl_string_append_asl_key(asl_string_t
*str
, const char *app
)
667 return asl_string_append_internal(str
, app
, 1);
671 asl_string_append_op(asl_string_t
*str
, uint32_t op
)
676 if (str
== NULL
) return NULL
;
678 if (op
== ASL_QUERY_OP_NULL
)
680 return asl_string_append_char_no_encoding(str
, '.');
684 if (op
& ASL_QUERY_OP_CASEFOLD
) opstr
[i
++] = 'C';
686 if (op
& ASL_QUERY_OP_REGEX
) opstr
[i
++] = 'R';
688 if (op
& ASL_QUERY_OP_NUMERIC
) opstr
[i
++] = 'N';
690 if (op
& ASL_QUERY_OP_PREFIX
)
692 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'S';
693 else opstr
[i
++] = 'A';
695 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'Z';
697 switch (op
& ASL_QUERY_OP_TRUE
)
699 case ASL_QUERY_OP_EQUAL
:
702 case ASL_QUERY_OP_GREATER
:
705 case ASL_QUERY_OP_GREATER_EQUAL
:
709 case ASL_QUERY_OP_LESS
:
712 case ASL_QUERY_OP_LESS_EQUAL
:
716 case ASL_QUERY_OP_NOT_EQUAL
:
719 case ASL_QUERY_OP_TRUE
:
728 return asl_string_append_char_no_encoding(str
, '.');
732 return asl_string_append_no_encoding_len(str
, opstr
, 0);
736 asl_string_append_xml_tag(asl_string_t
*str
, const char *tag
, const char *s
)
738 asl_string_append_no_encoding_len(str
, "\t\t<", 3);
739 asl_string_append_no_encoding_len(str
, tag
, 0);
740 asl_string_append_char_no_encoding(str
, '>');
741 asl_string_append_internal(str
, s
, 0);
742 asl_string_append_no_encoding_len(str
, "</", 2);
743 asl_string_append_no_encoding_len(str
, tag
, 0);
744 asl_string_append_no_encoding_len(str
, ">\n", 2);