source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/c-utility/src/map.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 22.6 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdlib.h>
5#include "azure_macro_utils/macro_utils.h"
6#include "azure_c_shared_utility/gballoc.h"
7#include "azure_c_shared_utility/map.h"
8#include "azure_c_shared_utility/optimize_size.h"
9#include "azure_c_shared_utility/xlogging.h"
10#include "azure_c_shared_utility/strings.h"
11
12MU_DEFINE_ENUM_STRINGS(MAP_RESULT, MAP_RESULT_VALUES);
13
14typedef struct MAP_HANDLE_DATA_TAG
15{
16 char** keys;
17 char** values;
18 size_t count;
19 MAP_FILTER_CALLBACK mapFilterCallback;
20}MAP_HANDLE_DATA;
21
22#define LOG_MAP_ERROR LogError("result = %" PRI_MU_ENUM "", MU_ENUM_VALUE(MAP_RESULT, result));
23
24MAP_HANDLE Map_Create(MAP_FILTER_CALLBACK mapFilterFunc)
25{
26 /*Codes_SRS_MAP_02_001: [Map_Create shall create a new, empty map.]*/
27 MAP_HANDLE_DATA* result = (MAP_HANDLE_DATA*)calloc(1, sizeof(MAP_HANDLE_DATA));
28 /*Codes_SRS_MAP_02_002: [If during creation there are any error, then Map_Create shall return NULL.]*/
29 if (result != NULL)
30 {
31 /*Codes_SRS_MAP_02_003: [Otherwise, it shall return a non-NULL handle that can be used in subsequent calls.] */
32 result->keys = NULL;
33 result->values = NULL;
34 result->count = 0;
35 result->mapFilterCallback = mapFilterFunc;
36 }
37 return (MAP_HANDLE)result;
38}
39
40void Map_Destroy(MAP_HANDLE handle)
41{
42 /*Codes_SRS_MAP_02_005: [If parameter handle is NULL then Map_Destroy shall take no action.] */
43 if (handle != NULL)
44 {
45 /*Codes_SRS_MAP_02_004: [Map_Destroy shall release all resources associated with the map.] */
46 MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle;
47 size_t i;
48
49 for (i = 0; i < handleData->count; i++)
50 {
51 free(handleData->keys[i]);
52 free(handleData->values[i]);
53 }
54 free(handleData->keys);
55 free(handleData->values);
56 free(handleData);
57 }
58}
59
60/*makes a copy of a vector of const char*, having size "size". source cannot be NULL*/
61/*returns NULL if it fails*/
62static char** Map_CloneVector(const char*const * source, size_t count)
63{
64 char** result;
65 result = (char**)malloc(count *sizeof(char*));
66 if (result == NULL)
67 {
68 /*do nothing, just return it (NULL)*/
69 }
70 else
71 {
72 size_t i;
73 for (i = 0; i < count; i++)
74 {
75 if (mallocAndStrcpy_s(result + i, source[i]) != 0)
76 {
77 break;
78 }
79 }
80
81 if (i == count)
82 {
83 /*it is all good, proceed to return result*/
84 }
85 else
86 {
87 size_t j;
88 for (j = 0; j < i; j++)
89 {
90 free(result[j]);
91 }
92 free(result);
93 result = NULL;
94 }
95 }
96 return result;
97}
98
99/*Codes_SRS_MAP_02_039: [Map_Clone shall make a copy of the map indicated by parameter handle and return a non-NULL handle to it.]*/
100MAP_HANDLE Map_Clone(MAP_HANDLE handle)
101{
102 MAP_HANDLE_DATA* result;
103 if (handle == NULL)
104 {
105 /*Codes_SRS_MAP_02_038: [Map_Clone returns NULL if parameter handle is NULL.]*/
106 result = NULL;
107 LogError("invalid arg to Map_Clone (NULL)");
108 }
109 else
110 {
111 MAP_HANDLE_DATA * handleData = (MAP_HANDLE_DATA *)handle;
112 result = (MAP_HANDLE_DATA*)calloc(1, sizeof(MAP_HANDLE_DATA));
113 if (result == NULL)
114 {
115 /*Codes_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */
116 /*do nothing, proceed to return it, this is an error case*/
117 LogError("unable to malloc");
118 }
119 else
120 {
121 if (handleData->count == 0)
122 {
123 result->count = 0;
124 result->keys = NULL;
125 result->values = NULL;
126 result->mapFilterCallback = NULL;
127 }
128 else
129 {
130 result->mapFilterCallback = handleData->mapFilterCallback;
131 result->count = handleData->count;
132 if( (result->keys = Map_CloneVector((const char* const*)handleData->keys, handleData->count))==NULL)
133 {
134 /*Codes_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */
135 LogError("unable to clone keys");
136 free(result);
137 result = NULL;
138 }
139 else if ((result->values = Map_CloneVector((const char* const*)handleData->values, handleData->count)) == NULL)
140 {
141 size_t i;
142 /*Codes_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */
143 LogError("unable to clone values");
144 for (i = 0; i < result->count; i++)
145 {
146 free(result->keys[i]);
147 }
148 free(result->keys);
149 free(result);
150 result = NULL;
151 }
152 else
153 {
154 /*all fine, return it*/
155 }
156 }
157 }
158 }
159 return (MAP_HANDLE)result;
160}
161
162static int Map_IncreaseStorageKeysValues(MAP_HANDLE_DATA* handleData)
163{
164 int result;
165 char** newKeys = (char**)realloc(handleData->keys, (handleData->count + 1) * sizeof(char*));
166 if (newKeys == NULL)
167 {
168 LogError("realloc error");
169 result = MU_FAILURE;
170 }
171 else
172 {
173 char** newValues;
174 handleData->keys = newKeys;
175 handleData->keys[handleData->count] = NULL;
176 newValues = (char**)realloc(handleData->values, (handleData->count + 1) * sizeof(char*));
177 if (newValues == NULL)
178 {
179 LogError("realloc error");
180 if (handleData->count == 0) /*avoiding an implementation defined behavior */
181 {
182 free(handleData->keys);
183 handleData->keys = NULL;
184 }
185 else
186 {
187 char** undoneKeys = (char**)realloc(handleData->keys, (handleData->count) * sizeof(char*));
188 if (undoneKeys == NULL)
189 {
190 LogError("CATASTROPHIC error, unable to undo through realloc to a smaller size");
191 }
192 else
193 {
194 handleData->keys = undoneKeys;
195 }
196 }
197 result = MU_FAILURE;
198 }
199 else
200 {
201 handleData->values = newValues;
202 handleData->values[handleData->count] = NULL;
203 handleData->count++;
204 result = 0;
205 }
206 }
207 return result;
208}
209
210static void Map_DecreaseStorageKeysValues(MAP_HANDLE_DATA* handleData)
211{
212 if (handleData->count == 1)
213 {
214 free(handleData->keys);
215 handleData->keys = NULL;
216 free(handleData->values);
217 handleData->values = NULL;
218 handleData->count = 0;
219 handleData->mapFilterCallback = NULL;
220 }
221 else
222 {
223 /*certainly > 1...*/
224 char** undoneValues;
225 char** undoneKeys = (char**)realloc(handleData->keys, sizeof(char*)* (handleData->count - 1));
226 if (undoneKeys == NULL)
227 {
228 LogError("CATASTROPHIC error, unable to undo through realloc to a smaller size");
229 }
230 else
231 {
232 handleData->keys = undoneKeys;
233 }
234
235 undoneValues = (char**)realloc(handleData->values, sizeof(char*)* (handleData->count - 1));
236 if (undoneValues == NULL)
237 {
238 LogError("CATASTROPHIC error, unable to undo through realloc to a smaller size");
239 }
240 else
241 {
242 handleData->values = undoneValues;
243 }
244
245 handleData->count--;
246 }
247}
248
249static char** findKey(MAP_HANDLE_DATA* handleData, const char* key)
250{
251 char** result;
252 if (handleData->keys == NULL)
253 {
254 result = NULL;
255 }
256 else
257 {
258 size_t i;
259 result = NULL;
260 for (i = 0; i < handleData->count; i++)
261 {
262 if (strcmp(handleData->keys[i], key) == 0)
263 {
264 result = handleData->keys + i;
265 break;
266 }
267 }
268 }
269 return result;
270}
271
272static char** findValue(MAP_HANDLE_DATA* handleData, const char* value)
273{
274 char** result;
275 if (handleData->values == NULL)
276 {
277 result = NULL;
278 }
279 else
280 {
281 size_t i;
282 result = NULL;
283 for (i = 0; i < handleData->count; i++)
284 {
285 if (strcmp(handleData->values[i], value) == 0)
286 {
287 result = handleData->values + i;
288 break;
289 }
290 }
291 }
292 return result;
293}
294
295static int insertNewKeyValue(MAP_HANDLE_DATA* handleData, const char* key, const char* value)
296{
297 int result;
298 if (Map_IncreaseStorageKeysValues(handleData) != 0) /*this increases handleData->count*/
299 {
300 result = MU_FAILURE;
301 }
302 else
303 {
304 if (mallocAndStrcpy_s(&(handleData->keys[handleData->count - 1]), key) != 0)
305 {
306 Map_DecreaseStorageKeysValues(handleData);
307 LogError("unable to mallocAndStrcpy_s");
308 result = MU_FAILURE;
309 }
310 else
311 {
312 if (mallocAndStrcpy_s(&(handleData->values[handleData->count - 1]), value) != 0)
313 {
314 free(handleData->keys[handleData->count - 1]);
315 Map_DecreaseStorageKeysValues(handleData);
316 LogError("unable to mallocAndStrcpy_s");
317 result = MU_FAILURE;
318 }
319 else
320 {
321 result = 0;
322 }
323 }
324 }
325 return result;
326}
327
328MAP_RESULT Map_Add(MAP_HANDLE handle, const char* key, const char* value)
329{
330 MAP_RESULT result;
331 /*Codes_SRS_MAP_02_006: [If parameter handle is NULL then Map_Add shall return MAP_INVALID_ARG.] */
332 /*Codes_SRS_MAP_02_007: [If parameter key is NULL then Map_Add shall return MAP_INVALID_ARG.]*/
333 /*Codes_SRS_MAP_02_008: [If parameter value is NULL then Map_Add shall return MAP_INVALID_ARG.] */
334 if (
335 (handle == NULL) ||
336 (key == NULL) ||
337 (value == NULL)
338 )
339 {
340 result = MAP_INVALIDARG;
341 LOG_MAP_ERROR;
342 }
343 else
344 {
345 MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle;
346 /*Codes_SRS_MAP_02_009: [If the key already exists, then Map_Add shall return MAP_KEYEXISTS.] */
347 if (findKey(handleData, key) != NULL)
348 {
349 result = MAP_KEYEXISTS;
350 }
351 else
352 {
353 /* Codes_SRS_MAP_07_009: [If the mapFilterCallback function is not NULL, then the return value will be check and if it is not zero then Map_Add shall return MAP_FILTER_REJECT.] */
354 if ( (handleData->mapFilterCallback != NULL) && (handleData->mapFilterCallback(key, value) != 0) )
355 {
356 result = MAP_FILTER_REJECT;
357 }
358 else
359 {
360 /*Codes_SRS_MAP_02_010: [Otherwise, Map_Add shall add the pair <key,value> to the map.] */
361 if (insertNewKeyValue(handleData, key, value) != 0)
362 {
363 /*Codes_SRS_MAP_02_011: [If adding the pair <key,value> fails then Map_Add shall return MAP_ERROR.] */
364 result = MAP_ERROR;
365 LOG_MAP_ERROR;
366 }
367 else
368 {
369 /*Codes_SRS_MAP_02_012: [Otherwise, Map_Add shall return MAP_OK.] */
370 result = MAP_OK;
371 }
372 }
373 }
374 }
375 return result;
376}
377
378MAP_RESULT Map_AddOrUpdate(MAP_HANDLE handle, const char* key, const char* value)
379{
380 MAP_RESULT result;
381 /*Codes_SRS_MAP_02_013: [If parameter handle is NULL then Map_AddOrUpdate shall return MAP_INVALID_ARG.]*/
382 /*Codes_SRS_MAP_02_014: [If parameter key is NULL then Map_AddOrUpdate shall return MAP_INVALID_ARG.]*/
383 /*Codes_SRS_MAP_02_015: [If parameter value is NULL then Map_AddOrUpdate shall return MAP_INVALID_ARG.] */
384 if (
385 (handle == NULL) ||
386 (key == NULL) ||
387 (value == NULL)
388 )
389 {
390 result = MAP_INVALIDARG;
391 LOG_MAP_ERROR;
392 }
393 else
394 {
395 MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle;
396
397 /* Codes_SRS_MAP_07_008: [If the mapFilterCallback function is not NULL, then the return value will be check and if it is not zero then Map_AddOrUpdate shall return MAP_FILTER_REJECT.] */
398 if (handleData->mapFilterCallback != NULL && handleData->mapFilterCallback(key, value) != 0)
399 {
400 result = MAP_FILTER_REJECT;
401 }
402 else
403 {
404 char** whereIsIt = findKey(handleData, key);
405 if (whereIsIt == NULL)
406 {
407 /*Codes_SRS_MAP_02_017: [Otherwise, Map_AddOrUpdate shall add the pair <key,value> to the map.]*/
408 if (insertNewKeyValue(handleData, key, value) != 0)
409 {
410 result = MAP_ERROR;
411 LOG_MAP_ERROR;
412 }
413 else
414 {
415 result = MAP_OK;
416 }
417 }
418 else
419 {
420 /*Codes_SRS_MAP_02_016: [If the key already exists, then Map_AddOrUpdate shall overwrite the value of the existing key with parameter value.]*/
421 size_t index = whereIsIt - handleData->keys;
422 size_t valueLength = strlen(value);
423 /*try to realloc value of this key*/
424 char* newValue = (char*)realloc(handleData->values[index],valueLength + 1);
425 if (newValue == NULL)
426 {
427 result = MAP_ERROR;
428 LOG_MAP_ERROR;
429 }
430 else
431 {
432 (void)memcpy(newValue, value, valueLength + 1);
433 handleData->values[index] = newValue;
434 /*Codes_SRS_MAP_02_019: [Otherwise, Map_AddOrUpdate shall return MAP_OK.] */
435 result = MAP_OK;
436 }
437 }
438 }
439 }
440 return result;
441}
442
443MAP_RESULT Map_Delete(MAP_HANDLE handle, const char* key)
444{
445 MAP_RESULT result;
446 /*Codes_SRS_MAP_02_020: [If parameter handle is NULL then Map_Delete shall return MAP_INVALIDARG.]*/
447 /*Codes_SRS_MAP_02_021: [If parameter key is NULL then Map_Delete shall return MAP_INVALIDARG.]*/
448 if (
449 (handle == NULL) ||
450 (key == NULL)
451 )
452 {
453 result = MAP_INVALIDARG;
454 LOG_MAP_ERROR;
455 }
456 else
457 {
458 MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle;
459 char** whereIsIt = findKey(handleData,key);
460 if (whereIsIt == NULL)
461 {
462 /*Codes_SRS_MAP_02_022: [If key does not exist then Map_Delete shall return MAP_KEYNOTFOUND.]*/
463 result = MAP_KEYNOTFOUND;
464 }
465 else
466 {
467 /*Codes_SRS_MAP_02_023: [Otherwise, Map_Delete shall remove the key and its associated value from the map and return MAP_OK.]*/
468 size_t index = whereIsIt - handleData->keys;
469 free(handleData->keys[index]);
470 free(handleData->values[index]);
471 memmove(handleData->keys + index, handleData->keys + index + 1, (handleData->count - index - 1)*sizeof(char*)); /*if order doesn't matter... then this can be optimized*/
472 memmove(handleData->values + index, handleData->values + index + 1, (handleData->count - index - 1)*sizeof(char*));
473 Map_DecreaseStorageKeysValues(handleData);
474 result = MAP_OK;
475 }
476
477 }
478 return result;
479}
480
481MAP_RESULT Map_ContainsKey(MAP_HANDLE handle, const char* key, bool* keyExists)
482{
483 MAP_RESULT result;
484 /*Codes_SRS_MAP_02_024: [If parameter handle, key or keyExists are NULL then Map_ContainsKey shall return MAP_INVALIDARG.]*/
485 if (
486 (handle ==NULL) ||
487 (key == NULL) ||
488 (keyExists == NULL)
489 )
490 {
491 result = MAP_INVALIDARG;
492 LOG_MAP_ERROR;
493 }
494 else
495 {
496 MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle;
497 /*Codes_SRS_MAP_02_025: [Otherwise if a key exists then Map_ContainsKey shall return MAP_OK and shall write in keyExists "true".]*/
498 /*Codes_SRS_MAP_02_026: [If a key doesn't exist, then Map_ContainsKey shall return MAP_OK and write in keyExists "false".] */
499 *keyExists = (findKey(handleData, key) != NULL) ? true: false;
500 result = MAP_OK;
501 }
502 return result;
503}
504
505MAP_RESULT Map_ContainsValue(MAP_HANDLE handle, const char* value, bool* valueExists)
506{
507 MAP_RESULT result;
508 /*Codes_SRS_MAP_02_027: [If parameter handle, value or valueExists is NULL then Map_ContainsValue shall return MAP_INVALIDARG.] */
509 if (
510 (handle == NULL) ||
511 (value == NULL) ||
512 (valueExists == NULL)
513 )
514 {
515 result = MAP_INVALIDARG;
516 LOG_MAP_ERROR;
517 }
518 else
519 {
520 MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle;
521 /*Codes_SRS_MAP_02_028: [Otherwise, if a pair <key, value> has its value equal to the parameter value, the Map_ContainsValue shall return MAP_OK and shall write in valueExists "true".]*/
522 /*Codes_SRS_MAP_02_029: [Otherwise, if such a <key, value> does not exist, then Map_ContainsValue shall return MAP_OK and shall write in valueExists "false".] */
523 *valueExists = (findValue(handleData, value) != NULL) ? true : false;
524 result = MAP_OK;
525 }
526 return result;
527}
528
529const char* Map_GetValueFromKey(MAP_HANDLE handle, const char* key)
530{
531 const char* result;
532 /*Codes_SRS_MAP_02_040: [If parameter handle or key is NULL then Map_GetValueFromKey returns NULL.]*/
533 if (
534 (handle == NULL) ||
535 (key == NULL)
536 )
537 {
538 result = NULL;
539 LogError("invalid parameter to Map_GetValueFromKey");
540 }
541 else
542 {
543 MAP_HANDLE_DATA * handleData = (MAP_HANDLE_DATA *)handle;
544 char** whereIsIt = findKey(handleData, key);
545 if(whereIsIt == NULL)
546 {
547 /*Codes_SRS_MAP_02_041: [If the key is not found, then Map_GetValueFromKey returns NULL.]*/
548 result = NULL;
549 }
550 else
551 {
552 /*Codes_SRS_MAP_02_042: [Otherwise, Map_GetValueFromKey returns the key's value.] */
553 size_t index = whereIsIt - handleData->keys;
554 result = handleData->values[index];
555 }
556 }
557 return result;
558}
559
560MAP_RESULT Map_GetInternals(MAP_HANDLE handle, const char*const** keys, const char*const** values, size_t* count)
561{
562 MAP_RESULT result;
563 /*Codes_SRS_MAP_02_046: [If parameter handle, keys, values or count is NULL then Map_GetInternals shall return MAP_INVALIDARG.] */
564 if (
565 (handle == NULL) ||
566 (keys == NULL) ||
567 (values == NULL) ||
568 (count == NULL)
569 )
570 {
571 result = MAP_INVALIDARG;
572 LOG_MAP_ERROR;
573 }
574 else
575 {
576 /*Codes_SRS_MAP_02_043: [Map_GetInternals shall produce in *keys an pointer to an array of const char* having all the keys stored so far by the map.]*/
577 /*Codes_SRS_MAP_02_044: [Map_GetInternals shall produce in *values a pointer to an array of const char* having all the values stored so far by the map.]*/
578 /*Codes_SRS_MAP_02_045: [ Map_GetInternals shall produce in *count the number of stored keys and values.]*/
579 MAP_HANDLE_DATA * handleData = (MAP_HANDLE_DATA *)handle;
580 *keys =(const char* const*)(handleData->keys);
581 *values = (const char* const*)(handleData->values);
582 *count = handleData->count;
583 result = MAP_OK;
584 }
585 return result;
586}
587
588STRING_HANDLE Map_ToJSON(MAP_HANDLE handle)
589{
590 STRING_HANDLE result;
591 /*Codes_SRS_MAP_02_052: [If parameter handle is NULL then Map_ToJSON shall return NULL.] */
592 if (handle == NULL)
593 {
594 result = NULL;
595 LogError("invalid arg (NULL)");
596 }
597 else
598 {
599 /*Codes_SRS_MAP_02_048: [Map_ToJSON shall produce a STRING_HANDLE representing the content of the MAP.] */
600 result = STRING_construct("{");
601 if (result == NULL)
602 {
603 LogError("STRING_construct failed");
604 }
605 else
606 {
607 size_t i;
608 MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA *)handle;
609 /*Codes_SRS_MAP_02_049: [If the MAP is empty, then Map_ToJSON shall produce the string "{}".*/
610 bool breakFor = false; /*used to break out of for*/
611 for (i = 0; (i < handleData->count) && (!breakFor); i++)
612 {
613 /*add one entry to the JSON*/
614 /*Codes_SRS_MAP_02_050: [If the map has properties then Map_ToJSON shall produce the following string:{"name1":"value1", "name2":"value2" ...}]*/
615 STRING_HANDLE key = STRING_new_JSON(handleData->keys[i]);
616 if (key == NULL)
617 {
618 LogError("STRING_new_JSON failed");
619 STRING_delete(result);
620 result = NULL;
621 breakFor = true;
622 }
623 else
624 {
625 STRING_HANDLE value = STRING_new_JSON(handleData->values[i]);
626 if (value == NULL)
627 {
628 LogError("STRING_new_JSON failed");
629 STRING_delete(result);
630 result = NULL;
631 breakFor = true;
632 }
633 else
634 {
635 if (!(
636 ((i>0) ? (STRING_concat(result, ",") == 0) : 1) &&
637 (STRING_concat_with_STRING(result, key) == 0) &&
638 (STRING_concat(result, ":") == 0) &&
639 (STRING_concat_with_STRING(result, value) == 0)
640 ))
641 {
642 LogError("failed to build the JSON");
643 STRING_delete(result);
644 result = NULL;
645 breakFor = true;
646 }
647 else
648 {
649 /*all nice, go to the next element in the map*/
650 }
651 STRING_delete(value);
652 }
653 STRING_delete(key);
654 }
655 }
656
657 if (breakFor)
658 {
659 LogError("error happened during JSON string builder");
660 }
661 else
662 {
663 if (STRING_concat(result, "}") != 0)
664 {
665 LogError("failed to build the JSON");
666 STRING_delete(result);
667 result = NULL;
668 }
669 else
670 {
671 /*return as is, JSON has been build*/
672 }
673 }
674 }
675 }
676 return result;
677
678}
Note: See TracBrowser for help on using the repository browser.