Azure IoT / azure_c_shared_utility

Dependents:   STM32F746_iothub_client_sample_mqtt f767zi_mqtt iothub_client_sample_amqp iothub_client_sample_http ... more

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