Simulated product dispenser
Fork of mbed-cloud-workshop-connect-HTS221 by
arm_uc_utilities.c
00001 // ---------------------------------------------------------------------------- 00002 // Copyright 2016-2017 ARM Ltd. 00003 // 00004 // SPDX-License-Identifier: Apache-2.0 00005 // 00006 // Licensed under the Apache License, Version 2.0 (the "License"); 00007 // you may not use this file except in compliance with the License. 00008 // You may obtain a copy of the License at 00009 // 00010 // http://www.apache.org/licenses/LICENSE-2.0 00011 // 00012 // Unless required by applicable law or agreed to in writing, software 00013 // distributed under the License is distributed on an "AS IS" BASIS, 00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 // See the License for the specific language governing permissions and 00016 // limitations under the License. 00017 // ---------------------------------------------------------------------------- 00018 00019 #include "update-client-common/arm_uc_utilities.h" 00020 #include "update-client-common/arm_uc_error.h" 00021 #include "update-client-common/arm_uc_config.h" 00022 00023 #include <string.h> 00024 #include <stdlib.h> 00025 #include <stdio.h> 00026 00027 /* lookup table for printing hexadecimal values */ 00028 const uint8_t arm_uc_hex_table[16] = {'0', '1', '2', '3', '4', '5', '6', '7', 00029 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 00030 00031 /** 00032 * @brief Parse a uri string to populate a arm_uc_uri_t struct 00033 * @detail Format of uri scheme:[//]host[:port]/path 00034 * [] means optional, path will always start with a '/' 00035 * 00036 * @param str Pointer to string containing URI. 00037 * @param size String length. 00038 * @param uri The arm_uc_uri_t struct to be populated 00039 * @return Error code. 00040 */ 00041 arm_uc_error_t arm_uc_str2uri(const uint8_t* buffer, 00042 uint32_t buffer_size, 00043 arm_uc_uri_t* uri) 00044 { 00045 arm_uc_error_t result = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; 00046 00047 if (buffer && 00048 uri && 00049 uri->ptr && 00050 (buffer_size < uri->size_max)) 00051 { 00052 const uint8_t* str = buffer; 00053 uint8_t* colon = NULL; 00054 uint8_t* slash = NULL; 00055 uint32_t len = 0; 00056 00057 /* find scheme by searching for first colon */ 00058 colon = memchr(str, ':', buffer_size); 00059 len = colon - str; 00060 00061 if (len < uri->size_max) 00062 { 00063 /* copy scheme to temporary uri buffer and convert to lower case. 00064 */ 00065 for (uint32_t index = 0; index < len; index++) 00066 { 00067 /* lower case characters have higher ASCII value */ 00068 if (str[index] < 'a') 00069 { 00070 uri->ptr[index] = str[index] + ('a' - 'A'); 00071 } 00072 else 00073 { 00074 uri->ptr[index] = str[index]; 00075 } 00076 } 00077 00078 /* copy ':' */ 00079 uri->ptr[len] = str[len]; 00080 00081 /* convert scheme string to scheme type */ 00082 if (memcmp(uri->ptr, "http:", 5) == 0) 00083 { 00084 uri->scheme = URI_SCHEME_HTTP; 00085 00086 /* set default port based on scheme - can be overwritten */ 00087 uri->port = 80; 00088 } 00089 else 00090 { 00091 uri->scheme = URI_SCHEME_NONE; 00092 } 00093 00094 /* only continue if scheme is supported */ 00095 if (uri->scheme != URI_SCHEME_NONE) 00096 { 00097 /* strip any leading '/' */ 00098 str = colon + 1; 00099 for (str += 1; 00100 (str[0] == '/') && (str < (buffer + buffer_size)); 00101 ++str); 00102 00103 /* find separation between host and path */ 00104 slash = memchr(str, '/', buffer_size - (str - buffer)); 00105 00106 if (slash != NULL) 00107 { 00108 bool parsed = true; 00109 00110 /* find optional port */ 00111 colon = memchr(str, ':', buffer_size - (slash - buffer)); 00112 00113 if (colon != NULL) 00114 { 00115 uri->port = arm_uc_str2uint32(colon + 1, 00116 buffer_size - (colon - buffer), 00117 &parsed); 00118 len = colon - str; 00119 } 00120 else 00121 { 00122 len = slash - str; 00123 } 00124 00125 /* check */ 00126 if ((parsed == 1) && (len < uri->size_max)) 00127 { 00128 /* copy host name to URI buffer */ 00129 memcpy(uri->ptr, str, len); 00130 00131 /* \0 terminate string */ 00132 uri->ptr[len] = '\0'; 00133 00134 /* update length */ 00135 uri->size = len + 1; 00136 00137 /* set host pointer */ 00138 uri->host = (char*) uri->ptr; 00139 00140 /* find remaining path length */ 00141 str = slash; 00142 len = arm_uc_strnlen(str, buffer_size - (str - buffer)); 00143 00144 /* check */ 00145 if ((len > 0) && (len < (uri->size_max - uri->size))) 00146 { 00147 /* copy path to URI buffer */ 00148 memcpy(&uri->ptr[uri->size], str, len); 00149 00150 /* set path pointer */ 00151 uri->path = (char*) &uri->ptr[uri->size]; 00152 00153 /* \0 terminate string */ 00154 uri->ptr[uri->size + len] = '\0'; 00155 00156 /* update length after path pointer is set */ 00157 uri->size += len + 1; 00158 00159 /* parsing passed all checks */ 00160 result = (arm_uc_error_t){ ERR_NONE }; 00161 } 00162 } 00163 } 00164 } 00165 } 00166 } 00167 00168 return result; 00169 } 00170 00171 /** 00172 * @brief Find substring inside string. 00173 * @details The size of both string and substring is explicitly passed so no 00174 * assumptions are made about NULL termination. 00175 * 00176 * @param big_buffer Pointer to the string to be searched. 00177 * @param big_length Length of the string to be searched. 00178 * @param little_buffer Pointer to the substring being searched for. 00179 * @param little_length Length of the substring being searched for. 00180 * @return Index to where the substring was found inside the string. If the 00181 * string doesn't contain the subtring, UINT32_MAX is returned. 00182 */ 00183 uint32_t arm_uc_strnstrn(const uint8_t* big_buffer, 00184 uint32_t big_length, 00185 const uint8_t* little_buffer, 00186 uint32_t little_length) 00187 { 00188 uint32_t result = UINT32_MAX; 00189 00190 /* Sanity check. Pointers are not NULL. The little buffer is smaller than 00191 the big buffer. The little buffer is not empty. 00192 */ 00193 if (big_buffer && 00194 little_buffer && 00195 (big_length >= little_length) && 00196 (little_length > 0)) 00197 { 00198 uint8_t little_hash = 0; 00199 uint8_t big_hash = 0; 00200 uint32_t little_length_m1 = little_length - 1; 00201 00202 /* Prepare hashes. The last byte for the big hash is added in the 00203 comparison loop. 00204 */ 00205 for (uint32_t index = 0; index < little_length_m1; index++) 00206 { 00207 little_hash ^= little_buffer[index]; 00208 big_hash ^= big_buffer[index]; 00209 } 00210 00211 /* Add the last byte for the little hash. */ 00212 little_hash ^= little_buffer[little_length_m1]; 00213 00214 /* Comparison loop. In each loop the big hash is updated and compared 00215 to the little hash. If the hash matches, a more thorough byte-wise 00216 comparison is performed. The complexity of the hash determines how 00217 often a collision occures and how often a full comparison is done. 00218 */ 00219 for (uint32_t index = 0; 00220 index < (big_length - (little_length_m1)); 00221 index++) 00222 { 00223 /* update hash */ 00224 big_hash ^= big_buffer[index + (little_length_m1)]; 00225 00226 /* cursory check */ 00227 if (little_hash == big_hash) 00228 { 00229 /* hash checks out do comprehensive check */ 00230 uint32_t checks = 0; 00231 00232 for ( ; checks < little_length; checks++) 00233 { 00234 /* stop counting if bytes differ */ 00235 if (big_buffer[index + checks] != little_buffer[checks]) 00236 { 00237 break; 00238 } 00239 } 00240 00241 /* check if all bytes matched */ 00242 if (checks == little_length) 00243 { 00244 /* save pointer and break loop */ 00245 result = index; 00246 break; 00247 } 00248 } 00249 00250 /* update hash - remove tail */ 00251 big_hash ^= big_buffer[index]; 00252 } 00253 } 00254 00255 return result; 00256 } 00257 00258 /** 00259 * @brief Find string length. 00260 * @details Custom implementation of strnlen which is a GNU extension. 00261 * Returns either the string length or max_length. 00262 * 00263 * @param buffer Pointer to string. 00264 * @param max_length Maximum buffer length. 00265 * 00266 * @return String length or max_length. 00267 */ 00268 uint32_t arm_uc_strnlen(const uint8_t* buffer, uint32_t max_length) 00269 { 00270 uint32_t length = 0; 00271 00272 for ( ; length < max_length; length++) 00273 { 00274 if (buffer[length] == '\0') 00275 { 00276 break; 00277 } 00278 } 00279 00280 return length; 00281 } 00282 00283 /** 00284 * @brief Convert string to unsigned 32 bit integer. 00285 * @details Function tries to parse string as an unsigned 32 bit integer 00286 * and return the value. The function expects the first byte to be an 00287 * integer and will continue until: 00288 * 1. the buffer is empty 00289 * 2. the intermediate result is larger then UINT32_MAX 00290 * 3. the next byte is not a number 00291 * 00292 * If a valid 32 bit unsigned integer is found the third parameter is 00293 * set to true and the return value holds the parsed number. Otherwise, 00294 * the third parameter will be false and the return value will be 0. 00295 * 00296 * @param buffer Pointer to string. 00297 * @param max_length Maximum buffer length. 00298 * @param success Pointer to boolean indicating whether the parsing was successful. 00299 * @return Parsed value. Only valid if success it true. 00300 */ 00301 uint32_t arm_uc_str2uint32(const uint8_t* buffer, 00302 uint32_t max_length, 00303 bool* success) 00304 { 00305 uint64_t result = 0; 00306 bool found = false; 00307 00308 /* default output and return status is 0 and false */ 00309 uint32_t output = 0; 00310 00311 if (success) 00312 { 00313 *success = false; 00314 } 00315 00316 /* null pointer and length check */ 00317 if (buffer && (max_length > 0)) 00318 { 00319 /* loop through string */ 00320 for (uint32_t index = 0; index < max_length; index++) 00321 { 00322 /* check if character is a number */ 00323 if (('0' <= buffer[index]) && 00324 (buffer[index] <= '9') && 00325 (result < UINT64_MAX)) 00326 { 00327 /* shift one decimal position and append next digit */ 00328 result *= 10; 00329 result += buffer[index] - '0'; 00330 00331 /* found at least one integer, mark as found */ 00332 found = true; 00333 } 00334 else 00335 { 00336 /* character is not a number, stop loop */ 00337 break; 00338 } 00339 } 00340 00341 /* set output and return value only if a valid number was found */ 00342 if (found && (result <= UINT64_MAX)) 00343 { 00344 output = result; 00345 00346 if (success) 00347 { 00348 *success = true; 00349 } 00350 } 00351 } 00352 00353 return output; 00354 } 00355 00356 uint32_t arm_uc_crc32(const uint8_t* buffer, uint32_t length) 00357 { 00358 const uint8_t* current = buffer; 00359 uint32_t crc = 0xFFFFFFFF; 00360 00361 while (length--) 00362 { 00363 crc ^= *current++; 00364 00365 for (uint32_t counter = 0; counter < 8; counter++) 00366 { 00367 if (crc & 1) 00368 { 00369 crc = (crc >> 1) ^ 0xEDB88320; 00370 } 00371 else 00372 { 00373 crc = crc >> 1; 00374 } 00375 } 00376 } 00377 00378 return (crc ^ 0xFFFFFFFF); 00379 } 00380 00381 uint32_t arm_uc_parse_uint32(const uint8_t* input) 00382 { 00383 uint32_t result = 0; 00384 00385 if (input) 00386 { 00387 result = input[0]; 00388 result = (result << 8) | input[1]; 00389 result = (result << 8) | input[2]; 00390 result = (result << 8) | input[3]; 00391 } 00392 00393 return result; 00394 } 00395 00396 uint64_t arm_uc_parse_uint64(const uint8_t* input) 00397 { 00398 uint64_t result = 0; 00399 00400 if (input) 00401 { 00402 result = input[0]; 00403 result = (result << 8) | input[1]; 00404 result = (result << 8) | input[2]; 00405 result = (result << 8) | input[3]; 00406 result = (result << 8) | input[4]; 00407 result = (result << 8) | input[5]; 00408 result = (result << 8) | input[6]; 00409 result = (result << 8) | input[7]; 00410 } 00411 00412 return result; 00413 } 00414 00415 void arm_uc_write_uint32(uint8_t* buffer, uint32_t value) 00416 { 00417 if (buffer) 00418 { 00419 buffer[3] = value; 00420 buffer[2] = (value >> 8); 00421 buffer[1] = (value >> 16); 00422 buffer[0] = (value >> 24); 00423 } 00424 } 00425 00426 void arm_uc_write_uint64(uint8_t* buffer, uint64_t value) 00427 { 00428 if (buffer) 00429 { 00430 buffer[7] = value; 00431 buffer[6] = (value >> 8); 00432 buffer[5] = (value >> 16); 00433 buffer[4] = (value >> 24); 00434 buffer[3] = (value >> 32); 00435 buffer[2] = (value >> 40); 00436 buffer[1] = (value >> 48); 00437 buffer[0] = (value >> 56); 00438 } 00439 } 00440 00441 // Constant time binary comparison 00442 uint32_t ARM_UC_BinCompareCT(const arm_uc_buffer_t* a, const arm_uc_buffer_t* b) 00443 { 00444 uint32_t result; 00445 uint32_t i; 00446 const uint32_t *wa = (uint32_t *)a->ptr; 00447 const uint32_t *wb = (uint32_t *)b->ptr; 00448 const uint32_t bytes_aligned = a->size & ~((1 << sizeof(uint32_t)) - 1); 00449 const uint32_t bytes = a->size; 00450 00451 // Check sizes 00452 if (a->size != b->size) 00453 { 00454 return 1; 00455 } 00456 result = 0; 00457 for (i = 0; i < bytes_aligned; i += sizeof(uint32_t)) 00458 { 00459 const uint32_t idx = i/sizeof(uint32_t); 00460 result = result | (wa[idx] ^ wb[idx]); 00461 } 00462 for (; i < bytes; i++) 00463 { 00464 result = result | (a->ptr[i] ^ b->ptr[i]); 00465 } 00466 // Reduce to 0 or 1 in constant time 00467 return (result | -result) >> 31; 00468 } 00469 00470 static const uint8_t base64EncodeArray[65] = {MBED_CLOUD_UPDATE_BASE64_CHARSET}; 00471 00472 uint8_t * ARM_UC_Base64Enc(uint8_t* buf, const uint32_t size, const arm_uc_buffer_t* bin) 00473 { 00474 uint32_t partial = 0; 00475 const uint8_t * lastPos = buf + size; 00476 uint32_t i; 00477 uint32_t pad2 = (bin->size - bin->size % 3); 00478 uint32_t pad1 = (bin->size - bin->size % 3) + 1; 00479 for (i = 0; i < bin->size && buf <= lastPos - 4; i+=3) { 00480 partial = (bin->ptr[i] << 16); 00481 if ( i < pad1 ) 00482 { 00483 partial = partial | (bin->ptr[i+1] << 8); 00484 } 00485 if ( i < pad2) 00486 { 00487 partial = partial | (bin->ptr[i+2] << 0); 00488 } 00489 buf[0] = base64EncodeArray[(partial >> 18) & 0x3f]; 00490 buf[1] = base64EncodeArray[(partial >> 12) & 0x3f]; 00491 buf[2] = (i < pad1) ? base64EncodeArray[(partial >> 6) & 0x3f] : base64EncodeArray[64]; 00492 buf[3] = (i < pad2) ? base64EncodeArray[(partial >> 0) & 0x3f] : base64EncodeArray[64]; 00493 buf += 4; 00494 } 00495 buf[0] = 0; 00496 return buf; 00497 } 00498 00499 uint32_t ARM_UC_Base64DecodeChar(uint8_t c) 00500 { 00501 if (c == MBED_CLOUD_UPDATE_BASE64_CHARSET[64] || c == MBED_CLOUD_UPDATE_BASE64_CHARSET[0]) 00502 { 00503 return 0; 00504 } 00505 uint32_t idx = 0; 00506 int32_t i; 00507 for (i = 5; i >= 0; i--) 00508 { 00509 uint32_t tmpidx = idx | 1 << i; 00510 uint8_t ct = MBED_CLOUD_UPDATE_BASE64_CHARSET[tmpidx]; 00511 if (c == ct) 00512 { 00513 return tmpidx; 00514 } 00515 else if (c > ct) 00516 { 00517 idx = tmpidx; 00518 } 00519 } 00520 return (uint32_t) -1; 00521 } 00522 00523 void ARM_UC_Base64Dec(arm_uc_buffer_t* bin, const uint32_t size, const uint8_t* buf) 00524 { 00525 uintptr_t optr = (uintptr_t)bin->ptr; 00526 const uint8_t* iptr = buf; 00527 while ((uintptr_t)iptr + 4 < (uintptr_t) buf + size && optr + 1 < (uintptr_t)bin->ptr + bin->size_max) { 00528 uint8_t partial[3]; 00529 uint8_t a = (ARM_UC_Base64DecodeChar(iptr[0])); 00530 uint8_t b = (ARM_UC_Base64DecodeChar(iptr[1])); 00531 uint8_t c = (ARM_UC_Base64DecodeChar(iptr[2])); 00532 uint8_t d = (ARM_UC_Base64DecodeChar(iptr[3])); 00533 uint8_t l = 3; 00534 if (d == MBED_CLOUD_UPDATE_BASE64_CHARSET[64]) 00535 { 00536 l--; 00537 } 00538 if (c == MBED_CLOUD_UPDATE_BASE64_CHARSET[64]) 00539 { 00540 l--; 00541 } 00542 partial[0] = ((a << 2) & 0xfc) | ((b >> 4) & 0x3); 00543 partial[1] = ((b << 4) & 0xf0) | ((c >> 2) & 0xf); 00544 partial[2] = ((c << 6) & 0xc0) | ((d >> 0) & 0x3f); 00545 memcpy((void*)optr, partial, l); 00546 iptr += 4; 00547 optr += l; 00548 if (d == MBED_CLOUD_UPDATE_BASE64_CHARSET[64]) 00549 { 00550 break; 00551 } 00552 } 00553 bin->size = optr - (uintptr_t)bin->ptr; 00554 }
Generated on Tue Jul 12 2022 19:12:11 by 1.7.2