|
| 1 | + // Escape any special HTML (unsafe) characters in a string. e.g. anti-XSS. |
| 2 | + // Args: |
| 3 | + // unescaped: A string containing text to make HTML safe. |
| 4 | + // Returns: |
| 5 | + // A string that is HTML safe. |
| 6 | + String htmlEscape(const String unescaped) { |
| 7 | + String result = ""; |
| 8 | + uint16_t ulen = unescaped.length(); |
| 9 | + result.reserve(ulen); // The result will be at least the size of input. |
| 10 | + for (size_t i = 0; i < ulen; i++) { |
| 11 | + char c = unescaped[i]; |
| 12 | + switch (c) { |
| 13 | + // ';!-"<>=&#{}() are all unsafe. |
| 14 | + case '\'': |
| 15 | + result += F("'"); |
| 16 | + break; |
| 17 | + case ';': |
| 18 | + result += F(";"); |
| 19 | + break; |
| 20 | + case '!': |
| 21 | + result += F("!"); |
| 22 | + break; |
| 23 | + case '-': |
| 24 | + result += F("‐"); |
| 25 | + break; |
| 26 | + case '\"': |
| 27 | + result += F("""); |
| 28 | + break; |
| 29 | + case '<': |
| 30 | + result += F("<"); |
| 31 | + break; |
| 32 | + case '>': |
| 33 | + result += F(">"); |
| 34 | + break; |
| 35 | + case '=': |
| 36 | + result += F("&#equals;"); |
| 37 | + break; |
| 38 | + case '&': |
| 39 | + result += F("&"); |
| 40 | + break; |
| 41 | + case '#': |
| 42 | + result += F("#"); |
| 43 | + break; |
| 44 | + case '{': |
| 45 | + result += F("{"); |
| 46 | + break; |
| 47 | + case '}': |
| 48 | + result += F("}"); |
| 49 | + break; |
| 50 | + case '(': |
| 51 | + result += F("("); |
| 52 | + break; |
| 53 | + case ')': |
| 54 | + result += F(")"); |
| 55 | + break; |
| 56 | + default: |
| 57 | + result += c; |
| 58 | + } |
| 59 | + } |
| 60 | + return result; |
| 61 | + } |
| 62 | + |
| 63 | +String uint64ToString(uint64_t input, uint8_t base = 10); |
| 64 | + |
| 65 | +// Convert a uint64_t (unsigned long long) to a string. |
| 66 | +// Arduino String/toInt/Serial.print() can't handle printing 64 bit values. |
| 67 | +// |
| 68 | +// Args: |
| 69 | +// input: The value to print |
| 70 | +// base: The output base. |
| 71 | +// Returns: |
| 72 | +// A string representation of the integer. |
| 73 | +// Note: Based on Arduino's Print::printNumber() |
| 74 | +String uint64ToString(uint64_t input, uint8_t base) { |
| 75 | + String result = ""; |
| 76 | + // prevent issues if called with base <= 1 |
| 77 | + if (base < 2) base = 10; |
| 78 | + // Check we have a base that we can actually print. |
| 79 | + // i.e. [0-9A-Z] == 36 |
| 80 | + if (base > 36) base = 10; |
| 81 | + |
| 82 | + // Reserve some string space to reduce fragmentation. |
| 83 | + // 16 bytes should store a uint64 in hex text which is the likely worst case. |
| 84 | + // 64 bytes would be the worst case (base 2). |
| 85 | + result.reserve(16); |
| 86 | + |
| 87 | + do { |
| 88 | + char c = input % base; |
| 89 | + input /= base; |
| 90 | + |
| 91 | + if (c < 10) |
| 92 | + c += '0'; |
| 93 | + else |
| 94 | + c += 'A' - 10; |
| 95 | + result = c + result; |
| 96 | + } while (input); |
| 97 | + return result; |
| 98 | +} |
| 99 | + |
| 100 | +#ifdef ARDUINO |
| 101 | +// Print a uint64_t/unsigned long long to the Serial port |
| 102 | +// Serial.print() can't handle printing long longs. (uint64_t) |
| 103 | +// |
| 104 | +// Args: |
| 105 | +// input: The value to print |
| 106 | +// base: The output base. |
| 107 | +void serialPrintUint64(uint64_t input, uint8_t base) { |
| 108 | + Serial.print(uint64ToString(input, base)); |
| 109 | +} |
| 110 | +#endif |
| 111 | + |
| 112 | +#define D_CHR_TIME_SEP ":" |
| 113 | +#define D_STR_DAY "Day" |
| 114 | +#define D_STR_DAYS D_STR_DAY "s" |
| 115 | +#define D_STR_HOUR "Hour" |
| 116 | +#define D_STR_HOURS D_STR_HOUR "s" |
| 117 | +#define D_STR_MINUTE "Minute" |
| 118 | +#define D_STR_MINUTES D_STR_MINUTE "s" |
| 119 | +#define D_STR_SECOND "Second" |
| 120 | +#define D_STR_SECONDS D_STR_SECOND "s" |
| 121 | +#define D_STR_NOW " - " |
| 122 | + |
| 123 | +const PROGMEM char* kTimeSep = D_CHR_TIME_SEP; |
| 124 | +const PROGMEM char* kDayStr = D_STR_DAY; |
| 125 | +const PROGMEM char* kDaysStr = D_STR_DAYS; |
| 126 | +const PROGMEM char* kHourStr = D_STR_HOUR; |
| 127 | +const PROGMEM char* kHoursStr = D_STR_HOURS; |
| 128 | +const PROGMEM char* kMinuteStr = D_STR_MINUTE; |
| 129 | +const PROGMEM char* kMinutesStr = D_STR_MINUTES; |
| 130 | +const PROGMEM char* kSecondStr = D_STR_SECOND; |
| 131 | +const PROGMEM char* kSecondsStr = D_STR_SECONDS; |
| 132 | +const PROGMEM char* kNowStr = D_STR_NOW; |
| 133 | + |
| 134 | +String getTimerMS(uint32_t const msecs){ |
| 135 | + uint32_t totalseconds = msecs / 1000; |
| 136 | + if (totalseconds == 0) return kNowStr; |
| 137 | + |
| 138 | + // Note: uint32_t can only hold up to 45 days, so uint8_t is safe. |
| 139 | + uint8_t days = totalseconds / (60 * 60 * 24); |
| 140 | + uint8_t hours = (totalseconds / (60 * 60)) % 24; |
| 141 | + uint8_t minutes = (totalseconds / 60) % 60; |
| 142 | + uint8_t seconds = totalseconds % 60; |
| 143 | + uint8_t mils = msecs % 100; |
| 144 | + String result = ""; |
| 145 | + |
| 146 | + if(minutes < 10) result += "0"; |
| 147 | + result += uint64ToString(minutes) + kTimeSep; |
| 148 | + if(seconds < 10) result += "0"; |
| 149 | + result += uint64ToString(seconds) + kTimeSep; |
| 150 | + if(mils < 10) result += "0"; |
| 151 | + result += (String)mils; |
| 152 | + return result; |
| 153 | +} |
| 154 | + |
| 155 | +String getTimer(uint32_t const msecs){ |
| 156 | + uint32_t totalseconds = msecs / 1000; |
| 157 | + if (totalseconds == 0) return kNowStr; |
| 158 | + |
| 159 | + // Note: uint32_t can only hold up to 45 days, so uint8_t is safe. |
| 160 | + uint8_t days = totalseconds / (60 * 60 * 24); |
| 161 | + uint8_t hours = (totalseconds / (60 * 60)) % 24; |
| 162 | + uint8_t minutes = (totalseconds / 60) % 60; |
| 163 | + uint8_t seconds = totalseconds % 60; |
| 164 | + uint8_t mils = msecs % 100; |
| 165 | + String result = ""; |
| 166 | + |
| 167 | + if(minutes < 10) result += "0"; |
| 168 | + result += uint64ToString(minutes) + kTimeSep; |
| 169 | + if(seconds < 10) result += "0"; |
| 170 | + result += uint64ToString(seconds); |
| 171 | + return result; |
| 172 | +} |
| 173 | + |
| 174 | + String msToString(uint32_t const msecs) { |
| 175 | + uint32_t totalseconds = msecs / 1000; |
| 176 | + if (totalseconds == 0) return kNowStr; |
| 177 | + |
| 178 | + // Note: uint32_t can only hold up to 45 days, so uint8_t is safe. |
| 179 | + uint8_t days = totalseconds / (60 * 60 * 24); |
| 180 | + uint8_t hours = (totalseconds / (60 * 60)) % 24; |
| 181 | + uint8_t minutes = (totalseconds / 60) % 60; |
| 182 | + uint8_t seconds = totalseconds % 60; |
| 183 | + |
| 184 | + String result = ""; |
| 185 | + if (days) |
| 186 | + result += uint64ToString(days) + ' ' + ((days > 1) ? "kDaysStr" : kDayStr); |
| 187 | + if (hours) { |
| 188 | + if (result.length()) result += ' '; |
| 189 | + result += uint64ToString(hours) + ' ' + ((hours > 1) ? kHoursStr |
| 190 | + : kHourStr); |
| 191 | + } |
| 192 | + if (minutes) { |
| 193 | + if (result.length()) result += ' '; |
| 194 | + result += uint64ToString(minutes) + ' ' + ((minutes > 1) ? kMinutesStr |
| 195 | + : kMinuteStr); |
| 196 | + } |
| 197 | + if (seconds) { |
| 198 | + if (result.length()) result += ' '; |
| 199 | + result += uint64ToString(seconds) + ' ' + ((seconds > 1) ? kSecondsStr |
| 200 | + : kSecondStr); |
| 201 | + } |
| 202 | + return result; |
| 203 | + } |
| 204 | + |
| 205 | + String minsToString(const uint16_t mins) { |
| 206 | + String result = ""; |
| 207 | + result.reserve(5); // 23:59 is the typical worst case. |
| 208 | + if (mins / 60 < 10) result += '0'; // Zero pad the hours |
| 209 | + result += uint64ToString(mins / 60) + kTimeSep; |
| 210 | + if (mins % 60 < 10) result += '0'; // Zero pad the minutes. |
| 211 | + result += uint64ToString(mins % 60); |
| 212 | + return result; |
| 213 | + } |
0 commit comments