1 //=============================================================================
2 //
3 //   File : KviControlCodes.cpp
4 //   Creation date : Sat Aug 31 17:07:36 2002 GMT by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 2002-2010 Szymon Stefanek (pragma at kvirc dot net)
8 //
9 //   This program is FREE software. You can redistribute it and/or
10 //   modify it under the terms of the GNU General Public License
11 //   as published by the Free Software Foundation; either version 2
12 //   of the License, or (at your option) any later version.
13 //
14 //   This program is distributed in the HOPE that it will be USEFUL,
15 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 //   See the GNU General Public License for more details.
18 //
19 //   You should have received a copy of the GNU General Public License
20 //   along with this program. If not, write to the Free Software Foundation,
21 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24 
25 #define _KVI_CONTROLCODE_CPP_
26 
27 #include "KviControlCodes.h"
28 
29 #include <QString>
30 
31 namespace KviControlCodes
32 {
stripControlBytes(const QString & szData)33 	QString stripControlBytes(const QString & szData)
34 	{
35 		QString szRet;
36 
37 		int i = 0;
38 		int iBegin = 0;
39 		unsigned char c1;
40 		unsigned char c2;
41 		while(i < szData.length())
42 		{
43 			switch(szData[i].unicode())
44 			{
45 				case KviControlCodes::Underline:
46 				case KviControlCodes::Bold:
47 				case KviControlCodes::Italic:
48 				case KviControlCodes::Reset:
49 				case KviControlCodes::Reverse:
50 				case KviControlCodes::CryptEscape:
51 				case KviControlCodes::CTCP:
52 				case KviControlCodes::Icon:
53 					if(i != iBegin)
54 						szRet += szData.mid(iBegin, i - iBegin);
55 					i++;
56 					iBegin = i;
57 					break;
58 				case KviControlCodes::Color:
59 					if(i != iBegin)
60 						szRet += szData.mid(iBegin, i - iBegin);
61 					i++;
62 					i = getUnicodeColorBytes(szData, i, &c1, &c2);
63 					iBegin = i;
64 					break;
65 				default:
66 					i++;
67 					break;
68 			}
69 		}
70 		if(i != iBegin)
71 			szRet += szData.mid(iBegin, i - iBegin);
72 		return szRet;
73 	}
74 
getColorBytesW(const kvi_wchar_t * pwData,unsigned char * pcByte1,unsigned char * pcByte2)75 	const kvi_wchar_t * getColorBytesW(const kvi_wchar_t * pwData, unsigned char * pcByte1, unsigned char * pcByte2)
76 	{
77 		//
78 		// Scans the pwData for a mIRC color code XX,XX
79 		// and fills the color values in the two bytes
80 		//
81 
82 		//First we can have a digit or a comma
83 		if(((*pwData >= '0') && (*pwData <= '9')))
84 		{
85 			//Something interesting ok.
86 			(*pcByte1) = ((*pwData) - '0'); //store the code
87 			pwData++;                       //and check the next
88 			if(((*pwData >= '0') && (*pwData <= '9')) || (*pwData == ','))
89 			{
90 				//Yes we can understand it
91 				if(*pwData == ',')
92 				{
93 					//A comma, need to check for background
94 					pwData++;
95 				}
96 				else
97 				{
98 					//A number
99 					//(*pcByte1)=((((*pcByte1)*10)+((*pwData)-'0'))%16);
100 					(*pcByte1) = ((*pcByte1) * 10) + ((*pwData) - '0');
101 					pwData++;
102 					if(*pwData == ',')
103 					{
104 						//A comma, need to check for background
105 						pwData++;
106 					}
107 					else
108 					{
109 						//Senseless return
110 						(*pcByte2) = KviControlCodes::NoChange;
111 						return pwData;
112 					}
113 				}
114 			}
115 			else
116 			{
117 				//Senseless character control code OK and return
118 				(*pcByte2) = KviControlCodes::NoChange;
119 				return pwData;
120 			}
121 		}
122 		else
123 		{
124 			//Senseless character : only a Ctrl+K code
125 			(*pcByte1) = KviControlCodes::NoChange;
126 			(*pcByte2) = KviControlCodes::NoChange;
127 			return pwData;
128 		}
129 
130 		if((*pwData >= '0') && (*pwData <= '9'))
131 		{
132 			//Background, a color code
133 			(*pcByte2) = (*pwData) - '0';
134 			pwData++;
135 			if((*pwData >= '0') && (*pwData <= '9'))
136 			{
137 				//(*pcByte2)=((((*pcByte2)*10)+((*pwData)-'0'))%16);
138 				(*pcByte2) = ((*pcByte2) * 10) + ((*pwData) - '0');
139 				pwData++;
140 			}
141 			return pwData;
142 		}
143 		else
144 		{
145 			(*pcByte2) = KviControlCodes::NoChange;
146 			return pwData - 1;
147 		}
148 	}
149 
getUnicodeColorBytes(const QString & szData,unsigned int iChar,unsigned char * pcByte1,unsigned char * pcByte2)150 	unsigned int getUnicodeColorBytes(const QString & szData, unsigned int iChar, unsigned char * pcByte1, unsigned char * pcByte2)
151 	{
152 		//
153 		// Scans the szData for a mIRC color code XX,XX
154 		// and fills the color values in the two bytes
155 		//
156 
157 		if(iChar >= (unsigned int)szData.length())
158 		{
159 			(*pcByte1) = KviControlCodes::NoChange;
160 			(*pcByte2) = KviControlCodes::NoChange;
161 			return iChar;
162 		}
163 
164 		unsigned short c = szData[(int)iChar].unicode();
165 
166 		//First we can have a digit or a comma
167 		if(((c < '0') || (c > '9')))
168 		{
169 			//Senseless : only a Ctrl+K code
170 			(*pcByte1) = KviControlCodes::NoChange;
171 			(*pcByte2) = KviControlCodes::NoChange;
172 			return iChar;
173 		}
174 
175 		//Something interesting OK.
176 		(*pcByte1) = c - '0'; //store the code
177 		iChar++;
178 		if(iChar >= (unsigned int)szData.length())
179 		{
180 			(*pcByte2) = KviControlCodes::NoChange;
181 			return iChar;
182 		}
183 
184 		c = szData[(int)iChar].unicode();
185 
186 		if(((c < '0') || (c > '9')) && (c != ','))
187 		{
188 			(*pcByte2) = KviControlCodes::NoChange;
189 			return iChar;
190 		}
191 
192 		if((c >= '0') && (c <= '9'))
193 		{
194 			(*pcByte1) = (((*pcByte1) * 10) + (c - '0'));
195 			iChar++;
196 			if(iChar >= (unsigned int)szData.length())
197 			{
198 				(*pcByte2) = KviControlCodes::NoChange;
199 				return iChar;
200 			}
201 			c = szData[(int)iChar].unicode();
202 		}
203 
204 		if(c == ',')
205 		{
206 			iChar++;
207 			if(iChar >= (unsigned int)szData.length())
208 			{
209 				(*pcByte2) = KviControlCodes::NoChange;
210 				return iChar;
211 			}
212 			c = szData[(int)iChar].unicode();
213 		}
214 		else
215 		{
216 			(*pcByte2) = KviControlCodes::NoChange;
217 			return iChar;
218 		}
219 
220 		if((c < '0') || (c > '9'))
221 		{
222 			(*pcByte2) = KviControlCodes::NoChange;
223 			if(szData[(int)(iChar - 1)].unicode() == ',')
224 				return iChar - 1;
225 			else
226 				return iChar;
227 		}
228 
229 		//Background, a color code
230 		(*pcByte2) = c - '0';
231 		iChar++;
232 		if(iChar >= (unsigned int)szData.length())
233 			return iChar;
234 		c = szData[(int)iChar].unicode();
235 
236 		if((c >= '0') && (c <= '9'))
237 		{
238 			(*pcByte2) = (((*pcByte2) * 10) + (c - '0'));
239 			iChar++;
240 		}
241 
242 		return iChar;
243 	}
244 
245 #if 0
246 	const char * getColorBytes(const char * pcData, unsigned char * pcByte1, unsigned char * pcByte2)
247 	{
248 		//
249 		// Scans the pcData for a mIRC color code XX,XX
250 		// and fills the color values in the two bytes
251 		//
252 
253 		//First we can have a digit or a comma
254 		if(((*pcData >= '0') && (*pcData <='9')))
255 		{
256 			//Something interesting ok.
257 			(*pcByte1)=(*pcData)-'0'; //store the code
258 			pcData++;     //and check the next
259 			if(((*pcData >= '0') && (*pcData <= '9'))||(*pcData==','))
260 			{
261 				//Yes we can understand it
262 				if(*pcData==',')
263 				{
264 					//A comma, need to check for background
265 					pcData++;
266 				} else {
267 					//A number
268 					(*pcByte1)=((((*pcByte1)*10)+((*pcData)-'0')));
269 					pcData++;
270 					if(*pcData==',')
271 					{
272 						//A comma, need to check for background
273 						pcData++;
274 					} else {
275 						//Senseless return
276 						(*pcByte2)=KviControlCodes::NoChange;
277 						return pcData;
278 					}
279 				}
280 			} else {
281 				//Senseless character control code OK and return
282 				(*pcByte2)=KviControlCodes::NoChange;
283 				return pcData;
284 			}
285 		} else {
286 			//Senseless character : only a Ctrl+K code
287 			(*pcByte1)=KviControlCodes::NoChange;
288 			(*pcByte2)=KviControlCodes::NoChange;
289 			return pcData;
290 		}
291 
292 		if((*pcData >= '0') && (*pcData <='9'))
293 		{
294 			//Background, a color code
295 			(*pcByte2)=(*pcData)-'0';
296 			pcData++;
297 			if((*pcData >= '0') && (*pcData <='9'))
298 			{
299 				(*pcByte2)=((((*pcByte2)*10)+((*pcData)-'0')));
300 				pcData++;
301 			}
302 			return pcData;
303 		} else {
304 			(*pcByte2)=KviControlCodes::NoChange;
305 			return pcData-1;
306 		}
307 	}
308 #endif
309 
310 	// Get extended (16-98) mIRC color.
311 	// Unlike the 0-15 ones, these are not configurable.
312 	// https://modern.ircdocs.horse/formatting.html#colors-16-98
313 	// Returns (kvi_u32_t)-1 if index is out of bounds.
getExtendedColor(int index)314 	kvi_u32_t getExtendedColor(int index)
315 	{
316 		const int minColor = KVI_MIRCCOLOR_MAX + 1; // 16
317 		const int maxColor = KVI_EXTCOLOR_MAX;
318 		static const kvi_u32_t colors[maxColor - minColor + 1] = {
319 			0x470000,
320 			0x472100,
321 			0x474700,
322 			0x324700,
323 			0x004700,
324 			0x00472c,
325 			0x004747,
326 			0x002747,
327 			0x000047,
328 			0x2e0047,
329 			0x470047,
330 			0x47002a,
331 			0x740000,
332 			0x743a00,
333 			0x747400,
334 			0x517400,
335 			0x007400,
336 			0x007449,
337 			0x007474,
338 			0x004074,
339 			0x000074,
340 			0x4b0074,
341 			0x740074,
342 			0x740045,
343 			0xb50000,
344 			0xb56300,
345 			0xb5b500,
346 			0x7db500,
347 			0x00b500,
348 			0x00b571,
349 			0x00b5b5,
350 			0x0063b5,
351 			0x0000b5,
352 			0x7500b5,
353 			0xb500b5,
354 			0xb5006b,
355 			0xff0000,
356 			0xff8c00,
357 			0xffff00,
358 			0xb2ff00,
359 			0x00ff00,
360 			0x00ffa0,
361 			0x00ffff,
362 			0x008cff,
363 			0x0000ff,
364 			0xa500ff,
365 			0xff00ff,
366 			0xff0098,
367 			0xff5959,
368 			0xffb459,
369 			0xffff71,
370 			0xcfff60,
371 			0x6fff6f,
372 			0x65ffc9,
373 			0x6dffff,
374 			0x59b4ff,
375 			0x5959ff,
376 			0xc459ff,
377 			0xff66ff,
378 			0xff59bc,
379 			0xff9c9c,
380 			0xffd39c,
381 			0xffff9c,
382 			0xe2ff9c,
383 			0x9cff9c,
384 			0x9cffdb,
385 			0x9cffff,
386 			0x9cd3ff,
387 			0x9c9cff,
388 			0xdc9cff,
389 			0xff9cff,
390 			0xff94d3,
391 			0x000000,
392 			0x131313,
393 			0x282828,
394 			0x363636,
395 			0x4d4d4d,
396 			0x656565,
397 			0x818181,
398 			0x9f9f9f,
399 			0xbcbcbc,
400 			0xe2e2e2,
401 			0xffffff,
402 		};
403 		if (index < minColor || index > maxColor)
404 			return (kvi_u32_t)-1;
405 		return colors[index - minColor];
406 	}
407 }
408