mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Added fallbacks strlen_P, strncmp_P, strcmp_P and memcpy_P (fixes #1073)
This commit is contained in:
		| @@ -1,6 +1,11 @@ | ||||
| ArduinoJson: change log | ||||
| ======================= | ||||
|  | ||||
| HEAD | ||||
| ---- | ||||
|  | ||||
| * Added fallback implementations of `strlen_P()`, `strncmp_P()`, `strcmp_P()`, and `memcpy_P()` (issue #1073) | ||||
|  | ||||
| v6.11.4 (2019-08-12) | ||||
| ------- | ||||
|  | ||||
|   | ||||
| @@ -15,7 +15,7 @@ class UnsafeFlashStringReader { | ||||
|       : _ptr(reinterpret_cast<const char*>(ptr)) {} | ||||
|  | ||||
|   int read() { | ||||
|     return pgm_read_byte_near(_ptr++); | ||||
|     return pgm_read_byte(_ptr++); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| @@ -29,7 +29,7 @@ class SafeFlashStringReader { | ||||
|  | ||||
|   int read() { | ||||
|     if (_ptr < _end) | ||||
|       return pgm_read_byte_near(_ptr++); | ||||
|       return pgm_read_byte(_ptr++); | ||||
|     else | ||||
|       return -1; | ||||
|   } | ||||
|   | ||||
							
								
								
									
										62
									
								
								src/ArduinoJson/Polyfills/pgmspace.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/ArduinoJson/Polyfills/pgmspace.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2019 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
| // Wraps a const char* so that the our functions are picked only if the | ||||
| // originals are missing | ||||
| struct pgm_p { | ||||
|   pgm_p(const char* p) : address(p) {} | ||||
|   const char* address; | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|  | ||||
| #ifndef strlen_P | ||||
| inline size_t strlen_P(ARDUINOJSON_NAMESPACE::pgm_p s) { | ||||
|   const char* p = s.address; | ||||
|   while (pgm_read_byte(p)) p++; | ||||
|   return size_t(p - s.address); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #ifndef strncmp_P | ||||
| inline int strncmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) { | ||||
|   const char* s1 = a; | ||||
|   const char* s2 = b.address; | ||||
|   while (n-- > 0) { | ||||
|     char c1 = *s1++; | ||||
|     char c2 = static_cast<char>(pgm_read_byte(s2++)); | ||||
|     if (c1 < c2) return -1; | ||||
|     if (c1 > c2) return 1; | ||||
|     if (c1 == 0 /* and c2 as well */) return 0; | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #ifndef strcmp_P | ||||
| inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) { | ||||
|   const char* s1 = a; | ||||
|   const char* s2 = b.address; | ||||
|   for (;;) { | ||||
|     char c1 = *s1++; | ||||
|     char c2 = static_cast<char>(pgm_read_byte(s2++)); | ||||
|     if (c1 < c2) return -1; | ||||
|     if (c1 > c2) return 1; | ||||
|     if (c1 == 0 /* and c2 as well */) return 0; | ||||
|   } | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #ifndef memcpy_P | ||||
| inline void* memcpy_P(void* dst, ARDUINOJSON_NAMESPACE::pgm_p src, size_t n) { | ||||
|   uint8_t* d = reinterpret_cast<uint8_t*>(dst); | ||||
|   const char* s = src.address; | ||||
|   while (n-- > 0) { | ||||
|     *d++ = pgm_read_byte(s++); | ||||
|   } | ||||
|   return dst; | ||||
| } | ||||
| #endif | ||||
| @@ -4,6 +4,8 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Polyfills/pgmspace.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class FlashStringAdapter { | ||||
|   | ||||
| @@ -51,3 +51,37 @@ TEST_CASE("Flash strings") { | ||||
|     REQUIRE(doc[0] == F("world")); | ||||
|   } | ||||
| } | ||||
|  | ||||
| TEST_CASE("strlen_P") { | ||||
|   CHECK(strlen_P(FC("")) == 0); | ||||
|   CHECK(strlen_P(FC("a")) == 1); | ||||
|   CHECK(strlen_P(FC("ac")) == 2); | ||||
| } | ||||
|  | ||||
| TEST_CASE("strncmp_P") { | ||||
|   CHECK(strncmp_P("a", FC("b"), 0) == 0); | ||||
|   CHECK(strncmp_P("a", FC("b"), 1) == -1); | ||||
|   CHECK(strncmp_P("b", FC("a"), 1) == 1); | ||||
|   CHECK(strncmp_P("a", FC("a"), 0) == 0); | ||||
|   CHECK(strncmp_P("a", FC("b"), 2) == -1); | ||||
|   CHECK(strncmp_P("b", FC("a"), 2) == 1); | ||||
|   CHECK(strncmp_P("a", FC("a"), 2) == 0); | ||||
| } | ||||
|  | ||||
| TEST_CASE("strcmp_P") { | ||||
|   CHECK(strcmp_P("a", FC("b")) == -1); | ||||
|   CHECK(strcmp_P("b", FC("a")) == 1); | ||||
|   CHECK(strcmp_P("a", FC("a")) == 0); | ||||
|   CHECK(strcmp_P("aa", FC("ab")) == -1); | ||||
|   CHECK(strcmp_P("ab", FC("aa")) == 1); | ||||
|   CHECK(strcmp_P("aa", FC("aa")) == 0); | ||||
| } | ||||
|  | ||||
| TEST_CASE("memcpy_P") { | ||||
|   char dst[4]; | ||||
|   CHECK(memcpy_P(dst, FC("ABC"), 4) == dst); | ||||
|   CHECK(dst[0] == 'A'); | ||||
|   CHECK(dst[1] == 'B'); | ||||
|   CHECK(dst[2] == 'C'); | ||||
|   CHECK(dst[3] == 0); | ||||
| } | ||||
|   | ||||
| @@ -7,9 +7,6 @@ | ||||
|  | ||||
| class __FlashStringHelper; | ||||
|  | ||||
| typedef char prog_char; | ||||
| typedef void prog_void; | ||||
|  | ||||
| inline const void* convertPtrToFlash(const void* s) { | ||||
|   return reinterpret_cast<const char*>(s) + 42; | ||||
| } | ||||
| @@ -19,23 +16,8 @@ inline const void* convertFlashToPtr(const void* s) { | ||||
| } | ||||
|  | ||||
| #define F(X) reinterpret_cast<const __FlashStringHelper*>(convertPtrToFlash(X)) | ||||
| #define FC(X) reinterpret_cast<const char*>(convertPtrToFlash(X)) | ||||
|  | ||||
| inline uint8_t pgm_read_byte_near(const void* p) { | ||||
| inline uint8_t pgm_read_byte(const void* p) { | ||||
|   return *reinterpret_cast<const uint8_t*>(convertFlashToPtr(p)); | ||||
| } | ||||
|  | ||||
| inline void* memcpy_P(void* a, const prog_void* b, size_t n) { | ||||
|   return memcpy(a, convertFlashToPtr(b), n); | ||||
| } | ||||
|  | ||||
| inline int strcmp_P(const char* a, const prog_char* b) { | ||||
|   return strcmp(a, reinterpret_cast<const char*>(convertFlashToPtr(b))); | ||||
| } | ||||
|  | ||||
| inline int strncmp_P(const char* a, const prog_char* b, size_t n) { | ||||
|   return strncmp(a, reinterpret_cast<const char*>(convertFlashToPtr(b)), n); | ||||
| } | ||||
|  | ||||
| inline size_t strlen_P(const prog_char* s) { | ||||
|   return strlen(reinterpret_cast<const char*>(convertFlashToPtr(s))); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user