1 /*
2  *  Copyright (C) 2007-2010  Anders Gavare.  All rights reserved.
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions are met:
6  *
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. The name of the author may not be used to endorse or promote products
13  *     derived from this software without specific prior written permission.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  *  SUCH DAMAGE.
26  */
27 
28 #include "EscapedString.h"
29 
30 
EscapedString(const string & str)31 EscapedString::EscapedString(const string& str)
32 	: m_str(str)
33 {
34 }
35 
36 
Generate() const37 string EscapedString::Generate() const
38 {
39 	string result = "\"";
40 
41 	for (size_t i=0; i<m_str.length(); i++) {
42 		char ch = m_str[i];
43 
44 		switch (ch) {
45 		case '\n':
46 			result += "\\n";
47 			break;
48 		case '\r':
49 			result += "\\r";
50 			break;
51 		case '\t':
52 			result += "\\t";
53 			break;
54 		case '"':
55 			result += "\\\"";
56 			break;
57 		case '\\':
58 			result += "\\\\";
59 			break;
60 		default:
61 			result += ch;
62 		}
63 	}
64 
65 	result += "\"";
66 
67 	return result;
68 }
69 
70 
Decode(bool & success) const71 string EscapedString::Decode(bool& success) const
72 {
73 	success = false;
74 
75 	// Not an escaped string? Then return failure.
76 	if (m_str.size() < 2 || m_str[0] != '"'
77 	    || m_str[m_str.size() - 1] != '"')
78 		return "";
79 
80 	string result = "";
81 	size_t i;
82 
83 	for (i = 1; i < m_str.length() - 1; i++) {
84 		char ch = m_str[i];
85 
86 		switch (ch) {
87 		case '\\':
88 			{
89 				char ch2 = m_str[++i];
90 				switch (ch2) {
91 				case 'n':
92 					result += '\n';
93 					break;
94 				case 'r':
95 					result += '\r';
96 					break;
97 				case 't':
98 					result += '\t';
99 					break;
100 				default:
101 					result += ch2;
102 				}
103 				break;
104 			}
105 		default:
106 			result += ch;
107 		}
108 	}
109 
110 	if (i == m_str.length() - 1)
111 		success = true;
112 
113 	return result;
114 }
115 
116 
117 /*****************************************************************************/
118 
119 
120 #ifdef WITHUNITTESTS
121 
Test_EscapedString_Generate()122 static void Test_EscapedString_Generate()
123 {
124 	UnitTest::Assert("trivial escape: normal text",
125 	    EscapedString("hello world 123").Generate() ==
126 	    "\"hello world 123\"");
127 
128 	UnitTest::Assert("escape tab",
129 	    EscapedString("hi\tworld").Generate() ==
130 	    "\"hi\\tworld\"");
131 
132 	UnitTest::Assert("escape newline and carriage return",
133 	    EscapedString("hi\nworld\ragain").Generate() ==
134 	    "\"hi\\nworld\\ragain\"");
135 
136 	UnitTest::Assert("escape quotes",
137 	    EscapedString("hi'123\"456\"789").Generate() ==
138 	    "\"hi'123\\\"456\\\"789\"");
139 
140 	UnitTest::Assert("escaped escape char",
141 	    EscapedString("Hello\\world").Generate() ==
142 	    "\"Hello\\\\world\"");
143 }
144 
Test_EscapedString_Decode()145 static void Test_EscapedString_Decode()
146 {
147 	bool success = false;
148 
149 	UnitTest::Assert("trivial escape: normal text",
150 	    EscapedString("\"hello world 123\"").Decode(success) ==
151 	    "hello world 123");
152 	UnitTest::Assert("success failed? (1)", success == true);
153 
154 	success = false;
155 	UnitTest::Assert("escape tab",
156 	    EscapedString("\"hi\\tworld\"").Decode(success) ==
157 	    "hi\tworld");
158 	UnitTest::Assert("success failed? (2)", success == true);
159 
160 	success = false;
161 	UnitTest::Assert("escape newline and carriage return",
162 	    EscapedString("\"hi\\nworld\\ragain\"").Decode(success) ==
163 	    "hi\nworld\ragain");
164 	UnitTest::Assert("success failed? (3)", success == true);
165 
166 	success = false;
167 	UnitTest::Assert("escape quotes",
168 	    EscapedString("\"hi'123\\\"456\\\"789\"").Decode(success) ==
169 	    "hi'123\"456\"789");
170 	UnitTest::Assert("success failed? (4)", success == true);
171 
172 	success = false;
173 	UnitTest::Assert("escaped escape char",
174 	    EscapedString("\"Hello\\\\world\"").Decode(success) ==
175 	    "Hello\\world");
176 	UnitTest::Assert("success failed? (5)", success == true);
177 }
178 
Test_EscapedString_Decode_WithoutQuotes()179 static void Test_EscapedString_Decode_WithoutQuotes()
180 {
181 	bool success = true;
182 
183 	UnitTest::Assert("trivial escape: normal text",
184 	    EscapedString("hello world 123").Decode(success) ==
185 	    "");
186 	UnitTest::Assert("success should have failed", success == false);
187 }
188 
UNITTESTS(EscapedString)189 UNITTESTS(EscapedString)
190 {
191 	UNITTEST(Test_EscapedString_Generate);
192 	UNITTEST(Test_EscapedString_Decode);
193 	UNITTEST(Test_EscapedString_Decode_WithoutQuotes);
194 }
195 
196 #endif
197