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