source: azure_iot_hub/trunk/azure_iothub/c-utility/src/urlencode.c@ 389

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

ビルドが通るよう更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 9.4 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdlib.h>
5#include <stddef.h>
6#include <string.h>
7#include "azure_c_shared_utility/gballoc.h"
8#include "azure_c_shared_utility/urlencode.h"
9#include "azure_c_shared_utility/xlogging.h"
10#include "azure_c_shared_utility/strings.h"
11#include "azure_c_shared_utility/crt_abstractions.h"
12
13#define NIBBLE_TO_STRING(c) (char)((c) < 10 ? (c) + '0' : (c) - 10 + 'a')
14#define NIBBLE_FROM_STRING(c) (char)(ISDIGIT(c) ? (c) - '0' : TOUPPER(c) + 10 - 'A')
15#define IS_HEXDIGIT(c) ( \
16 ((c >= '0') && (c <= '9')) || \
17 ((c >= 'A') && (c <= 'F')) || \
18 ((c >= 'a') && (c <= 'f')) \
19)
20#define IS_PRINTABLE(c) ( \
21 (c == 0) || \
22 (c == '!') || \
23 (c == '(') || (c == ')') || (c == '*') || \
24 (c == '-') || (c == '.') || \
25 ((c >= '0') && (c <= '9')) || \
26 ((c >= 'A') && (c <= 'Z')) || \
27 (c == '_') || \
28 ((c >= 'a') && (c <= 'z')) \
29)
30
31/*The below macros are to be called on the big nibble of a hex value*/
32#define IS_IN_ASCII_RANGE(c) ( \
33 (c >= '0') && (c <= '7') \
34)
35#define IS_IN_EXTENDED_ASCII_RANGE(c) ( \
36 ((c >= '8') && (c <= '9')) || \
37 ((c >= 'A') && (c <= 'F')) || \
38 ((c >= 'a') && (c <= 'f')) \
39)
40#define IS_IN_CONTINUATION_BYTE_RANGE(c) ( \
41 (c == '8') || (c == '9') || \
42 (c == 'A') || (c == 'B') || \
43 (c == 'a') || (c == 'b') \
44)
45#define IS_IN_LEADING_BYTE_RANGE(c) ( \
46 ((c >= 'C') && (c <= 'F')) || \
47 ((c >= 'c') && (c <= 'f')) \
48)
49#define IS_IN_UNSUPPORTED_LEADING_BYTE_RANGE(c) ( \
50 ((c >= 'D') && (c <= 'F')) || \
51 ((c >= 'd') && (c <= 'f')) \
52)
53
54static size_t URL_PrintableChar(unsigned char charVal, char* buffer)
55{
56 size_t size;
57 if (IS_PRINTABLE(charVal))
58 {
59 buffer[0] = (char)charVal;
60 size = 1;
61 }
62 else
63 {
64 char bigNibbleStr;
65 char littleNibbleStr;
66 unsigned char bigNibbleVal = charVal >> 4;
67 unsigned char littleNibbleVal = charVal & 0x0F;
68
69 if (bigNibbleVal >= 0x0C)
70 {
71 bigNibbleVal -= 0x04;
72 }
73
74 bigNibbleStr = NIBBLE_TO_STRING(bigNibbleVal);
75 littleNibbleStr = NIBBLE_TO_STRING(littleNibbleVal);
76
77 buffer[0] = '%';
78
79 if (charVal < 0x80)
80 {
81 buffer[1] = bigNibbleStr;
82 buffer[2] = littleNibbleStr;
83 size = 3;
84 }
85 else
86 {
87 buffer[1] = 'c';
88 buffer[3] = '%';
89 buffer[4] = bigNibbleStr;
90 buffer[5] = littleNibbleStr;
91 if (charVal < 0xC0)
92 {
93 buffer[2] = '2';
94 }
95 else
96 {
97 buffer[2] = '3';
98 }
99 size = 6;
100 }
101 }
102
103 return size;
104}
105
106static size_t calculateDecodedStringSize(const char* encodedString, size_t len)
107{
108 size_t decodedSize = 0;
109
110 if (encodedString == NULL)
111 {
112 LogError("Null encoded string");
113 }
114 else if (len == 0)
115 {
116 decodedSize = 1; //for null terminator
117 }
118 else
119 {
120 size_t remaining_len = len;
121 size_t next_step = 0;
122 size_t i = 0;
123 while (i < len)
124 {
125 //percent encoded character
126 if (encodedString[i] == '%')
127 {
128 if (remaining_len < 3 || !IS_HEXDIGIT(encodedString[i+1]) || !IS_HEXDIGIT(encodedString[i+2]))
129 {
130 LogError("Incomplete or invalid percent encoding");
131 break;
132 }
133 else if (!IS_IN_ASCII_RANGE(encodedString[i+1]))
134 {
135 LogError("Out of range of characters accepted by this decoder");
136 break;
137 }
138 else
139 {
140 decodedSize++;
141 next_step = 3;
142 }
143 }
144 else if (!IS_PRINTABLE(encodedString[i]))
145 {
146 LogError("Unprintable value in encoded string");
147 break;
148 }
149 //safe character
150 else
151 {
152 decodedSize++;
153 next_step = 1;
154 }
155
156 i += next_step;
157 remaining_len -= next_step;
158 }
159
160 if (encodedString[i] != '\0') //i.e. broke out of above loop due to error
161 {
162 decodedSize = 0;
163 }
164 else
165 {
166 decodedSize++; //add space for the null terminator
167 }
168 }
169 return decodedSize;
170}
171
172static unsigned char charFromNibbles(char bigNibbleStr, char littleNibbleStr)
173{
174 unsigned char bigNibbleVal = NIBBLE_FROM_STRING(bigNibbleStr);
175 unsigned char littleNibbleVal = NIBBLE_FROM_STRING(littleNibbleStr);
176
177 return bigNibbleVal << 4 | littleNibbleVal;
178}
179
180static void createDecodedString(const char* input, size_t input_size, char* output)
181{
182 /* Note that there is no danger of reckless indexing here, as calculateDecodedStringSize()
183 has already checked lengths of strings to ensure the formatting is always correct*/
184 size_t i = 0;
185 while (i <= input_size) //the <= instead of < ensures the '\0' will be copied
186 {
187 if (input[i] != '%')
188 {
189 *output++ = input[i];
190 i++;
191 }
192 else
193 {
194 *output++ = charFromNibbles(input[i+1], input[i+2]);
195 i += 3;
196 }
197 }
198}
199
200static size_t URL_PrintableCharSize(unsigned char charVal)
201{
202 size_t size;
203 if (IS_PRINTABLE(charVal))
204 {
205 size = 1;
206 }
207 else
208 {
209 if (charVal < 0x80)
210 {
211 size = 3;
212 }
213 else
214 {
215 size = 6;
216 }
217 }
218 return size;
219}
220
221static STRING_HANDLE encode_url_data(const char* text)
222{
223 STRING_HANDLE result;
224 size_t lengthOfResult = 0;
225 char* encodedURL;
226 unsigned char currentUnsignedChar;
227 const char* iterator = text;
228
229 /*Codes_SRS_URL_ENCODE_06_003: [If input is a zero length string then URL_Encode will return a zero length string.]*/
230 do
231 {
232 currentUnsignedChar = (unsigned char)(*iterator++);
233 lengthOfResult += URL_PrintableCharSize(currentUnsignedChar);
234 } while (currentUnsignedChar != 0);
235
236 if ((encodedURL = (char*)malloc(lengthOfResult)) == NULL)
237 {
238 /*Codes_SRS_URL_ENCODE_06_002: [If an error occurs during the encoding of input then URL_Encode will return NULL.]*/
239 result = NULL;
240 LogError("URL_Encode:: MALLOC failure on encode.");
241 }
242 else
243 {
244 size_t currentEncodePosition = 0;
245 iterator = text;;
246 do
247 {
248 currentUnsignedChar = (unsigned char)(*iterator++);
249 currentEncodePosition += URL_PrintableChar(currentUnsignedChar, &encodedURL[currentEncodePosition]);
250 } while (currentUnsignedChar != 0);
251
252 result = STRING_new_with_memory(encodedURL);
253 if (result == NULL)
254 {
255 LogError("URL_Encode:: MALLOC failure on encode.");
256 free(encodedURL);
257 }
258 }
259 return result;
260}
261
262STRING_HANDLE URL_EncodeString(const char* textEncode)
263{
264 STRING_HANDLE result;
265 if (textEncode == NULL)
266 {
267 result = NULL;
268 }
269 else
270 {
271 result = encode_url_data(textEncode);
272 }
273 return result;
274}
275
276STRING_HANDLE URL_Encode(STRING_HANDLE input)
277{
278 STRING_HANDLE result;
279 if (input == NULL)
280 {
281 /*Codes_SRS_URL_ENCODE_06_001: [If input is NULL then URL_Encode will return NULL.]*/
282 result = NULL;
283 LogError("URL_Encode:: NULL input");
284 }
285 else
286 {
287 result = encode_url_data(STRING_c_str(input));
288 }
289 return result;
290}
291
292STRING_HANDLE URL_DecodeString(const char* textDecode)
293{
294 STRING_HANDLE result;
295 if (textDecode == NULL)
296 {
297 result = NULL;
298 }
299 else
300 {
301 STRING_HANDLE tempString = STRING_construct(textDecode);
302 if (tempString == NULL)
303 {
304 result = NULL;
305 }
306 else
307 {
308 result = URL_Decode(tempString);
309 STRING_delete(tempString);
310 }
311 }
312 return result;
313}
314
315STRING_HANDLE URL_Decode(STRING_HANDLE input)
316{
317 STRING_HANDLE result;
318 if (input == NULL)
319 {
320 LogError("URL_Decode:: NULL input");
321 result = NULL;
322 }
323 else
324 {
325 size_t decodedStringSize;
326 char* decodedString;
327 const char* inputString = STRING_c_str(input);
328 size_t inputLen = strlen(inputString);
329 if ((decodedStringSize = calculateDecodedStringSize(inputString, inputLen)) == 0)
330 {
331 LogError("URL_Decode:: Invalid input string");
332 result = NULL;
333 }
334 else if ((decodedString = (char*)malloc(decodedStringSize)) == NULL)
335 {
336 LogError("URL_Decode:: MALLOC failure on decode.");
337 result = NULL;
338 }
339 else
340 {
341 createDecodedString(inputString, inputLen, decodedString);
342 result = STRING_new_with_memory(decodedString);
343 if (result == NULL)
344 {
345 LogError("URL_Decode:: MALLOC failure on decode");
346 free(decodedString);
347 }
348 }
349 }
350 return result;
351}
Note: See TracBrowser for help on using the repository browser.