You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							286 lines
						
					
					
						
							5.2 KiB
						
					
					
				
			
		
		
	
	
							286 lines
						
					
					
						
							5.2 KiB
						
					
					
				| #include "str_utils.h"
 | |
| #include "matcher.h"
 | |
| #include "malloc_safe.h"
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <stdint.h>
 | |
| 
 | |
| // Lot of this stuff is actually not needed anymore,
 | |
| // it was written for the ESP AT firmware, which is no longer used.
 | |
| 
 | |
| /**
 | |
|  * Escape a char.
 | |
|  * @returns what to put after backslash, or '\0' for no escape.
 | |
|  */
 | |
| static char escape_char(char c)
 | |
| {
 | |
| 	switch (c) {
 | |
| 		case '\r': return 'r';
 | |
| 		case '\n': return 'n';
 | |
| 		case '\t': return 't';
 | |
| 		case '\\': return '\\';
 | |
| 		default: return 0;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Escape string in place
 | |
|  */
 | |
| void str_escape_ip(char * buf, size_t buf_len)
 | |
| {
 | |
| 	size_t i = 0;
 | |
| 
 | |
| 	// string length (updated when escapes are performed)
 | |
| 	size_t slen = strlen(buf);
 | |
| 
 | |
| 	for (; i < buf_len - 1 && buf[i] != 0; i++) {
 | |
| 		char replace = escape_char(buf[i]);
 | |
| 
 | |
| 		// Escape, shift trailing chars
 | |
| 		if (replace != 0) {
 | |
| 			if (i >= buf_len - 2) {
 | |
| 				break; // discard the char, escape wouldn't fit.
 | |
| 			}
 | |
| 
 | |
| 			// (could be faster if moved starting at the end)
 | |
| 
 | |
| 			char m = buf[i + 1]; // remember next char
 | |
| 
 | |
| 			buf[i] = '\\';
 | |
| 			buf[i + 1] = replace;
 | |
| 
 | |
| 			slen++; // account for the added backslash
 | |
| 
 | |
| 			// shift trailing chars
 | |
| 			for (size_t j = i + 2; j <= slen; j++) {
 | |
| 				char n = buf[j];
 | |
| 				buf[j] = m;
 | |
| 				m = n;
 | |
| 			}
 | |
| 
 | |
| 			i++; // skip the insterted slash
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	buf[i] = 0; // add terminator (in case end of string was reached)
 | |
| }
 | |
| 
 | |
| 
 | |
| void str_escape(char *dest, const char *src, size_t dest_len)
 | |
| {
 | |
| 	size_t di = 0, si = 0;
 | |
| 
 | |
| 	for (; src[si] != 0 && di < dest_len - 1; si++) {
 | |
| 		char orig = src[si];
 | |
| 		char replace = escape_char(orig);
 | |
| 
 | |
| 		if (replace == 0) {
 | |
| 			dest[di++] = orig;
 | |
| 		} else {
 | |
| 			if (di >= dest_len - 2) {
 | |
| 				break; // out of space
 | |
| 			}
 | |
| 
 | |
| 			dest[di++] = '\\';
 | |
| 			dest[di++] = replace;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	dest[di] = 0; // append terminator
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| int32_t strpos(const char *haystack, const char *needle)
 | |
| {
 | |
| 	const char *p = strstr(haystack, needle);
 | |
| 	if (p) return (p - haystack);
 | |
| 	return -1;   // Not found = -1.
 | |
| }
 | |
| 
 | |
| 
 | |
| int32_t strpos_upto(const char *haystack, const char *needle, size_t limit)
 | |
| {
 | |
| 	if (limit <= 0) return strpos(haystack, needle);
 | |
| 
 | |
| 	matcher_t m = {needle, 0};
 | |
| 	char c;
 | |
| 
 | |
| 	for (size_t i = 0; i < limit; i++, haystack++) {
 | |
| 		c = *haystack;
 | |
| 		if (c == 0) break;
 | |
| 
 | |
| 		if (matcher_test(&m, (uint8_t)c)) {
 | |
| 			return i - strlen(needle) + 1; // match occured on the last needle char
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| 
 | |
| int32_t strpos_upto_match(const char *haystack, const char *needle, const char *endmatch)
 | |
| {
 | |
| 	if (endmatch == NULL) return strpos(haystack, needle);
 | |
| 
 | |
| 	matcher_t matcher_needle = {needle, 0};
 | |
| 	matcher_t matcher_end = {endmatch, 0};
 | |
| 	char c;
 | |
| 
 | |
| 	for (int i = 0;; i++, haystack++) {
 | |
| 		c = *haystack;
 | |
| 		if (c == 0) break;
 | |
| 
 | |
| 		// match
 | |
| 		if (matcher_test(&matcher_needle, (uint8_t)c)) {
 | |
| 			return i - strlen(needle) + 1; // match occured on the last needle char
 | |
| 		}
 | |
| 
 | |
| 		// end
 | |
| 		if (matcher_test(&matcher_end, (uint8_t)c)) {
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| size_t str_copy(char * dest, const char *src)
 | |
| {
 | |
| 	char c;
 | |
| 	size_t i = 0;
 | |
| 	while ((c = *src++) != 0) {
 | |
| 		*dest++ = c;
 | |
| 		i++;
 | |
| 	}
 | |
| 	return i;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Decode URL-encoded string in place.
 | |
|  */
 | |
| void urldecode_ip(char *str)
 | |
| {
 | |
| 	unsigned int x;
 | |
| 
 | |
| 	for (size_t i = 0; str[i] != 0; i++) {
 | |
| 		char c = str[i];
 | |
| 		if (c == '+') {
 | |
| 			str[i] = ' ';
 | |
| 		} else if (c == '%') {
 | |
| 			// decode the byte
 | |
| 			sscanf(&str[i + 1], "%02x", &x);
 | |
| 			str[i] = (char)x;
 | |
| 
 | |
| 			// shift following chars
 | |
| 			for (size_t a = i + 3, b = i + 1;; a++, b++) {
 | |
| 				str[b] = str[a]; // move
 | |
| 				if (str[a] == 0) break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * url-decode string, put output in a buffer.
 | |
|  */
 | |
| void urldecode(char *dest, const char *src)
 | |
| {
 | |
| 	unsigned int x;
 | |
| 	size_t si = 0, di = 0;
 | |
| 
 | |
| 	for (; src[si] != 0; si++) {
 | |
| 		char c = src[si];
 | |
| 		if (c == '+') {
 | |
| 			dest[di++] = ' ';
 | |
| 		} else if (c == '%') {
 | |
| 			// decode the byte
 | |
| 			sscanf(&src[si + 1], "%02x", &x);
 | |
| 			dest[di++] = (char)x;
 | |
| 
 | |
| 			si += 2;
 | |
| 		} else {
 | |
| 			dest[di++] = c;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// add terminator
 | |
| 	dest[di] = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * url-decode string, put output in a buffer.
 | |
|  * Limit operation to N chars in input string
 | |
|  */
 | |
| void urldecode_n(char *dest, const char *src, size_t count)
 | |
| {
 | |
| 	unsigned int x;
 | |
| 	size_t si = 0, di = 0;
 | |
| 
 | |
| 	for (; src[si] != 0 && si < count; si++) {
 | |
| 		char c = src[si];
 | |
| 		if (c == '+') {
 | |
| 			dest[di++] = ' ';
 | |
| 		} else if (c == '%') {
 | |
| 			// decode the byte
 | |
| 			sscanf(&src[si + 1], "%02x", &x);
 | |
| 			dest[di++] = (char)x;
 | |
| 
 | |
| 			si += 2;
 | |
| 		} else {
 | |
| 			dest[di++] = c;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// add terminator
 | |
| 	dest[di] = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool get_query_value(char *buffer, const char *querystring, const char *key, size_t buf_len)
 | |
| {
 | |
| 	bool retval;
 | |
| 
 | |
| 	size_t qs_len = strlen(querystring);
 | |
| 
 | |
| 	char *ptrn = malloc_s(strlen(key) + 3); // &key=\0
 | |
| 	sprintf(ptrn, "&%s=", key);
 | |
| 	matcher_t m = {ptrn, 1}; // pretend ampersand was already matched
 | |
| 
 | |
| 	for (size_t i = 0; i < qs_len; i++) {
 | |
| 		char c = querystring[i];
 | |
| 		if (matcher_test(&m, (uint8_t)c)) {
 | |
| 			// found the match
 | |
| 			i++; // advance past the equals sign
 | |
| 
 | |
| 			size_t seg_end = i;
 | |
| 			while (seg_end < qs_len && querystring[seg_end] != '&') {
 | |
| 				seg_end++;
 | |
| 			}
 | |
| 
 | |
| 			if (seg_end - i > buf_len) seg_end = i + buf_len;
 | |
| 
 | |
| 			if (seg_end == i) {
 | |
| 				buffer[0] = 0; // strncpy behaves strange with length 0
 | |
| 			} else {
 | |
| 				urldecode_n(buffer, querystring + i, seg_end - i);
 | |
| 			}
 | |
| 
 | |
| 			retval = true;
 | |
| 			goto done;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// not found
 | |
| 	retval = false;
 | |
| done:
 | |
| 	free(ptrn);
 | |
| 	return retval;
 | |
| }
 | |
| 
 |