DeepCover Embedded Security in IoT: Public-key Secured Data Paths

Dependencies:   MaximInterface

The MAXREFDES155# is an internet-of-things (IoT) embedded-security reference design, built to authenticate and control a sensing node using elliptic-curve-based public-key cryptography with control and notification from a web server.

The hardware includes an ARM® mbed™ shield and attached sensor endpoint. The shield contains a DS2476 DeepCover® ECDSA/SHA-2 coprocessor, Wifi communication, LCD push-button controls, and status LEDs. The sensor endpoint is attached to the shield using a 300mm cable and contains a DS28C36 DeepCover ECDSA/SHA-2 authenticator, IR-thermal sensor, and aiming laser for the IR sensor. The MAXREFDES155# is equipped with a standard Arduino® form-factor shield connector for immediate testing using an mbed board such as the MAX32600MBED#. The combination of these two devices represent an IoT device. Communication to the web server is accomplished with the shield Wifi circuitry. Communication from the shield to the attached sensor module is accomplished over I2C . The sensor module represents an IoT endpoint that generates small data with a requirement for message authenticity/integrity and secure on/off operational control.

The design is hierarchical with each mbed platform and shield communicating data from the sensor node to a web server that maintains a centralized log and dispatches notifications as necessary. The simplicity of this design enables rapid integration into any star-topology IoT network to provide security with the low overhead and cost provided by the ECDSA-P256 asymmetric-key and SHA-256 symmetric-key algorithms.

More information about the MAXREFDES155# is available on the Maxim Integrated website.

Committer:
IanBenzMaxim
Date:
Fri Feb 24 11:23:12 2017 -0600
Revision:
0:33d4e66780c0
Child:
3:d2799d8497c0
Initial commit.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
IanBenzMaxim 0:33d4e66780c0 1 /*******************************************************************************
IanBenzMaxim 0:33d4e66780c0 2 * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
IanBenzMaxim 0:33d4e66780c0 3 *
IanBenzMaxim 0:33d4e66780c0 4 * Permission is hereby granted, free of charge, to any person obtaining a
IanBenzMaxim 0:33d4e66780c0 5 * copy of this software and associated documentation files (the "Software"),
IanBenzMaxim 0:33d4e66780c0 6 * to deal in the Software without restriction, including without limitation
IanBenzMaxim 0:33d4e66780c0 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
IanBenzMaxim 0:33d4e66780c0 8 * and/or sell copies of the Software, and to permit persons to whom the
IanBenzMaxim 0:33d4e66780c0 9 * Software is furnished to do so, subject to the following conditions:
IanBenzMaxim 0:33d4e66780c0 10 *
IanBenzMaxim 0:33d4e66780c0 11 * The above copyright notice and this permission notice shall be included
IanBenzMaxim 0:33d4e66780c0 12 * in all copies or substantial portions of the Software.
IanBenzMaxim 0:33d4e66780c0 13 *
IanBenzMaxim 0:33d4e66780c0 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
IanBenzMaxim 0:33d4e66780c0 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
IanBenzMaxim 0:33d4e66780c0 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IanBenzMaxim 0:33d4e66780c0 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
IanBenzMaxim 0:33d4e66780c0 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
IanBenzMaxim 0:33d4e66780c0 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
IanBenzMaxim 0:33d4e66780c0 20 * OTHER DEALINGS IN THE SOFTWARE.
IanBenzMaxim 0:33d4e66780c0 21 *
IanBenzMaxim 0:33d4e66780c0 22 * Except as contained in this notice, the name of Maxim Integrated
IanBenzMaxim 0:33d4e66780c0 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
IanBenzMaxim 0:33d4e66780c0 24 * Products, Inc. Branding Policy.
IanBenzMaxim 0:33d4e66780c0 25 *
IanBenzMaxim 0:33d4e66780c0 26 * The mere transfer of this software does not imply any licenses
IanBenzMaxim 0:33d4e66780c0 27 * of trade secrets, proprietary technology, copyrights, patents,
IanBenzMaxim 0:33d4e66780c0 28 * trademarks, maskwork rights, or any other form of intellectual
IanBenzMaxim 0:33d4e66780c0 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
IanBenzMaxim 0:33d4e66780c0 30 * ownership rights.
IanBenzMaxim 0:33d4e66780c0 31 *******************************************************************************/
IanBenzMaxim 0:33d4e66780c0 32
IanBenzMaxim 0:33d4e66780c0 33 #include <algorithm>
IanBenzMaxim 0:33d4e66780c0 34 #include <functional>
IanBenzMaxim 0:33d4e66780c0 35 #include <list>
IanBenzMaxim 0:33d4e66780c0 36 #include "Bitmap.hpp"
IanBenzMaxim 0:33d4e66780c0 37 #include "Display.hpp"
IanBenzMaxim 0:33d4e66780c0 38 #include "Text.hpp"
IanBenzMaxim 0:33d4e66780c0 39
IanBenzMaxim 0:33d4e66780c0 40 using std::string;
IanBenzMaxim 0:33d4e66780c0 41
IanBenzMaxim 0:33d4e66780c0 42 static const unsigned int characterWidth = 5;
IanBenzMaxim 0:33d4e66780c0 43 static const unsigned int characterHeight = 7;
IanBenzMaxim 0:33d4e66780c0 44
IanBenzMaxim 0:33d4e66780c0 45 static const unsigned char printableCharBegin = 0x20;
IanBenzMaxim 0:33d4e66780c0 46 static const unsigned char printableCharEnd = 0x7E;
IanBenzMaxim 0:33d4e66780c0 47
IanBenzMaxim 0:33d4e66780c0 48 static const uint8_t characterMap[][characterWidth] = {
IanBenzMaxim 0:33d4e66780c0 49 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // ' '
IanBenzMaxim 0:33d4e66780c0 50 { 0x00, 0x00, 0xF2, 0x00, 0x00 }, // '!'
IanBenzMaxim 0:33d4e66780c0 51 { 0x00, 0xE0, 0x00, 0xE0, 0x00 }, // '"'
IanBenzMaxim 0:33d4e66780c0 52 { 0x28, 0xFE, 0x28, 0xFE, 0x28 }, // '#'
IanBenzMaxim 0:33d4e66780c0 53 { 0x24, 0x54, 0xFE, 0x54, 0x48 }, // '$'
IanBenzMaxim 0:33d4e66780c0 54 { 0xC4, 0xC8, 0x10, 0x26, 0x46 }, // '%'
IanBenzMaxim 0:33d4e66780c0 55 { 0x6C, 0x92, 0xAA, 0x44, 0x0A }, // '&'
IanBenzMaxim 0:33d4e66780c0 56 { 0x00, 0xA0, 0xC0, 0x00, 0x00 }, // '''
IanBenzMaxim 0:33d4e66780c0 57 { 0x00, 0x28, 0x44, 0x82, 0x00 }, // '('
IanBenzMaxim 0:33d4e66780c0 58 { 0x00, 0x82, 0x44, 0x38, 0x00 }, // ')'
IanBenzMaxim 0:33d4e66780c0 59 { 0x28, 0x10, 0x7C, 0x10, 0x28 }, // '*'
IanBenzMaxim 0:33d4e66780c0 60 { 0x10, 0x10, 0x7C, 0x10, 0x10 }, // '+'
IanBenzMaxim 0:33d4e66780c0 61 { 0x00, 0x0A, 0x0C, 0x00, 0x00 }, // ','
IanBenzMaxim 0:33d4e66780c0 62 { 0x10, 0x10, 0x10, 0x10, 0x10 }, // '-'
IanBenzMaxim 0:33d4e66780c0 63 { 0x00, 0x06, 0x06, 0x00, 0x00 }, // '.'
IanBenzMaxim 0:33d4e66780c0 64 { 0x04, 0x08, 0x10, 0x20, 0x40 }, // '/'
IanBenzMaxim 0:33d4e66780c0 65 { 0x7C, 0x8A, 0x92, 0xA2, 0x7C }, // '0'
IanBenzMaxim 0:33d4e66780c0 66 { 0x00, 0x42, 0xFE, 0x02, 0x00 }, // '1'
IanBenzMaxim 0:33d4e66780c0 67 { 0x42, 0x86, 0x8A, 0x92, 0x62 }, // '2'
IanBenzMaxim 0:33d4e66780c0 68 { 0x84, 0x82, 0xA2, 0xD2, 0x8C }, // '3'
IanBenzMaxim 0:33d4e66780c0 69 { 0x18, 0x28, 0x48, 0xFE, 0x08 }, // '4'
IanBenzMaxim 0:33d4e66780c0 70 { 0xE4, 0xA2, 0xA2, 0xA2, 0x9C }, // '5'
IanBenzMaxim 0:33d4e66780c0 71 { 0x3C, 0x52, 0x92, 0x92, 0x0C }, // '6'
IanBenzMaxim 0:33d4e66780c0 72 { 0x80, 0x8E, 0x90, 0xA0, 0xC0 }, // '7'
IanBenzMaxim 0:33d4e66780c0 73 { 0x6C, 0x92, 0x92, 0x92, 0x6C }, // '8'
IanBenzMaxim 0:33d4e66780c0 74 { 0x60, 0x92, 0x92, 0x94, 0x78 }, // '9'
IanBenzMaxim 0:33d4e66780c0 75 { 0x00, 0x6C, 0x6C, 0x00, 0x00 }, // ':'
IanBenzMaxim 0:33d4e66780c0 76 { 0x00, 0x6A, 0x6C, 0x00, 0x00 }, // ';'
IanBenzMaxim 0:33d4e66780c0 77 { 0x10, 0x28, 0x44, 0x82, 0x00 }, // '<'
IanBenzMaxim 0:33d4e66780c0 78 { 0x28, 0x28, 0x28, 0x28, 0x28 }, // '='
IanBenzMaxim 0:33d4e66780c0 79 { 0x00, 0x82, 0x44, 0x28, 0x10 }, // '>'
IanBenzMaxim 0:33d4e66780c0 80 { 0x40, 0x80, 0x8A, 0x90, 0x60 }, // '?'
IanBenzMaxim 0:33d4e66780c0 81 { 0x4C, 0x92, 0x9E, 0x82, 0x7C }, // '@'
IanBenzMaxim 0:33d4e66780c0 82 { 0x7E, 0x88, 0x88, 0x88, 0x7E }, // 'A'
IanBenzMaxim 0:33d4e66780c0 83 { 0xFE, 0x92, 0x92, 0x92, 0x6C }, // 'B'
IanBenzMaxim 0:33d4e66780c0 84 { 0x7C, 0x82, 0x82, 0x82, 0x44 }, // 'C'
IanBenzMaxim 0:33d4e66780c0 85 { 0xFE, 0x82, 0x82, 0x44, 0x38 }, // 'D'
IanBenzMaxim 0:33d4e66780c0 86 { 0xFE, 0x92, 0x92, 0x92, 0x82 }, // 'E'
IanBenzMaxim 0:33d4e66780c0 87 { 0xFE, 0x90, 0x90, 0x90, 0x80 }, // 'F'
IanBenzMaxim 0:33d4e66780c0 88 { 0x7C, 0x82, 0x92, 0x92, 0x5E }, // 'G'
IanBenzMaxim 0:33d4e66780c0 89 { 0xFE, 0x10, 0x10, 0x10, 0xFE }, // 'H'
IanBenzMaxim 0:33d4e66780c0 90 { 0x00, 0x82, 0xFE, 0x82, 0x00 }, // 'I'
IanBenzMaxim 0:33d4e66780c0 91 { 0x04, 0x02, 0x82, 0xFC, 0x80 }, // 'J'
IanBenzMaxim 0:33d4e66780c0 92 { 0xFE, 0x10, 0x28, 0x44, 0x82 }, // 'K'
IanBenzMaxim 0:33d4e66780c0 93 { 0xFE, 0x02, 0x02, 0x02, 0x02 }, // 'L'
IanBenzMaxim 0:33d4e66780c0 94 { 0xFE, 0x40, 0x21, 0x40, 0xFE }, // 'M'
IanBenzMaxim 0:33d4e66780c0 95 { 0xFE, 0x20, 0x10, 0x08, 0xFE }, // 'N'
IanBenzMaxim 0:33d4e66780c0 96 { 0x7C, 0x82, 0x82, 0x82, 0x7C }, // 'O'
IanBenzMaxim 0:33d4e66780c0 97 { 0xFE, 0x90, 0x90, 0x90, 0x60 }, // 'P'
IanBenzMaxim 0:33d4e66780c0 98 { 0x7C, 0x82, 0x8A, 0x82, 0x7A }, // 'Q'
IanBenzMaxim 0:33d4e66780c0 99 { 0xFE, 0x90, 0x98, 0x94, 0x62 }, // 'R'
IanBenzMaxim 0:33d4e66780c0 100 { 0x62, 0x92, 0x92, 0x92, 0x8C }, // 'S'
IanBenzMaxim 0:33d4e66780c0 101 { 0x80, 0x80, 0xFE, 0x80, 0x80 }, // 'T'
IanBenzMaxim 0:33d4e66780c0 102 { 0xFC, 0x02, 0x02, 0x02, 0xFC }, // 'U'
IanBenzMaxim 0:33d4e66780c0 103 { 0xF8, 0x04, 0x02, 0x04, 0xF8 }, // 'V'
IanBenzMaxim 0:33d4e66780c0 104 { 0xFC, 0x02, 0x1C, 0x02, 0xFC }, // 'W'
IanBenzMaxim 0:33d4e66780c0 105 { 0xC6, 0x28, 0x10, 0x28, 0xC6 }, // 'X'
IanBenzMaxim 0:33d4e66780c0 106 { 0xF0, 0x10, 0x0F, 0x10, 0xF0 }, // 'Y'
IanBenzMaxim 0:33d4e66780c0 107 { 0x86, 0x8A, 0x92, 0xA2, 0xC2 }, // 'Z'
IanBenzMaxim 0:33d4e66780c0 108 { 0x00, 0xFE, 0x82, 0x82, 0x00 }, // '['
IanBenzMaxim 0:33d4e66780c0 109 { 0x40, 0x20, 0x10, 0x08, 0x04 }, // '\'
IanBenzMaxim 0:33d4e66780c0 110 { 0x00, 0x82, 0x82, 0xFE, 0x00 }, // ']'
IanBenzMaxim 0:33d4e66780c0 111 { 0x20, 0x40, 0x80, 0x40, 0x20 }, // '^'
IanBenzMaxim 0:33d4e66780c0 112 { 0x02, 0x02, 0x02, 0x02, 0x02 }, // '_'
IanBenzMaxim 0:33d4e66780c0 113 { 0x00, 0x80, 0x40, 0x20, 0x00 }, // '`'
IanBenzMaxim 0:33d4e66780c0 114 { 0x04, 0x2A, 0x2A, 0x2A, 0x1E }, // 'a'
IanBenzMaxim 0:33d4e66780c0 115 { 0xFE, 0x12, 0x22, 0x22, 0x1C }, // 'b'
IanBenzMaxim 0:33d4e66780c0 116 { 0x1C, 0x22, 0x22, 0x22, 0x04 }, // 'c'
IanBenzMaxim 0:33d4e66780c0 117 { 0x1C, 0x22, 0x22, 0x12, 0xFE }, // 'd'
IanBenzMaxim 0:33d4e66780c0 118 { 0x1C, 0x2A, 0x2A, 0x2A, 0x18 }, // 'e'
IanBenzMaxim 0:33d4e66780c0 119 { 0x10, 0x7E, 0x90, 0x80, 0x40 }, // 'f'
IanBenzMaxim 0:33d4e66780c0 120 { 0x30, 0x4A, 0x4A, 0x4A, 0x7C }, // 'g'
IanBenzMaxim 0:33d4e66780c0 121 { 0xFE, 0x10, 0x20, 0x20, 0x1E }, // 'h'
IanBenzMaxim 0:33d4e66780c0 122 { 0x00, 0x22, 0xBE, 0x02, 0x00 }, // 'i'
IanBenzMaxim 0:33d4e66780c0 123 { 0x04, 0x02, 0x22, 0xBC, 0x00 }, // 'j'
IanBenzMaxim 0:33d4e66780c0 124 { 0xFE, 0x08, 0x14, 0x22, 0x00 }, // 'k'
IanBenzMaxim 0:33d4e66780c0 125 { 0x00, 0x82, 0xFE, 0x02, 0x00 }, // 'l'
IanBenzMaxim 0:33d4e66780c0 126 { 0x3E, 0x20, 0x18, 0x20, 0x1E }, // 'm'
IanBenzMaxim 0:33d4e66780c0 127 { 0x3E, 0x10, 0x20, 0x20, 0x1E }, // 'n'
IanBenzMaxim 0:33d4e66780c0 128 { 0x1C, 0x22, 0x22, 0x22, 0x1C }, // 'o'
IanBenzMaxim 0:33d4e66780c0 129 { 0x3E, 0x28, 0x28, 0x28, 0x10 }, // 'p'
IanBenzMaxim 0:33d4e66780c0 130 { 0x10, 0x28, 0x28, 0x18, 0x3E }, // 'q'
IanBenzMaxim 0:33d4e66780c0 131 { 0x3E, 0x10, 0x20, 0x20, 0x10 }, // 'r'
IanBenzMaxim 0:33d4e66780c0 132 { 0x12, 0x2A, 0x2A, 0x2A, 0x04 }, // 's'
IanBenzMaxim 0:33d4e66780c0 133 { 0x20, 0xFC, 0x22, 0x02, 0x04 }, // 't'
IanBenzMaxim 0:33d4e66780c0 134 { 0x3C, 0x02, 0x02, 0x04, 0x3E }, // 'u'
IanBenzMaxim 0:33d4e66780c0 135 { 0x38, 0x04, 0x02, 0x04, 0x38 }, // 'v'
IanBenzMaxim 0:33d4e66780c0 136 { 0x3C, 0x02, 0x0C, 0x02, 0x3C }, // 'w'
IanBenzMaxim 0:33d4e66780c0 137 { 0x22, 0x14, 0x08, 0x14, 0x22 }, // 'x'
IanBenzMaxim 0:33d4e66780c0 138 { 0x30, 0x0A, 0x0A, 0x0A, 0x3C }, // 'y'
IanBenzMaxim 0:33d4e66780c0 139 { 0x22, 0x26, 0x2A, 0x32, 0x22 }, // 'z'
IanBenzMaxim 0:33d4e66780c0 140 { 0x00, 0x10, 0x6C, 0x82, 0x00 }, // '{'
IanBenzMaxim 0:33d4e66780c0 141 { 0x00, 0x00, 0xFE, 0x00, 0x00 }, // '|'
IanBenzMaxim 0:33d4e66780c0 142 { 0x00, 0x82, 0x6C, 0x10, 0x00 }, // '}'
IanBenzMaxim 0:33d4e66780c0 143 { 0x10, 0x20, 0x10, 0x08, 0x10 } // '~'
IanBenzMaxim 0:33d4e66780c0 144 };
IanBenzMaxim 0:33d4e66780c0 145
IanBenzMaxim 0:33d4e66780c0 146 static bool charPrintable(unsigned char c)
IanBenzMaxim 0:33d4e66780c0 147 {
IanBenzMaxim 0:33d4e66780c0 148 return (c >= printableCharBegin) && (c <= printableCharEnd);
IanBenzMaxim 0:33d4e66780c0 149 }
IanBenzMaxim 0:33d4e66780c0 150
IanBenzMaxim 0:33d4e66780c0 151 static void removeNonprintableChars(string & s)
IanBenzMaxim 0:33d4e66780c0 152 {
IanBenzMaxim 0:33d4e66780c0 153 s.erase(std::remove_if(s.begin(), s.end(), std::not1(std::ptr_fun(charPrintable))));
IanBenzMaxim 0:33d4e66780c0 154 }
IanBenzMaxim 0:33d4e66780c0 155
IanBenzMaxim 0:33d4e66780c0 156 static bool compareStringLength(const string & a, const string & b)
IanBenzMaxim 0:33d4e66780c0 157 {
IanBenzMaxim 0:33d4e66780c0 158 return a.length() < b.length();
IanBenzMaxim 0:33d4e66780c0 159 }
IanBenzMaxim 0:33d4e66780c0 160
IanBenzMaxim 0:33d4e66780c0 161 // Functor trims string if it exceeds a certain length.
IanBenzMaxim 0:33d4e66780c0 162 class TrimString
IanBenzMaxim 0:33d4e66780c0 163 {
IanBenzMaxim 0:33d4e66780c0 164 public:
IanBenzMaxim 0:33d4e66780c0 165 TrimString(string::size_type maxSize) : maxSize(maxSize) { }
IanBenzMaxim 0:33d4e66780c0 166
IanBenzMaxim 0:33d4e66780c0 167 void operator()(string & s)
IanBenzMaxim 0:33d4e66780c0 168 {
IanBenzMaxim 0:33d4e66780c0 169 if (s.size() > maxSize)
IanBenzMaxim 0:33d4e66780c0 170 {
IanBenzMaxim 0:33d4e66780c0 171 s.resize(maxSize);
IanBenzMaxim 0:33d4e66780c0 172 }
IanBenzMaxim 0:33d4e66780c0 173 }
IanBenzMaxim 0:33d4e66780c0 174
IanBenzMaxim 0:33d4e66780c0 175 private:
IanBenzMaxim 0:33d4e66780c0 176 string::size_type maxSize;
IanBenzMaxim 0:33d4e66780c0 177 };
IanBenzMaxim 0:33d4e66780c0 178
IanBenzMaxim 0:33d4e66780c0 179 // Split a string based on a character token. Token will be removed.
IanBenzMaxim 0:33d4e66780c0 180 static std::list<string> tokenizeString(const string & toSplit, char token)
IanBenzMaxim 0:33d4e66780c0 181 {
IanBenzMaxim 0:33d4e66780c0 182 std::list<string> toSplitLines;
IanBenzMaxim 0:33d4e66780c0 183 string::size_type beginIdx = 0, endIdx;
IanBenzMaxim 0:33d4e66780c0 184 do
IanBenzMaxim 0:33d4e66780c0 185 {
IanBenzMaxim 0:33d4e66780c0 186 endIdx = toSplit.find(token, beginIdx);
IanBenzMaxim 0:33d4e66780c0 187 toSplitLines.push_back(toSplit.substr(beginIdx, endIdx == string::npos ? string::npos : endIdx - beginIdx));
IanBenzMaxim 0:33d4e66780c0 188 beginIdx = endIdx + 1;
IanBenzMaxim 0:33d4e66780c0 189 } while (endIdx != string::npos);
IanBenzMaxim 0:33d4e66780c0 190 return toSplitLines;
IanBenzMaxim 0:33d4e66780c0 191 }
IanBenzMaxim 0:33d4e66780c0 192
IanBenzMaxim 0:33d4e66780c0 193 // Word wrap string into lines based on a specified line length.
IanBenzMaxim 0:33d4e66780c0 194 static std::list<string> wrapLines(const string & toSplit, const string::size_type lineLen)
IanBenzMaxim 0:33d4e66780c0 195 {
IanBenzMaxim 0:33d4e66780c0 196 std::list<string> toSplitLines;
IanBenzMaxim 0:33d4e66780c0 197 string::size_type beginIdx = 0;
IanBenzMaxim 0:33d4e66780c0 198 if (lineLen > 0)
IanBenzMaxim 0:33d4e66780c0 199 {
IanBenzMaxim 0:33d4e66780c0 200 // Split lines as much as necessary.
IanBenzMaxim 0:33d4e66780c0 201 string::size_type endIdx = lineLen;
IanBenzMaxim 0:33d4e66780c0 202 while (((toSplit.length() - beginIdx) > lineLen) && (endIdx != string::npos))
IanBenzMaxim 0:33d4e66780c0 203 {
IanBenzMaxim 0:33d4e66780c0 204 endIdx = toSplit.rfind(' ', endIdx);
IanBenzMaxim 0:33d4e66780c0 205 if ((endIdx == string::npos) || (endIdx <= beginIdx))
IanBenzMaxim 0:33d4e66780c0 206 {
IanBenzMaxim 0:33d4e66780c0 207 // Current word is too long to split. Find end of current word.
IanBenzMaxim 0:33d4e66780c0 208 endIdx = toSplit.find(' ', beginIdx);
IanBenzMaxim 0:33d4e66780c0 209 }
IanBenzMaxim 0:33d4e66780c0 210 if (endIdx != string::npos)
IanBenzMaxim 0:33d4e66780c0 211 {
IanBenzMaxim 0:33d4e66780c0 212 toSplitLines.push_back(toSplit.substr(beginIdx, endIdx - beginIdx));
IanBenzMaxim 0:33d4e66780c0 213 beginIdx = endIdx + 1;
IanBenzMaxim 0:33d4e66780c0 214 endIdx = beginIdx + lineLen;
IanBenzMaxim 0:33d4e66780c0 215 }
IanBenzMaxim 0:33d4e66780c0 216 }
IanBenzMaxim 0:33d4e66780c0 217 }
IanBenzMaxim 0:33d4e66780c0 218 // Last line is any remaining characters.
IanBenzMaxim 0:33d4e66780c0 219 toSplitLines.push_back(toSplit.substr(beginIdx, toSplit.length() - beginIdx));
IanBenzMaxim 0:33d4e66780c0 220 return toSplitLines;
IanBenzMaxim 0:33d4e66780c0 221 }
IanBenzMaxim 0:33d4e66780c0 222
IanBenzMaxim 0:33d4e66780c0 223 Text::Text(const string & text, Graphic * parent) :
IanBenzMaxim 0:33d4e66780c0 224 Graphic(parent), m_text(text), m_wordWrap(false), m_charSpacing(1), m_lineSpacing(1),
IanBenzMaxim 0:33d4e66780c0 225 m_textLines(), m_preferredWidth(0), m_preferredHeight(0)
IanBenzMaxim 0:33d4e66780c0 226 {
IanBenzMaxim 0:33d4e66780c0 227 // Default to the preferred width and height.
IanBenzMaxim 0:33d4e66780c0 228 update();
IanBenzMaxim 0:33d4e66780c0 229 setWidth(preferredWidth());
IanBenzMaxim 0:33d4e66780c0 230 setHeight(preferredHeight());
IanBenzMaxim 0:33d4e66780c0 231 }
IanBenzMaxim 0:33d4e66780c0 232
IanBenzMaxim 0:33d4e66780c0 233 void Text::setText(const std::string & text)
IanBenzMaxim 0:33d4e66780c0 234 {
IanBenzMaxim 0:33d4e66780c0 235 if (m_text != text)
IanBenzMaxim 0:33d4e66780c0 236 {
IanBenzMaxim 0:33d4e66780c0 237 m_text = text;
IanBenzMaxim 0:33d4e66780c0 238 invalidateRegion();
IanBenzMaxim 0:33d4e66780c0 239 }
IanBenzMaxim 0:33d4e66780c0 240 }
IanBenzMaxim 0:33d4e66780c0 241
IanBenzMaxim 0:33d4e66780c0 242 void Text::setWordWrap(bool wordWrap)
IanBenzMaxim 0:33d4e66780c0 243 {
IanBenzMaxim 0:33d4e66780c0 244 if (m_wordWrap != wordWrap)
IanBenzMaxim 0:33d4e66780c0 245 {
IanBenzMaxim 0:33d4e66780c0 246 m_wordWrap = wordWrap;
IanBenzMaxim 0:33d4e66780c0 247 invalidateRegion();
IanBenzMaxim 0:33d4e66780c0 248 }
IanBenzMaxim 0:33d4e66780c0 249 }
IanBenzMaxim 0:33d4e66780c0 250
IanBenzMaxim 0:33d4e66780c0 251 void Text::setLineSpacing(unsigned int lineSpacing)
IanBenzMaxim 0:33d4e66780c0 252 {
IanBenzMaxim 0:33d4e66780c0 253 if (m_lineSpacing != lineSpacing)
IanBenzMaxim 0:33d4e66780c0 254 {
IanBenzMaxim 0:33d4e66780c0 255 m_lineSpacing = lineSpacing;
IanBenzMaxim 0:33d4e66780c0 256 invalidateRegion();
IanBenzMaxim 0:33d4e66780c0 257 }
IanBenzMaxim 0:33d4e66780c0 258 }
IanBenzMaxim 0:33d4e66780c0 259
IanBenzMaxim 0:33d4e66780c0 260 void Text::setCharSpacing(unsigned int charSpacing)
IanBenzMaxim 0:33d4e66780c0 261 {
IanBenzMaxim 0:33d4e66780c0 262 if (m_charSpacing != charSpacing)
IanBenzMaxim 0:33d4e66780c0 263 {
IanBenzMaxim 0:33d4e66780c0 264 m_charSpacing = charSpacing;
IanBenzMaxim 0:33d4e66780c0 265 invalidateRegion();
IanBenzMaxim 0:33d4e66780c0 266 }
IanBenzMaxim 0:33d4e66780c0 267 }
IanBenzMaxim 0:33d4e66780c0 268
IanBenzMaxim 0:33d4e66780c0 269 void Text::doPostLayout()
IanBenzMaxim 0:33d4e66780c0 270 {
IanBenzMaxim 0:33d4e66780c0 271 using std::list;
IanBenzMaxim 0:33d4e66780c0 272
IanBenzMaxim 0:33d4e66780c0 273 if (regionValid())
IanBenzMaxim 0:33d4e66780c0 274 return;
IanBenzMaxim 0:33d4e66780c0 275
IanBenzMaxim 0:33d4e66780c0 276 // Split string into lines.
IanBenzMaxim 0:33d4e66780c0 277 m_textLines = tokenizeString(m_text, '\n');
IanBenzMaxim 0:33d4e66780c0 278
IanBenzMaxim 0:33d4e66780c0 279 // Remove non-printable characters.
IanBenzMaxim 0:33d4e66780c0 280 std::for_each(m_textLines.begin(), m_textLines.end(), removeNonprintableChars);
IanBenzMaxim 0:33d4e66780c0 281
IanBenzMaxim 0:33d4e66780c0 282 const unsigned int lineLen =
IanBenzMaxim 0:33d4e66780c0 283 (width() / (characterWidth + m_charSpacing)) +
IanBenzMaxim 0:33d4e66780c0 284 (((width() % (characterWidth + m_charSpacing)) >= characterWidth) ? 1 : 0);
IanBenzMaxim 0:33d4e66780c0 285 const unsigned int numLines =
IanBenzMaxim 0:33d4e66780c0 286 (height() / (characterHeight + m_lineSpacing)) +
IanBenzMaxim 0:33d4e66780c0 287 (((height() % (characterHeight + m_lineSpacing)) >= characterHeight) ? 1 : 0);
IanBenzMaxim 0:33d4e66780c0 288
IanBenzMaxim 0:33d4e66780c0 289 // Word wrap lines if enabled.
IanBenzMaxim 0:33d4e66780c0 290 if (m_wordWrap)
IanBenzMaxim 0:33d4e66780c0 291 {
IanBenzMaxim 0:33d4e66780c0 292 list<string>::iterator lineIt = m_textLines.begin();
IanBenzMaxim 0:33d4e66780c0 293 while (lineIt != m_textLines.end())
IanBenzMaxim 0:33d4e66780c0 294 {
IanBenzMaxim 0:33d4e66780c0 295 list<string>::iterator nextLineIt = lineIt;
IanBenzMaxim 0:33d4e66780c0 296 nextLineIt++;
IanBenzMaxim 0:33d4e66780c0 297
IanBenzMaxim 0:33d4e66780c0 298 // Wrap current line.
IanBenzMaxim 0:33d4e66780c0 299 list<string> wrappedLines = wrapLines(*lineIt, lineLen);
IanBenzMaxim 0:33d4e66780c0 300 m_textLines.splice(lineIt, wrappedLines);
IanBenzMaxim 0:33d4e66780c0 301 // Remove old line.
IanBenzMaxim 0:33d4e66780c0 302 m_textLines.erase(lineIt);
IanBenzMaxim 0:33d4e66780c0 303
IanBenzMaxim 0:33d4e66780c0 304 lineIt = nextLineIt;
IanBenzMaxim 0:33d4e66780c0 305 }
IanBenzMaxim 0:33d4e66780c0 306 }
IanBenzMaxim 0:33d4e66780c0 307
IanBenzMaxim 0:33d4e66780c0 308 // Calculate preferred size.
IanBenzMaxim 0:33d4e66780c0 309 string::size_type maxLineLength =
IanBenzMaxim 0:33d4e66780c0 310 std::max_element(m_textLines.begin(), m_textLines.end(), compareStringLength)->length();
IanBenzMaxim 0:33d4e66780c0 311 m_preferredWidth = (maxLineLength > 0) ?
IanBenzMaxim 0:33d4e66780c0 312 (maxLineLength * characterWidth) + ((maxLineLength - 1) * m_charSpacing) : 1;
IanBenzMaxim 0:33d4e66780c0 313 m_preferredHeight =
IanBenzMaxim 0:33d4e66780c0 314 (m_textLines.size() * characterHeight) + ((m_textLines.size() - 1) * m_lineSpacing);
IanBenzMaxim 0:33d4e66780c0 315
IanBenzMaxim 0:33d4e66780c0 316 // Remove clipped text.
IanBenzMaxim 0:33d4e66780c0 317 if (m_textLines.size() > numLines)
IanBenzMaxim 0:33d4e66780c0 318 m_textLines.resize(numLines);
IanBenzMaxim 0:33d4e66780c0 319 std::for_each(m_textLines.begin(), m_textLines.end(), TrimString(lineLen));
IanBenzMaxim 0:33d4e66780c0 320 }
IanBenzMaxim 0:33d4e66780c0 321
IanBenzMaxim 0:33d4e66780c0 322 Bitmap Text::render() const
IanBenzMaxim 0:33d4e66780c0 323 {
IanBenzMaxim 0:33d4e66780c0 324 using std::list;
IanBenzMaxim 0:33d4e66780c0 325
IanBenzMaxim 0:33d4e66780c0 326 // Render each line.
IanBenzMaxim 0:33d4e66780c0 327 Bitmap bitmap(width(), height());
IanBenzMaxim 0:33d4e66780c0 328 unsigned int lineNum = 0;
IanBenzMaxim 0:33d4e66780c0 329 for (list<string>::const_iterator lineIt = m_textLines.begin(); lineIt != m_textLines.end(); lineIt++)
IanBenzMaxim 0:33d4e66780c0 330 {
IanBenzMaxim 0:33d4e66780c0 331 // Render each character.
IanBenzMaxim 0:33d4e66780c0 332 for (string::size_type charNum = 0; charNum < lineIt->length(); charNum++)
IanBenzMaxim 0:33d4e66780c0 333 {
IanBenzMaxim 0:33d4e66780c0 334 Bitmap character(characterWidth, characterHeight,
IanBenzMaxim 0:33d4e66780c0 335 &characterMap[(*lineIt)[charNum] - printableCharBegin][0]);
IanBenzMaxim 0:33d4e66780c0 336 bitmap.overlay(character, charNum * (characterWidth + m_charSpacing),
IanBenzMaxim 0:33d4e66780c0 337 lineNum * (characterHeight + m_lineSpacing));
IanBenzMaxim 0:33d4e66780c0 338 }
IanBenzMaxim 0:33d4e66780c0 339 lineNum++;
IanBenzMaxim 0:33d4e66780c0 340 }
IanBenzMaxim 0:33d4e66780c0 341 return bitmap;
IanBenzMaxim 0:33d4e66780c0 342 }