2 * Copyright (c) 2015 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <kern/kern_cdata.h>
30 #import <Foundation/Foundation.h>
32 #import "KCDBasicTypeDescription.h"
33 #import "KCDStructTypeDescription.h"
35 #define MAX_KCDATATYPE_BUFFER_SIZE 2048
36 extern struct kcdata_type_definition *kcdata_get_typedescription(unsigned type_id, uint8_t *buffer, uint32_t buffer_size);
40 * @function getTypeFromTypeDef
43 * Build a KCDataType from a type definition.
46 * A pointer to kcdata_type_definition_t that specifies the type fields and has subtype definitions
47 * in the memory immediately following the type_definition.
49 * @return KCDataType * type object which can be used to parse data into dictionaries.
50 * This may return nil if it finds the data to be invalid.
53 * This routine tries to decode the typeDef structure and create either a basic type (KCDBasicTypeDescription)
56 static KCDataType * getTypeFromTypeDef(struct kcdata_type_definition * typeDef);
59 getTypeFromTypeDef(struct kcdata_type_definition * typeDef)
61 if (typeDef == NULL) {
64 NSString * kct_name = [NSString stringWithFormat:@"%s", typeDef->kct_name];
65 if (typeDef->kct_num_elements == 1) {
66 KCDBasicTypeDescription * retval = [[KCDBasicTypeDescription alloc] initWithKCTypeDesc:&typeDef->kct_elements[0]];
69 KCDStructTypeDescription * retval =
70 [[KCDStructTypeDescription alloc] initWithType:typeDef->kct_type_identifier withName:kct_name];
71 /* need to do work here to get the array of elements setup here */
72 KCDBasicTypeDescription * curField = nil;
73 for (unsigned int i = 0; i < typeDef->kct_num_elements; i++) {
74 curField = [[KCDBasicTypeDescription alloc] initWithKCTypeDesc:&typeDef->kct_elements[i]];
75 [retval addFieldBasicType:curField];
83 getKCDataTypeForID(uint32_t typeID)
85 static dispatch_once_t onceToken;
86 static NSMutableDictionary * knownTypes = nil;
87 dispatch_once(&onceToken, ^{
89 knownTypes = [[NSMutableDictionary alloc] init];
92 NSNumber * type = [NSNumber numberWithUnsignedInt:typeID];
93 if (!knownTypes[type]) {
94 /* code to query system for type information */
95 uint8_t buffer[MAX_KCDATATYPE_BUFFER_SIZE];
96 struct kcdata_type_definition * sys_def = kcdata_get_typedescription(typeID, buffer, MAX_KCDATATYPE_BUFFER_SIZE);
97 if (sys_def == NULL) {
98 knownTypes[type] = [[KCDBasicTypeDescription alloc] createDefaultForType:typeID];
100 knownTypes[type] = getTypeFromTypeDef(sys_def);
103 assert(knownTypes[type] != nil);
104 return knownTypes[type];
108 KCDataTypeNameForID(uint32_t typeID)
110 NSString * retval = [NSString stringWithFormat:@"%u", typeID];
111 KCDataType * t = getKCDataTypeForID(typeID);
113 if (![[t name] containsString:@"Type_"]) {
119 NSMutableDictionary *
120 parseKCDataArray(void * dataBuffer)
122 uint32_t typeID = KCDATA_ITEM_ARRAY_GET_EL_TYPE(dataBuffer);
123 uint32_t count = KCDATA_ITEM_ARRAY_GET_EL_COUNT(dataBuffer);
124 uint32_t size = KCDATA_ITEM_ARRAY_GET_EL_SIZE(dataBuffer);
125 uint8_t * buffer = (uint8_t *)KCDATA_ITEM_DATA_PTR(dataBuffer);
126 KCDataType * datatype = getKCDataTypeForID(typeID);
127 NSMutableDictionary * retval = [[NSMutableDictionary alloc] initWithCapacity:1];
128 NSMutableArray * arr = [[NSMutableArray alloc] initWithCapacity:count];
129 retval[[datatype name]] = arr;
130 NSMutableDictionary * tmpdict = NULL;
131 for (uint32_t i = 0; i < count; i++) {
132 tmpdict = [datatype parseData:(void *)&buffer[i * size] ofLength:size];
133 [arr addObject:tmpdict];
138 NSMutableDictionary *
139 parseKCDataContainer(void * dataBuffer, uint32_t * bytesParsed)
141 if (bytesParsed == NULL)
143 assert(KCDATA_ITEM_TYPE(dataBuffer) == KCDATA_TYPE_CONTAINER_BEGIN);
144 uint64_t containerID = KCDATA_CONTAINER_ID(dataBuffer);
146 /* setup collection object for sub containers */
147 NSMutableDictionary * sub_containers = [[NSMutableDictionary alloc] init];
148 NSMutableDictionary * retval = [[NSMutableDictionary alloc] init];
149 NSMutableDictionary * container = [[NSMutableDictionary alloc] init];
150 struct kcdata_item * buffer = (struct kcdata_item *)KCDATA_ITEM_NEXT_HEADER(dataBuffer);
151 KCDataType * tmptype;
154 NSMutableDictionary * tmpdict;
155 retval[KCDataTypeNameForID(kcdata_get_container_type(dataBuffer))] = container;
157 KCDATA_ITEM_FOREACH(buffer)
159 _t = KCDATA_ITEM_TYPE(buffer);
160 _d = KCDATA_ITEM_DATA_PTR(buffer);
161 if (_t == KCDATA_TYPE_CONTAINER_END) {
162 if (KCDATA_CONTAINER_ID(buffer) == containerID) {
168 if (_t == KCDATA_TYPE_ARRAY) {
169 tmpdict = parseKCDataArray(buffer);
170 [container addEntriesFromDictionary:tmpdict];
174 if (_t == KCDATA_TYPE_CONTAINER_BEGIN) {
175 uint32_t container_size = 0;
176 tmpdict = parseKCDataContainer(buffer, &container_size);
177 NSString * subcontainerID = [NSString stringWithFormat:@"%llu", KCDATA_CONTAINER_ID(buffer)];
178 NSString * k_desc = nil;
179 assert([tmpdict count] == 1);
180 for (NSString * k in [tmpdict keyEnumerator]) {
182 if ([k intValue] != 0)
183 k_desc = KCDataTypeNameForID([k intValue]);
185 if ([sub_containers objectForKey:k_desc] == nil) {
186 sub_containers[k_desc] = [[NSMutableDictionary alloc] init];
188 sub_containers[k_desc][subcontainerID] = tmpdict[k];
190 buffer = (struct kcdata_item *)((uintptr_t)buffer + container_size);
191 if (KCDATA_ITEM_TYPE(buffer) == KCDATA_TYPE_BUFFER_END) {
197 tmptype = getKCDataTypeForID(_t);
198 tmpdict = [tmptype parseData:_d ofLength:KCDATA_ITEM_SIZE(buffer)];
199 if ([tmpdict count] == 1)
200 [container addEntriesFromDictionary:tmpdict];
202 container[[tmptype name]] = tmpdict;
204 [container addEntriesFromDictionary:sub_containers];
205 *bytesParsed = (uint32_t)((uintptr_t)buffer - (uintptr_t)dataBuffer);