| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "mojo/public/c/bindings/array.h" | |
| 6 | |
| 7 #include <assert.h> | |
| 8 #include <stddef.h> | |
| 9 #include <stdint.h> | |
| 10 #include <string.h> | |
| 11 | |
| 12 #include "mojo/public/c/bindings/buffer.h" | |
| 13 #include "mojo/public/c/bindings/interface.h" | |
| 14 #include "mojo/public/c/bindings/lib/type_descriptor.h" | |
| 15 #include "mojo/public/c/bindings/lib/util.h" | |
| 16 #include "mojo/public/c/bindings/union.h" | |
| 17 | |
| 18 struct MojomArrayHeader* MojomArray_New(struct MojomBuffer* buf, | |
| 19 uint32_t num_elements, | |
| 20 uint32_t element_byte_size) { | |
| 21 assert(buf); | |
| 22 | |
| 23 uint64_t num_bytes = sizeof(struct MojomArrayHeader) + | |
| 24 (uint64_t)num_elements * element_byte_size; | |
| 25 if (num_bytes > UINT32_MAX) | |
| 26 return NULL; | |
| 27 | |
| 28 struct MojomArrayHeader* arr = | |
| 29 (struct MojomArrayHeader*)MojomBuffer_Allocate(buf, (uint32_t)num_bytes); | |
| 30 if (arr == NULL) | |
| 31 return NULL; | |
| 32 | |
| 33 assert((uintptr_t)arr + MOJOM_INTERNAL_ROUND_TO_8(num_bytes) == | |
| 34 (uintptr_t)buf->buf + buf->num_bytes_used); | |
| 35 | |
| 36 arr->num_elements = num_elements; | |
| 37 arr->num_bytes = MOJOM_INTERNAL_ROUND_TO_8((uint32_t)num_bytes); | |
| 38 | |
| 39 return arr; | |
| 40 } | |
| 41 | |
| 42 // Gets the |index|th element (whose type is described by |type|) of |array|. | |
| 43 // Only supports non-POD types. | |
| 44 static void* array_index_by_type(const struct MojomArrayHeader* array, | |
| 45 enum MojomTypeDescriptorType type, | |
| 46 size_t index) { | |
| 47 switch (type) { | |
| 48 case MOJOM_TYPE_DESCRIPTOR_TYPE_STRUCT_PTR: | |
| 49 case MOJOM_TYPE_DESCRIPTOR_TYPE_MAP_PTR: | |
| 50 case MOJOM_TYPE_DESCRIPTOR_TYPE_ARRAY_PTR: | |
| 51 return MOJOM_ARRAY_INDEX(array, union MojomPointer, index); | |
| 52 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION: | |
| 53 return MOJOM_ARRAY_INDEX(array, struct MojomUnionLayout, index); | |
| 54 case MOJOM_TYPE_DESCRIPTOR_TYPE_HANDLE: | |
| 55 return MOJOM_ARRAY_INDEX(array, MojoHandle, index); | |
| 56 case MOJOM_TYPE_DESCRIPTOR_TYPE_INTERFACE: | |
| 57 return MOJOM_ARRAY_INDEX(array, struct MojomInterfaceData, index); | |
| 58 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION_PTR: | |
| 59 case MOJOM_TYPE_DESCRIPTOR_TYPE_POD: | |
| 60 // This is a type that isn't supported in an array. | |
| 61 assert(0); | |
| 62 break; | |
| 63 } | |
| 64 return NULL; | |
| 65 } | |
| 66 | |
| 67 size_t MojomArray_ComputeSerializedSize( | |
| 68 const struct MojomTypeDescriptorArray* in_type_desc, | |
| 69 const struct MojomArrayHeader* in_array) { | |
| 70 assert(in_array); | |
| 71 assert(in_type_desc); | |
| 72 | |
| 73 size_t size = in_array->num_bytes; | |
| 74 if (!MojomType_IsPointer(in_type_desc->elem_type) && | |
| 75 in_type_desc->elem_type != MOJOM_TYPE_DESCRIPTOR_TYPE_UNION) | |
| 76 return size; | |
| 77 | |
| 78 for (uint32_t i = 0; i < in_array->num_elements; i++) { | |
| 79 size += MojomType_DispatchComputeSerializedSize( | |
| 80 in_type_desc->elem_type, | |
| 81 in_type_desc->elem_descriptor, | |
| 82 in_type_desc->nullable, | |
| 83 array_index_by_type(in_array, in_type_desc->elem_type, i)); | |
| 84 } | |
| 85 | |
| 86 return size; | |
| 87 } | |
| 88 | |
| 89 void MojomArray_EncodePointersAndHandles( | |
| 90 const struct MojomTypeDescriptorArray* in_type_desc, | |
| 91 struct MojomArrayHeader* inout_array, | |
| 92 uint32_t in_array_size, | |
| 93 struct MojomHandleBuffer* inout_handles_buffer) { | |
| 94 assert(in_type_desc); | |
| 95 assert(inout_array); | |
| 96 assert(in_array_size >= sizeof(struct MojomArrayHeader)); | |
| 97 assert(in_array_size >= inout_array->num_bytes); | |
| 98 | |
| 99 // Nothing to encode for POD types. | |
| 100 if (in_type_desc->elem_type == MOJOM_TYPE_DESCRIPTOR_TYPE_POD) | |
| 101 return; | |
| 102 | |
| 103 for (size_t i = 0; i < inout_array->num_elements; i++) { | |
| 104 char* elem_data = | |
| 105 array_index_by_type(inout_array, in_type_desc->elem_type, i); | |
| 106 assert(elem_data < (char*)inout_array + in_array_size); | |
| 107 | |
| 108 MojomType_DispatchEncodePointersAndHandles( | |
| 109 in_type_desc->elem_type, | |
| 110 in_type_desc->elem_descriptor, | |
| 111 in_type_desc->nullable, | |
| 112 elem_data, | |
| 113 in_array_size - (uint32_t)(elem_data - (char*)inout_array), | |
| 114 inout_handles_buffer); | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 void MojomArray_DecodePointersAndHandles( | |
| 119 const struct MojomTypeDescriptorArray* in_type_desc, | |
| 120 struct MojomArrayHeader* inout_array, | |
| 121 uint32_t in_array_size, | |
| 122 MojoHandle* inout_handles, | |
| 123 uint32_t in_num_handles) { | |
| 124 assert(in_type_desc); | |
| 125 assert(inout_array); | |
| 126 assert(inout_handles != NULL || in_num_handles == 0); | |
| 127 | |
| 128 // Nothing to encode for POD types. | |
| 129 if (in_type_desc->elem_type == MOJOM_TYPE_DESCRIPTOR_TYPE_POD) | |
| 130 return; | |
| 131 | |
| 132 for (size_t i = 0; i < inout_array->num_elements; i++) { | |
| 133 char* elem_data = | |
| 134 array_index_by_type(inout_array, in_type_desc->elem_type, i); | |
| 135 assert(elem_data < (char*)inout_array + in_array_size); | |
| 136 | |
| 137 MojomType_DispatchDecodePointersAndHandles( | |
| 138 in_type_desc->elem_type, | |
| 139 in_type_desc->elem_descriptor, | |
| 140 in_type_desc->nullable, | |
| 141 elem_data, | |
| 142 in_array_size - (uint32_t)(elem_data - (char*)inout_array), | |
| 143 inout_handles, | |
| 144 in_num_handles); | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 // Rounds up to nearest byte. | |
| 149 static uint64_t bits_to_bytes(uint64_t bits) { | |
| 150 return (bits + 7) / 8; | |
| 151 } | |
| 152 | |
| 153 static MojomValidationResult validate_array_header( | |
| 154 const struct MojomTypeDescriptorArray* in_type_desc, | |
| 155 const struct MojomArrayHeader* in_array, | |
| 156 uint32_t in_buf_size) { | |
| 157 if (in_buf_size < sizeof(struct MojomArrayHeader)) | |
| 158 return MOJOM_VALIDATION_ILLEGAL_MEMORY_RANGE; | |
| 159 | |
| 160 if (in_array->num_bytes < sizeof(struct MojomArrayHeader)) | |
| 161 return MOJOM_VALIDATION_UNEXPECTED_ARRAY_HEADER; | |
| 162 | |
| 163 if (in_array->num_bytes > in_buf_size) | |
| 164 return MOJOM_VALIDATION_ILLEGAL_MEMORY_RANGE; | |
| 165 | |
| 166 if (in_type_desc->num_elements != 0 && | |
| 167 in_array->num_elements != in_type_desc->num_elements) | |
| 168 return MOJOM_VALIDATION_UNEXPECTED_ARRAY_HEADER; | |
| 169 | |
| 170 // Array size is less than what we need to fit the elements. | |
| 171 if (in_array->num_bytes < | |
| 172 sizeof(struct MojomArrayHeader) + | |
| 173 bits_to_bytes((uint64_t)in_type_desc->elem_num_bits * | |
| 174 (uint64_t)in_array->num_elements)) { | |
| 175 return MOJOM_VALIDATION_UNEXPECTED_ARRAY_HEADER; | |
| 176 } | |
| 177 | |
| 178 return MOJOM_VALIDATION_ERROR_NONE; | |
| 179 } | |
| 180 | |
| 181 MojomValidationResult MojomArray_Validate( | |
| 182 const struct MojomTypeDescriptorArray* in_type_desc, | |
| 183 const struct MojomArrayHeader* in_array, | |
| 184 uint32_t in_array_size, | |
| 185 uint32_t in_num_handles, | |
| 186 struct MojomValidationContext* inout_context) { | |
| 187 assert(in_type_desc); | |
| 188 assert(in_array); | |
| 189 | |
| 190 MojomValidationResult result = | |
| 191 validate_array_header(in_type_desc, in_array, in_array_size); | |
| 192 if (result != MOJOM_VALIDATION_ERROR_NONE) | |
| 193 return result; | |
| 194 | |
| 195 // From here on out, all pointers need to point past the end of this struct. | |
| 196 inout_context->next_pointer = (char*)in_array + in_array->num_bytes; | |
| 197 | |
| 198 // Nothing to validate for POD types. | |
| 199 if (in_type_desc->elem_type == MOJOM_TYPE_DESCRIPTOR_TYPE_POD) | |
| 200 return MOJOM_VALIDATION_ERROR_NONE; | |
| 201 | |
| 202 for (size_t i = 0; i < in_array->num_elements; i++) { | |
| 203 char* elem_data = | |
| 204 array_index_by_type(in_array, in_type_desc->elem_type, i); | |
| 205 | |
| 206 MojomValidationResult result = MojomType_DispatchValidate( | |
| 207 in_type_desc->elem_type, | |
| 208 in_type_desc->elem_descriptor, | |
| 209 in_type_desc->nullable, | |
| 210 elem_data, | |
| 211 in_array_size - (uint32_t)(elem_data - (char*)in_array), | |
| 212 in_num_handles, | |
| 213 inout_context); | |
| 214 if (result != MOJOM_VALIDATION_ERROR_NONE) | |
| 215 return result; | |
| 216 } | |
| 217 | |
| 218 return MOJOM_VALIDATION_ERROR_NONE; | |
| 219 } | |
| 220 | |
| 221 bool MojomArray_DeepCopy( | |
| 222 struct MojomBuffer* buffer, | |
| 223 const struct MojomTypeDescriptorArray* in_type_desc, | |
| 224 const struct MojomArrayHeader* in_array, | |
| 225 struct MojomArrayHeader** out_array) { | |
| 226 assert(in_type_desc); | |
| 227 assert(in_array); | |
| 228 assert(out_array); | |
| 229 | |
| 230 *out_array = MojomBuffer_Allocate(buffer, in_array->num_bytes); | |
| 231 if (*out_array == NULL) | |
| 232 return false; | |
| 233 | |
| 234 memcpy(*out_array, in_array, in_array->num_bytes); | |
| 235 | |
| 236 // Nothing else to copy for POD types. | |
| 237 if (in_type_desc->elem_type == MOJOM_TYPE_DESCRIPTOR_TYPE_POD) | |
| 238 return true; | |
| 239 | |
| 240 for (size_t i = 0; i < in_array->num_elements; i++) { | |
| 241 void* in_elem_data = | |
| 242 array_index_by_type(in_array, in_type_desc->elem_type, i); | |
| 243 void* out_elem_data = | |
| 244 array_index_by_type(*out_array, in_type_desc->elem_type, i); | |
| 245 | |
| 246 if (!MojomType_DispatchDeepCopy(buffer, in_type_desc->elem_type, | |
| 247 in_type_desc->elem_descriptor, in_elem_data, | |
| 248 out_elem_data)) { | |
| 249 return false; | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 return true; | |
| 254 } | |
| OLD | NEW |