Nigel Rantor / azure_c_shared_utility

Fork of azure_c_shared_utility by Azure IoT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers strings.c Source File

strings.c

00001 // Copyright (c) Microsoft. All rights reserved.
00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
00003 
00004 //
00005 // PUT NO INCLUDES BEFORE HERE
00006 //
00007 #include <stdlib.h>
00008 #include "azure_c_shared_utility/gballoc.h"
00009 #include <stddef.h>
00010 #include <string.h>
00011 #include <stdarg.h>
00012 #include <stdio.h>
00013 
00014 //
00015 // PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE
00016 //
00017 
00018 #include "azure_c_shared_utility/strings.h"
00019 #include "azure_c_shared_utility/optimize_size.h"
00020 #include "azure_c_shared_utility/xlogging.h"
00021 
00022 static const char hexToASCII[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
00023 
00024 typedef struct STRING_TAG
00025 {
00026     char* s;
00027 } STRING;
00028 
00029 /*this function will allocate a new string with just '\0' in it*/
00030 /*return NULL if it fails*/
00031 /* Codes_SRS_STRING_07_001: [STRING_new shall allocate a new STRING_HANDLE pointing to an empty string.] */
00032 STRING_HANDLE STRING_new(void)
00033 {
00034     STRING* result;
00035     if ((result = (STRING*)malloc(sizeof(STRING))) != NULL)
00036     {
00037         if ((result->s = (char*)malloc(1)) != NULL)
00038         {
00039             result->s[0] = '\0';
00040         }
00041         else
00042         {
00043             /* Codes_SRS_STRING_07_002: [STRING_new shall return an NULL STRING_HANDLE on any error that is encountered.] */
00044             free(result);
00045             result = NULL;
00046         }
00047     }
00048     return (STRING_HANDLE)result;
00049 }
00050 
00051 /*Codes_SRS_STRING_02_001: [STRING_clone shall produce a new string having the same content as the handle string.*/
00052 STRING_HANDLE STRING_clone(STRING_HANDLE handle)
00053 {
00054     STRING* result;
00055     /*Codes_SRS_STRING_02_002: [If parameter handle is NULL then STRING_clone shall return NULL.]*/
00056     if (handle == NULL)
00057     {
00058         result = NULL;
00059     }
00060     else
00061     {
00062         /*Codes_SRS_STRING_02_003: [If STRING_clone fails for any reason, it shall return NULL.] */
00063         if ((result = (STRING*)malloc(sizeof(STRING))) != NULL)
00064         {
00065             STRING* source = (STRING*)handle;
00066             /*Codes_SRS_STRING_02_003: [If STRING_clone fails for any reason, it shall return NULL.] */
00067             size_t sourceLen = strlen(source->s);
00068             if ((result->s = (char*)malloc(sourceLen + 1)) == NULL)
00069             {
00070                 free(result);
00071                 result = NULL;
00072             }
00073             else
00074             {
00075                 (void)memcpy(result->s, source->s, sourceLen + 1);
00076             }
00077         }
00078         else
00079         {
00080             /*not much to do, result is NULL from malloc*/
00081         }
00082     }
00083     return (STRING_HANDLE)result;
00084 }
00085 
00086 /* Codes_SRS_STRING_07_003: [STRING_construct shall allocate a new string with the value of the specified const char*.] */
00087 STRING_HANDLE STRING_construct(const char* psz)
00088 {
00089     STRING_HANDLE result;
00090     if (psz == NULL)
00091     {
00092         /* Codes_SRS_STRING_07_005: [If the supplied const char* is NULL STRING_construct shall return a NULL value.] */
00093         result = NULL;
00094     }
00095     else
00096     {
00097         STRING* str;
00098         if ((str = (STRING*)malloc(sizeof(STRING))) != NULL)
00099         {
00100             size_t nLen = strlen(psz) + 1;
00101             if ((str->s = (char*)malloc(nLen)) != NULL)
00102             {
00103                 (void)memcpy(str->s, psz, nLen);
00104                 result = (STRING_HANDLE)str;
00105             }
00106             /* Codes_SRS_STRING_07_032: [STRING_construct encounters any error it shall return a NULL value.] */
00107             else
00108             {
00109                 free(str);
00110                 result = NULL;
00111             }
00112         }
00113         else
00114         {
00115             /* Codes_SRS_STRING_07_032: [STRING_construct encounters any error it shall return a NULL value.] */
00116             result = NULL;
00117         }
00118     }
00119     return result;
00120 }
00121 
00122 #if defined(__GNUC__)
00123 __attribute__ ((format (printf, 1, 2)))
00124 #endif
00125 STRING_HANDLE STRING_construct_sprintf(const char* format, ...)
00126 {
00127     STRING* result;
00128     
00129 #ifdef ARDUINO_ARCH_ESP8266
00130     size_t maxBufSize = 512;
00131     char buf[512];
00132 #else
00133     size_t maxBufSize = 0;
00134     char* buf = NULL;
00135 #endif
00136 
00137     if (format != NULL)
00138     {
00139         va_list arg_list;
00140         int length;
00141         va_start(arg_list, format);
00142 
00143         /* Codes_SRS_STRING_07_041: [STRING_construct_sprintf shall determine the size of the resulting string and allocate the necessary memory.] */
00144         length = vsnprintf(buf, maxBufSize, format, arg_list);
00145         va_end(arg_list);
00146         if (length > 0)
00147         {
00148             result = (STRING*)malloc(sizeof(STRING));
00149             if (result != NULL)
00150             {
00151                 result->s = (char*)malloc(length+1);
00152                 if (result->s != NULL)
00153                 {
00154                     va_start(arg_list, format);
00155                     if (vsnprintf(result->s, length+1, format, arg_list) < 0)
00156                     {
00157                         /* Codes_SRS_STRING_07_040: [If any error is encountered STRING_construct_sprintf shall return NULL.] */
00158                         free(result->s);
00159                         free(result);
00160                         result = NULL;
00161                         LogError("Failure: vsnprintf formatting failed.");
00162                     }
00163                     va_end(arg_list);
00164                 }
00165                 else
00166                 {
00167                     /* Codes_SRS_STRING_07_040: [If any error is encountered STRING_construct_sprintf shall return NULL.] */
00168                     free(result);
00169                     result = NULL;
00170                     LogError("Failure: allocation failed.");
00171                 }
00172             }
00173             else
00174             {
00175                 LogError("Failure: allocation failed.");
00176             }
00177         }
00178         else if (length == 0)
00179         {
00180             result = (STRING*)STRING_new();
00181         }
00182         else
00183         {
00184             /* Codes_SRS_STRING_07_039: [If the parameter format is NULL then STRING_construct_sprintf shall return NULL.] */
00185             result = NULL;
00186             LogError("Failure: vsnprintf return 0 length");
00187         }
00188     }
00189     else
00190     {
00191         LogError("Failure: invalid argument.");
00192         result = NULL;
00193     }
00194     /* Codes_SRS_STRING_07_045: [STRING_construct_sprintf shall allocate a new string with the value of the specified printf formated const char. ] */
00195     return (STRING_HANDLE)result;
00196 }
00197 
00198 /*this function will return a new STRING with the memory for the actual string passed in as a parameter.*/
00199 /*return NULL if it fails.*/
00200 /* The supplied memory must have been allocated with malloc! */
00201 /* Codes_SRS_STRING_07_006: [STRING_new_with_memory shall return a STRING_HANDLE by using the supplied char* memory.] */
00202 STRING_HANDLE STRING_new_with_memory(const char* memory)
00203 {
00204     STRING* result;
00205     if (memory == NULL)
00206     {
00207         /* Codes_SRS_STRING_07_007: [STRING_new_with_memory shall return a NULL STRING_HANDLE if the supplied char* is NULL.] */
00208         result = NULL;
00209     }
00210     else
00211     {
00212         if ((result = (STRING*)malloc(sizeof(STRING))) != NULL)
00213         {
00214             result->s = (char*)memory;
00215         }
00216     }
00217     return (STRING_HANDLE)result;
00218 }
00219 
00220 /* Codes_SRS_STRING_07_008: [STRING_new_quoted shall return a valid STRING_HANDLE Copying the supplied const char* value surrounded by quotes.] */
00221 STRING_HANDLE STRING_new_quoted(const char* source)
00222 {
00223     STRING* result;
00224     if (source == NULL)
00225     {
00226         /* Codes_SRS_STRING_07_009: [STRING_new_quoted shall return a NULL STRING_HANDLE if the supplied const char* is NULL.] */
00227         result = NULL;
00228     }
00229     else if ((result = (STRING*)malloc(sizeof(STRING))) != NULL)
00230     {
00231         size_t sourceLength = strlen(source);
00232         if ((result->s = (char*)malloc(sourceLength + 3)) != NULL)
00233         {
00234             result->s[0] = '"';
00235             (void)memcpy(result->s + 1, source, sourceLength);
00236             result->s[sourceLength + 1] = '"';
00237             result->s[sourceLength + 2] = '\0';
00238         }
00239         else
00240         {
00241             /* Codes_SRS_STRING_07_031: [STRING_new_quoted shall return a NULL STRING_HANDLE if any error is encountered.] */
00242             free(result);
00243             result = NULL;
00244         }
00245     }
00246     return (STRING_HANDLE)result;
00247 }
00248 
00249 /*this function takes a regular const char* and turns in into "this is a\"JSON\" strings\u0008" (starting and ending quote included)*/
00250 /*the newly created handle needs to be disposed of with STRING_delete*/
00251 /*returns NULL if there are errors*/
00252 STRING_HANDLE STRING_new_JSON(const char* source)
00253 {
00254     STRING* result;
00255     if (source == NULL)
00256     {
00257         /*Codes_SRS_STRING_02_011: [If source is NULL then STRING_new_JSON shall return NULL.] */
00258         result = NULL;
00259         LogError("invalid arg (NULL)");
00260     }
00261     else
00262     {
00263         size_t i;
00264         size_t nControlCharacters = 0; /*counts how many characters are to be expanded from 1 character to \uxxxx (6 characters)*/
00265         size_t nEscapeCharacters = 0;
00266         size_t vlen = strlen(source);
00267 
00268         for (i = 0; i < vlen; i++)
00269         {
00270             /*Codes_SRS_STRING_02_014: [If any character has the value outside [1...127] then STRING_new_JSON shall fail and return NULL.] */
00271             if ((unsigned char)source[i] >= 128) /*this be a UNICODE character begin*/
00272             {
00273                 break;
00274             }
00275             else
00276             {
00277                 if (source[i] <= 0x1F)
00278                 {
00279                     nControlCharacters++;
00280                 }
00281                 else if (
00282                     (source[i] == '"') ||
00283                     (source[i] == '\\') ||
00284                     (source[i] == '/')
00285                     )
00286                 {
00287                     nEscapeCharacters++;
00288                 }
00289             }
00290         }
00291 
00292         if (i < vlen)
00293         {
00294             result = NULL;
00295             LogError("invalid character in input string");
00296         }
00297         else
00298         {
00299             if ((result = (STRING*)malloc(sizeof(STRING))) == NULL)
00300             {
00301                 /*Codes_SRS_STRING_02_021: [If the complete JSON representation cannot be produced, then STRING_new_JSON shall fail and return NULL.] */
00302                 LogError("malloc failure");
00303             }
00304             else if ((result->s = (char*)malloc(vlen + 5 * nControlCharacters + nEscapeCharacters + 3)) == NULL)
00305             {
00306                 /*Codes_SRS_STRING_02_021: [If the complete JSON representation cannot be produced, then STRING_new_JSON shall fail and return NULL.] */
00307                 free(result);
00308                 result = NULL;
00309                 LogError("malloc failed");
00310             }
00311             else
00312             {
00313                 size_t pos = 0;
00314                 /*Codes_SRS_STRING_02_012: [The string shall begin with the quote character.] */
00315                 result->s[pos++] = '"';
00316                 for (i = 0; i < vlen; i++)
00317                 {
00318                     if (source[i] <= 0x1F)
00319                     {
00320                         /*Codes_SRS_STRING_02_019: [If the character code is less than 0x20 then it shall be represented as \u00xx, where xx is the hex representation of the character code.]*/
00321                         result->s[pos++] = '\\';
00322                         result->s[pos++] = 'u';
00323                         result->s[pos++] = '0';
00324                         result->s[pos++] = '0';
00325                         result->s[pos++] = hexToASCII[(source[i] & 0xF0) >> 4]; /*high nibble*/
00326                         result->s[pos++] = hexToASCII[source[i] & 0x0F]; /*low nibble*/
00327                     }
00328                     else if (source[i] == '"')
00329                     {
00330                         /*Codes_SRS_STRING_02_016: [If the character is " (quote) then it shall be repsented as \".] */
00331                         result->s[pos++] = '\\';
00332                         result->s[pos++] = '"';
00333                     }
00334                     else if (source[i] == '\\')
00335                     {
00336                         /*Codes_SRS_STRING_02_017: [If the character is \ (backslash) then it shall represented as \\.] */
00337                         result->s[pos++] = '\\';
00338                         result->s[pos++] = '\\';
00339                     }
00340                     else if (source[i] == '/')
00341                     {
00342                         /*Codes_SRS_STRING_02_018: [If the character is / (slash) then it shall be represented as \/.] */
00343                         result->s[pos++] = '\\';
00344                         result->s[pos++] = '/';
00345                     }
00346                     else
00347                     {
00348                         /*Codes_SRS_STRING_02_013: [The string shall copy the characters of source "as they are" (until the '\0' character) with the following exceptions:] */
00349                         result->s[pos++] = source[i];
00350                     }
00351                 }
00352                 /*Codes_SRS_STRING_02_020: [The string shall end with " (quote).] */
00353                 result->s[pos++] = '"';
00354                 /*zero terminating it*/
00355                 result->s[pos] = '\0';
00356             }
00357         }
00358 
00359     }
00360     return (STRING_HANDLE)result;
00361 }
00362 
00363 /*this function will concatenate to the string s1 the string s2, resulting in s1+s2*/
00364 /*returns 0 if success*/
00365 /*any other error code is failure*/
00366 /* Codes_SRS_STRING_07_012: [STRING_concat shall concatenate the given STRING_HANDLE and the const char* value and place the value in the handle.] */
00367 int STRING_concat(STRING_HANDLE handle, const char* s2)
00368 {
00369     int result;
00370     if ((handle == NULL) || (s2 == NULL))
00371     {
00372         /* Codes_SRS_STRING_07_013: [STRING_concat shall return a nonzero number if an error is encountered.] */
00373         result = __FAILURE__;
00374     }
00375     else
00376     {
00377         STRING* s1 = (STRING*)handle;
00378         size_t s1Length = strlen(s1->s);
00379         size_t s2Length = strlen(s2);
00380         char* temp = (char*)realloc(s1->s, s1Length + s2Length + 1);
00381         if (temp == NULL)
00382         {
00383             /* Codes_SRS_STRING_07_013: [STRING_concat shall return a nonzero number if an error is encountered.] */
00384             result = __FAILURE__;
00385         }
00386         else
00387         {
00388             s1->s = temp;
00389             (void)memcpy(s1->s + s1Length, s2, s2Length + 1);
00390             result = 0;
00391         }
00392     }
00393     return result;
00394 }
00395 
00396 /*this function will concatenate to the string s1 the string s2, resulting in s1+s2*/
00397 /*returns 0 if success*/
00398 /*any other error code is failure*/
00399 /* Codes_SRS_STRING_07_034: [String_Concat_with_STRING shall concatenate a given STRING_HANDLE variable with a source STRING_HANDLE.] */
00400 int STRING_concat_with_STRING(STRING_HANDLE s1, STRING_HANDLE s2)
00401 {
00402     int result;
00403     if ((s1 == NULL) || (s2 == NULL))
00404     {
00405         /* Codes_SRS_STRING_07_035: [String_Concat_with_STRING shall return a nonzero number if an error is encountered.] */
00406         result = __FAILURE__;
00407     }
00408     else
00409     {
00410         STRING* dest = (STRING*)s1;
00411         STRING* src = (STRING*)s2;
00412 
00413         size_t s1Length = strlen(dest->s);
00414         size_t s2Length = strlen(src->s);
00415         char* temp = (char*)realloc(dest->s, s1Length + s2Length + 1);
00416         if (temp == NULL)
00417         {
00418             /* Codes_SRS_STRING_07_035: [String_Concat_with_STRING shall return a nonzero number if an error is encountered.] */
00419             result = __FAILURE__;
00420         }
00421         else
00422         {
00423             dest->s = temp;
00424             /* Codes_SRS_STRING_07_034: [String_Concat_with_STRING shall concatenate a given STRING_HANDLE variable with a source STRING_HANDLE.] */
00425             (void)memcpy(dest->s + s1Length, src->s, s2Length + 1);
00426             result = 0;
00427         }
00428     }
00429     return result;
00430 }
00431 
00432 /*this function will copy the string from s2 to s1*/
00433 /*returns 0 if success*/
00434 /*any other error code is failure*/
00435 /* Codes_SRS_STRING_07_016: [STRING_copy shall copy the const char* into the supplied STRING_HANDLE.] */
00436 int STRING_copy(STRING_HANDLE handle, const char* s2)
00437 {
00438     int result;
00439     if ((handle == NULL) || (s2 == NULL))
00440     {
00441         /* Codes_SRS_STRING_07_017: [STRING_copy shall return a nonzero value if any of the supplied parameters are NULL.] */
00442         result = __FAILURE__;
00443     }
00444     else
00445     {
00446         STRING* s1 = (STRING*)handle;
00447         /* Codes_SRS_STRING_07_026: [If the underlying char* refered to by s1 handle is equal to char* s2 than STRING_copy shall be a noop and return 0.] */
00448         if (s1->s != s2)
00449         {
00450             size_t s2Length = strlen(s2);
00451             char* temp = (char*)realloc(s1->s, s2Length + 1);
00452             if (temp == NULL)
00453             {
00454                 /* Codes_SRS_STRING_07_027: [STRING_copy shall return a nonzero value if any error is encountered.] */
00455                 result = __FAILURE__;
00456             }
00457             else
00458             {
00459                 s1->s = temp;
00460                 memmove(s1->s, s2, s2Length + 1);
00461                 result = 0;
00462             }
00463         }
00464         else
00465         {
00466             /* Codes_SRS_STRING_07_033: [If overlapping pointer address is given to STRING_copy the behavior is undefined.] */
00467             result = 0;
00468         }
00469     }
00470     return result;
00471 }
00472 
00473 /*this function will copy n chars from s2 to the string s1, resulting in n chars only from s2 being stored in s1.*/
00474 /*returns 0 if success*/
00475 /*any other error code is failure*/
00476 /* Codes_SRS_STRING_07_018: [STRING_copy_n shall copy the number of characters in const char* or the size_t whichever is lesser.] */
00477 int STRING_copy_n(STRING_HANDLE handle, const char* s2, size_t n)
00478 {
00479     int result;
00480     if ((handle == NULL) || (s2 == NULL))
00481     {
00482         /* Codes_SRS_STRING_07_019: [STRING_copy_n shall return a nonzero value if STRING_HANDLE or const char* is NULL.] */
00483         result = __FAILURE__;
00484     }
00485     else
00486     {
00487         STRING* s1 = (STRING*)handle;
00488         size_t s2Length = strlen(s2);
00489         char* temp;
00490         if (s2Length > n)
00491         {
00492             s2Length = n;
00493         }
00494 
00495         temp = (char*)realloc(s1->s, s2Length + 1);
00496         if (temp == NULL)
00497         {
00498             /* Codes_SRS_STRING_07_028: [STRING_copy_n shall return a nonzero value if any error is encountered.] */
00499             result = __FAILURE__;
00500         }
00501         else
00502         {
00503             s1->s = temp;
00504             (void)memcpy(s1->s, s2, s2Length);
00505             s1->s[s2Length] = 0;
00506             result = 0;
00507         }
00508 
00509     }
00510     return result;
00511 }
00512 
00513 #if defined(__GNUC__)
00514 __attribute__ ((format (printf, 2, 3)))
00515 #endif
00516 int STRING_sprintf(STRING_HANDLE handle, const char* format, ...)
00517 {
00518     int result;
00519     
00520 #ifdef ARDUINO_ARCH_ESP8266
00521     size_t maxBufSize = 512;
00522     char buf[512];
00523 #else
00524     size_t maxBufSize = 0;
00525     char* buf = NULL;
00526 #endif
00527     
00528     if (handle == NULL || format == NULL)
00529     {
00530         /* Codes_SRS_STRING_07_042: [if the parameters s1 or format are NULL then STRING_sprintf shall return non zero value.] */
00531         LogError("Invalid arg (NULL)");
00532         result = __FAILURE__;
00533     }
00534     else
00535     {
00536         va_list arg_list;
00537         int s2Length;
00538         va_start(arg_list, format);
00539 
00540         s2Length = vsnprintf(buf, maxBufSize, format, arg_list);
00541         va_end(arg_list);
00542         if (s2Length < 0)
00543         {
00544             /* Codes_SRS_STRING_07_043: [If any error is encountered STRING_sprintf shall return a non zero value.] */
00545             LogError("Failure vsnprintf return < 0");
00546             result = __FAILURE__;
00547         }
00548         else if (s2Length == 0)
00549         {
00550             // Don't need to reallocate and nothing should be added
00551             result = 0;
00552         }
00553         else
00554         {
00555             STRING* s1 = (STRING*)handle;
00556             char* temp;
00557             size_t s1Length = strlen(s1->s);
00558             temp = (char*)realloc(s1->s, s1Length + s2Length + 1);
00559             if (temp != NULL)
00560             {
00561                 s1->s = temp;
00562                 va_start(arg_list, format);
00563                 if (vsnprintf(s1->s + s1Length, s1Length + s2Length + 1, format, arg_list) < 0)
00564                 {
00565                     /* Codes_SRS_STRING_07_043: [If any error is encountered STRING_sprintf shall return a non zero value.] */
00566                     LogError("Failure vsnprintf formatting error");
00567                     s1->s[s1Length] = '\0';
00568                     result = __FAILURE__;
00569                 }
00570                 else
00571                 {
00572                     /* Codes_SRS_STRING_07_044: [On success STRING_sprintf shall return 0.]*/
00573                     result = 0;
00574                 }
00575                 va_end(arg_list);
00576             }
00577             else
00578             {
00579                 /* Codes_SRS_STRING_07_043: [If any error is encountered STRING_sprintf shall return a non zero value.] */
00580                 LogError("Failure unable to reallocate memory");
00581                 result = __FAILURE__;
00582             }
00583         }
00584     }
00585     return result;
00586 }
00587 
00588 /*this function will quote the string passed as argument string =>"string"*/
00589 /*returns 0 if success*/ /*doesn't change the string otherwise*/
00590 /*any other error code is failure*/
00591 /* Codes_SRS_STRING_07_014: [STRING_quote shall "quote" the supplied STRING_HANDLE and return 0 on success.] */
00592 int STRING_quote(STRING_HANDLE handle)
00593 {
00594     int result;
00595     if (handle == NULL)
00596     {
00597         /* Codes_SRS_STRING_07_015: [STRING_quote shall return a nonzero value if any of the supplied parameters are NULL.] */
00598         result = __FAILURE__;
00599     }
00600     else
00601     {
00602         STRING* s1 = (STRING*)handle;
00603         size_t s1Length = strlen(s1->s);
00604         char* temp = (char*)realloc(s1->s, s1Length + 2 + 1);/*2 because 2 quotes, 1 because '\0'*/
00605         if (temp == NULL)
00606         {
00607             /* Codes_SRS_STRING_07_029: [STRING_quote shall return a nonzero value if any error is encountered.] */
00608             result = __FAILURE__;
00609         }
00610         else
00611         {
00612             s1->s = temp;
00613             memmove(s1->s + 1, s1->s, s1Length);
00614             s1->s[0] = '"';
00615             s1->s[s1Length + 1] = '"';
00616             s1->s[s1Length + 2] = '\0';
00617             result = 0;
00618         }
00619     }
00620     return result;
00621 }
00622 /*this function will revert a string to an empty state*/
00623 /*Returns 0 if the revert was succesful*/
00624 /* Codes_SRS_STRING_07_022: [STRING_empty shall revert the STRING_HANDLE to an empty state.] */
00625 int STRING_empty(STRING_HANDLE handle)
00626 {
00627     int result;
00628     if (handle == NULL)
00629     {
00630         /* Codes_SRS_STRING_07_023: [STRING_empty shall return a nonzero value if the STRING_HANDLE is NULL.] */
00631         result = __FAILURE__;
00632     }
00633     else
00634     {
00635         STRING* s1 = (STRING*)handle;
00636         char* temp = (char*)realloc(s1->s, 1);
00637         if (temp == NULL)
00638         {
00639             /* Codes_SRS_STRING_07_030: [STRING_empty shall return a nonzero value if the STRING_HANDLE is NULL.] */
00640             result = __FAILURE__;
00641         }
00642         else
00643         {
00644             s1->s = temp;
00645             s1->s[0] = '\0';
00646             result = 0;
00647         }
00648     }
00649     return result;
00650 }
00651 
00652 /*this function will deallocate a string constructed by str_new*/
00653 /* Codes_SRS_STRING_07_010: [STRING_delete will free the memory allocated by the STRING_HANDLE.] */
00654 void STRING_delete(STRING_HANDLE handle)
00655 {
00656     /* Codes_SRS_STRING_07_011: [STRING_delete will not attempt to free anything with a NULL STRING_HANDLE.] */
00657     if (handle != NULL)
00658     {
00659         STRING* value = (STRING*)handle;
00660         free(value->s);
00661         value->s = NULL;
00662         free(value);
00663     }
00664 }
00665 
00666 /* Codes_SRS_STRING_07_020: [STRING_c_str shall return the const char* associated with the given STRING_HANDLE.] */
00667 const char* STRING_c_str(STRING_HANDLE handle)
00668 {
00669     const char* result;
00670     if (handle != NULL)
00671     {
00672         result = ((STRING*)handle)->s;
00673     }
00674     else
00675     {
00676         /* Codes_SRS_STRING_07_021: [STRING_c_str shall return NULL if the STRING_HANDLE is NULL.] */
00677         result = NULL;
00678     }
00679     return result;
00680 }
00681 
00682 /* Codes_SRS_STRING_07_024: [STRING_length shall return the length of the underlying char* for the given handle] */
00683 size_t STRING_length(STRING_HANDLE handle)
00684 {
00685     size_t result = 0;
00686     /* Codes_SRS_STRING_07_025: [STRING_length shall return zero if the given handle is NULL.] */
00687     if (handle != NULL)
00688     {
00689         STRING* value = (STRING*)handle;
00690         result = strlen(value->s);
00691     }
00692     return result;
00693 }
00694 
00695 /*Codes_SRS_STRING_02_007: [STRING_construct_n shall construct a STRING_HANDLE from first "n" characters of the string pointed to by psz parameter.]*/
00696 STRING_HANDLE STRING_construct_n(const char* psz, size_t n)
00697 {
00698     STRING_HANDLE result;
00699     /*Codes_SRS_STRING_02_008: [If psz is NULL then STRING_construct_n shall return NULL.] */
00700     if (psz == NULL)
00701     {
00702         result = NULL;
00703         LogError("invalid arg (NULL)");
00704     }
00705     else
00706     {
00707         size_t len = strlen(psz);
00708         /*Codes_SRS_STRING_02_009: [If n is bigger than the size of the string psz, then STRING_construct_n shall return NULL.] */
00709         if (n > len)
00710         {
00711             result = NULL;
00712             LogError("invalig arg (n is bigger than the size of the string)");
00713         }
00714         else
00715         {
00716             STRING* str;
00717             if ((str = (STRING*)malloc(sizeof(STRING))) != NULL)
00718             {
00719                 if ((str->s = (char*)malloc(len + 1)) != NULL)
00720                 {
00721                     (void)memcpy(str->s, psz, n);
00722                     str->s[n] = '\0';
00723                     result = (STRING_HANDLE)str;
00724                 }
00725                 /* Codes_SRS_STRING_02_010: [In all other error cases, STRING_construct_n shall return NULL.]  */
00726                 else
00727                 {
00728                     free(str);
00729                     result = NULL;
00730                 }
00731             }
00732             else
00733             {
00734                 /* Codes_SRS_STRING_02_010: [In all other error cases, STRING_construct_n shall return NULL.]  */
00735                 result = NULL;
00736             }
00737         }
00738     }
00739     return result;
00740 }
00741 
00742 /* Codes_SRS_STRING_07_034: [STRING_compare returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string s2.] */
00743 int STRING_compare(STRING_HANDLE s1, STRING_HANDLE s2)
00744 {
00745     int result;
00746     if (s1 == NULL && s2 == NULL)
00747     {
00748         /* Codes_SRS_STRING_07_035: [If h1 and h2 are both NULL then STRING_compare shall return 0.]*/
00749         result = 0;
00750     }
00751     else if (s1 == NULL)
00752     {
00753         /* Codes_SRS_STRING_07_036: [If h1 is NULL and h2 is nonNULL then STRING_compare shall return 1.]*/
00754         result = 1;
00755     }
00756     else if (s2 == NULL)
00757     {
00758         /* Codes_SRS_STRING_07_037: [If h2 is NULL and h1 is nonNULL then STRING_compare shall return -1.] */
00759         result = -1;
00760     }
00761     else
00762     {
00763         /* Codes_SRS_STRING_07_038: [STRING_compare shall compare the char s variable using the strcmp function.] */
00764         STRING* value1 = (STRING*)s1;
00765         STRING* value2 = (STRING*)s2;
00766         result = strcmp(value1->s, value2->s);
00767     }
00768     return result;
00769 }
00770 
00771 STRING_HANDLE STRING_from_byte_array(const unsigned char* source, size_t size)
00772 {
00773     STRING* result;
00774     /*Codes_SRS_STRING_02_022: [ If source is NULL and size > 0 then STRING_from_BUFFER shall fail and return NULL. ]*/
00775     if ((source == NULL) && (size > 0))
00776     {
00777         LogError("invalid parameter (NULL)");
00778         result = NULL;
00779     }
00780     else
00781     {
00782         /*Codes_SRS_STRING_02_023: [ Otherwise, STRING_from_BUFFER shall build a string that has the same content (byte-by-byte) as source and return a non-NULL handle. ]*/
00783         result = (STRING*)malloc(sizeof(STRING));
00784         if (result == NULL)
00785         {
00786             /*Codes_SRS_STRING_02_024: [ If building the string fails, then STRING_from_BUFFER shall fail and return NULL. ]*/
00787             LogError("oom - unable to malloc");
00788             /*return as is*/
00789         }
00790         else
00791         {
00792             /*Codes_SRS_STRING_02_023: [ Otherwise, STRING_from_BUFFER shall build a string that has the same content (byte-by-byte) as source and return a non-NULL handle. ]*/
00793             result->s = (char*)malloc(size + 1);
00794             if (result->s == NULL)
00795             {
00796                 /*Codes_SRS_STRING_02_024: [ If building the string fails, then STRING_from_BUFFER shall fail and return NULL. ]*/
00797                 LogError("oom - unable to malloc");
00798                 free(result);
00799                 result = NULL;
00800             }
00801             else
00802             {
00803                 (void)memcpy(result->s, source, size);
00804                 result->s[size] = '\0'; /*all is fine*/
00805             }
00806         }
00807     }
00808     return (STRING_HANDLE)result;
00809 }
00810 
00811 int STRING_replace(STRING_HANDLE handle, char target, char replace)
00812 {
00813     int result;
00814     if (handle == NULL)
00815     {
00816         /* Codes_SRS_STRING_07_046: [ If handle is NULL STRING_replace shall return a non-zero value. ] */
00817         result = __FAILURE__;
00818     }
00819     else if (target == replace)
00820     {
00821         /* Codes_SRS_STRING_07_048: [ If target and replace are equal STRING_replace, shall do nothing shall return zero. ] */
00822         result = 0;
00823     }
00824     else
00825     {
00826         size_t length;
00827         size_t index;
00828         /* Codes_SRS_STRING_07_047: [ STRING_replace shall replace all instances of target with replace. ] */
00829         STRING* str_value = (STRING*)handle;
00830         length = strlen(str_value->s);
00831         for (index = 0; index < length; index++)
00832         {
00833             if (str_value->s[index] == target)
00834             {
00835                 str_value->s[index] = replace;
00836             }
00837         }
00838         /* Codes_SRS_STRING_07_049: [ On success STRING_replace shall return zero. ] */
00839         result = 0;
00840     }
00841     return result;
00842 }