Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / gui / libwww.cpp
blob5d739863d0041e10dfe149126862476226d865b0
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdpch.h"
23 #include "nel/gui/libwww.h"
24 #include "nel/gui/group_html.h"
26 #include <curl/curl.h>
28 using namespace NLMISC;
30 #ifdef DEBUG_NEW
31 #define new DEBUG_NEW
32 #endif
34 namespace NLGUI
36 struct CNameToHtmlElement
38 HTMLElement ID;
39 const char* Name;
40 CNameToHtmlElement(HTMLElement id, const char*name)
41 : ID(id), Name(name) {}
44 // sorted list of HTML_ELEMENT enum to TAG name
45 static CNameToHtmlElement htmlElementToName[] =
47 CNameToHtmlElement(HTML_A, "a"),
48 CNameToHtmlElement(HTML_ABBR, "abbr"),
49 CNameToHtmlElement(HTML_ADDRESS, "address"),
50 CNameToHtmlElement(HTML_APPLET, "applet"),
51 CNameToHtmlElement(HTML_AREA, "area"),
52 CNameToHtmlElement(HTML_ARTICLE, "article"),
53 CNameToHtmlElement(HTML_ASIDE, "aside"),
54 CNameToHtmlElement(HTML_AUDIO, "audio"),
55 CNameToHtmlElement(HTML_B, "b"),
56 CNameToHtmlElement(HTML_BASE, "base"),
57 CNameToHtmlElement(HTML_BDI, "bdi"),
58 CNameToHtmlElement(HTML_BDO, "bdo"),
59 CNameToHtmlElement(HTML_BLOCKQUOTE, "blockquote"),
60 CNameToHtmlElement(HTML_BODY, "body"),
61 CNameToHtmlElement(HTML_BR, "br"),
62 CNameToHtmlElement(HTML_BUTTON, "button"),
63 CNameToHtmlElement(HTML_CANVAS, "canvas"),
64 CNameToHtmlElement(HTML_CAPTION, "caption"),
65 CNameToHtmlElement(HTML_CITE, "cite"),
66 CNameToHtmlElement(HTML_CODE, "code"),
67 CNameToHtmlElement(HTML_COL, "col"),
68 CNameToHtmlElement(HTML_COLGROUP, "colgroup"),
69 CNameToHtmlElement(HTML_DATA, "data"),
70 CNameToHtmlElement(HTML_DATALIST, "datalist"),
71 CNameToHtmlElement(HTML_DD, "dd"),
72 CNameToHtmlElement(HTML_DEL, "del"),
73 CNameToHtmlElement(HTML_DETAILS, "details"),
74 CNameToHtmlElement(HTML_DFN, "dfn"),
75 CNameToHtmlElement(HTML_DIALOG, "dialog"),
76 CNameToHtmlElement(HTML_DIR, "dir"),
77 CNameToHtmlElement(HTML_DIV, "div"),
78 CNameToHtmlElement(HTML_DL, "dl"),
79 CNameToHtmlElement(HTML_DT, "dt"),
80 CNameToHtmlElement(HTML_EM, "em"),
81 CNameToHtmlElement(HTML_EMBED, "embed"),
82 CNameToHtmlElement(HTML_FIELDSET, "fieldset"),
83 CNameToHtmlElement(HTML_FIGCAPTION, "figcaption"),
84 CNameToHtmlElement(HTML_FIGURE, "figure"),
85 CNameToHtmlElement(HTML_FONT, "font"),
86 CNameToHtmlElement(HTML_FOOTER, "footer"),
87 CNameToHtmlElement(HTML_FORM, "form"),
88 CNameToHtmlElement(HTML_H1, "h1"),
89 CNameToHtmlElement(HTML_H2, "h2"),
90 CNameToHtmlElement(HTML_H3, "h3"),
91 CNameToHtmlElement(HTML_H4, "h4"),
92 CNameToHtmlElement(HTML_H5, "h5"),
93 CNameToHtmlElement(HTML_H6, "h6"),
94 CNameToHtmlElement(HTML_HEAD, "head"),
95 CNameToHtmlElement(HTML_HEADER, "header"),
96 CNameToHtmlElement(HTML_HGROUP, "hgroup"),
97 CNameToHtmlElement(HTML_HR, "hr"),
98 CNameToHtmlElement(HTML_HTML, "html"),
99 CNameToHtmlElement(HTML_I, "i"),
100 CNameToHtmlElement(HTML_IFRAME, "iframe"),
101 CNameToHtmlElement(HTML_IMG, "img"),
102 CNameToHtmlElement(HTML_INPUT, "input"),
103 CNameToHtmlElement(HTML_INS, "ins"),
104 CNameToHtmlElement(HTML_KBD, "kbd"),
105 CNameToHtmlElement(HTML_LABEL, "label"),
106 CNameToHtmlElement(HTML_LEGEND, "legend"),
107 CNameToHtmlElement(HTML_LI, "li"),
108 CNameToHtmlElement(HTML_LINK, "link"),
109 CNameToHtmlElement(HTML_LUA, "lua"),
110 CNameToHtmlElement(HTML_MAIN, "main"),
111 CNameToHtmlElement(HTML_MAP, "map"),
112 CNameToHtmlElement(HTML_MARK, "mark"),
113 CNameToHtmlElement(HTML_MENU, "menu"),
114 CNameToHtmlElement(HTML_MENUITEM, "menuitem"),
115 CNameToHtmlElement(HTML_META, "meta"),
116 CNameToHtmlElement(HTML_METER, "meter"),
117 CNameToHtmlElement(HTML_NAV, "nav"),
118 CNameToHtmlElement(HTML_NOEMBED, "noembed"),
119 CNameToHtmlElement(HTML_NOSCRIPT, "noscript"),
120 CNameToHtmlElement(HTML_OBJECT, "object"),
121 CNameToHtmlElement(HTML_OL, "ol"),
122 CNameToHtmlElement(HTML_OPTGROUP, "optgroup"),
123 CNameToHtmlElement(HTML_OPTION, "option"),
124 CNameToHtmlElement(HTML_OUTPUT, "output"),
125 CNameToHtmlElement(HTML_P, "p"),
126 CNameToHtmlElement(HTML_PARAM, "param"),
127 CNameToHtmlElement(HTML_PICTURE, "picture"),
128 CNameToHtmlElement(HTML_PRE, "pre"),
129 CNameToHtmlElement(HTML_PROGRESS, "progress"),
130 CNameToHtmlElement(HTML_Q, "q"),
131 CNameToHtmlElement(HTML_RB, "rb"),
132 CNameToHtmlElement(HTML_RP, "rp"),
133 CNameToHtmlElement(HTML_RT, "rt"),
134 CNameToHtmlElement(HTML_RTC, "rtc"),
135 CNameToHtmlElement(HTML_RUBY, "ruby"),
136 CNameToHtmlElement(HTML_S, "s"),
137 CNameToHtmlElement(HTML_SAMP, "samp"),
138 CNameToHtmlElement(HTML_SCRIPT, "script"),
139 CNameToHtmlElement(HTML_SECTION, "section"),
140 CNameToHtmlElement(HTML_SELECT, "select"),
141 CNameToHtmlElement(HTML_SMALL, "small"),
142 CNameToHtmlElement(HTML_SOURCE, "source"),
143 CNameToHtmlElement(HTML_SPAN, "span"),
144 CNameToHtmlElement(HTML_STRONG, "strong"),
145 CNameToHtmlElement(HTML_STYLE, "style"),
146 CNameToHtmlElement(HTML_SUB, "sub"),
147 CNameToHtmlElement(HTML_SUMMARY, "summary"),
148 CNameToHtmlElement(HTML_SUP, "sup"),
149 CNameToHtmlElement(HTML_TABLE, "table"),
150 CNameToHtmlElement(HTML_TBODY, "tbody"),
151 CNameToHtmlElement(HTML_TD, "td"),
152 CNameToHtmlElement(HTML_TEXTAREA, "textarea"),
153 CNameToHtmlElement(HTML_TFOOT, "tfoot"),
154 CNameToHtmlElement(HTML_TH, "th"),
155 CNameToHtmlElement(HTML_THEAD, "thead"),
156 CNameToHtmlElement(HTML_TIME, "time"),
157 CNameToHtmlElement(HTML_TITLE, "title"),
158 CNameToHtmlElement(HTML_TR, "tr"),
159 CNameToHtmlElement(HTML_TRACK, "track"),
160 CNameToHtmlElement(HTML_TT, "tt"),
161 CNameToHtmlElement(HTML_U, "u"),
162 CNameToHtmlElement(HTML_UL, "ul"),
163 CNameToHtmlElement(HTML_VAR, "var"),
164 CNameToHtmlElement(HTML_VIDEO, "video"),
165 CNameToHtmlElement(HTML_WBR, "wbr")
168 HTMLElement htmlElementLookup(const char* name)
170 uint end = sizeofarray(htmlElementToName);
171 uint mid = end >> 1;
172 sint ret;
173 while(mid < end)
175 sint ret = nlstricmp(name, htmlElementToName[mid].Name);
176 if (ret == 0)
178 return htmlElementToName[mid].ID;
180 else if (ret < 0)
182 // lower half
183 end = mid;
184 mid = end >> 1;
186 else
188 // upper half
189 mid++;
190 mid += (end - mid) >> 1;
194 // not found
195 return HTML_NB_ELEMENTS;
198 // ***************************************************************************
200 /// the cookie value for session identification (nel cookie)
201 std::string CurrentCookie;
203 /// store all cookies we receive and resent them depending of the domain
204 static std::map<std::string, std::map<std::string, std::string> > HTTPCookies;
206 // ***************************************************************************
208 // ***************************************************************************
209 bool getCssLength (float &value, std::string &unit, const std::string &str, bool neg)
211 static const std::set<std::string> knownUnits = {
212 "%", "rem", "em", "px", "pt", "vw", "vh", "vi", "vb", "vmin", "vmax"
215 std::string::size_type pos = 0;
216 std::string::size_type len = str.size();
217 if (len == 0)
219 return false;
222 if (len == 1 && str[0] == '0')
224 value = 0;
225 unit.clear();
226 return true;
229 // +100px; -100px
230 if (str[0] == '+')
231 pos++;
232 else if (neg && str[0] == '-')
233 pos++;
235 while(pos < len)
237 bool isNumeric = (str[pos] >= '0' && str[pos] <= '9')
238 || (pos == 0 && str[pos] == '.')
239 || (pos > 0 && str[pos] == '.' && str[pos-1] >= '0' && str[pos-1] <= '9');
240 if (!isNumeric)
242 break;
245 pos++;
248 unit = toLowerAscii(str.substr(pos));
249 if (knownUnits.count(unit))
251 std::string tmpstr = str.substr(0, pos);
252 return fromString(tmpstr, value);
255 return false;
258 // Read a width HTML parameter. "100" or "100%". Returns true if percent (0 ~ 1) else false
259 bool getPercentage (sint32 &width, float &percent, const char *str)
261 // Percent ?
262 const char *percentChar;
263 if ((percentChar = strchr (str, '%')) != NULL)
265 std::string toto = str;
266 toto = toto.substr (0, percentChar - str);
267 fromString(toto, percent);
268 percent /= 100.f;
269 return true;
271 else
273 fromString(str, width);
274 return false;
278 static bool isHexa(char c)
280 return isdigit(c) || (tolower(c) >= 'a' && tolower(c) <= 'f');
283 static uint8 convertHexa(char c)
285 return (uint8) (tolower(c) - (isdigit(c) ? '0' : ('a' - 10)));
288 // scan a color component, and return pointer to next position
289 static const char *scanColorComponent(const char *src, uint8 &intensity)
291 if (!src) return NULL;
292 if (!isHexa(*src)) return NULL;
293 uint8 value = convertHexa(*src++) << 4;
294 if (!isHexa(*src)) return NULL;
295 value += convertHexa(*src++);
296 intensity = value;
297 return src;
300 static float hueToRgb(float m1, float m2, float h)
302 if (h < 0) h += 1.0f;
303 if (h > 1) h -= 1.0f;
304 if (h*6 < 1.0f) return m1 + (m2 - m1)*h*6;
305 if (h*2 < 1.0f) return m2;
306 if (h*3 < 2.0f) return m1 + (m2 - m1) * (2.0f/3.0f - h)*6;
307 return m1;
310 static void hslToRgb(float h, float s, float l, CRGBA &result)
312 float m1, m2;
313 if (l <= 0.5f)
314 m2 = l * (s + 1.0f);
315 else
316 m2 = l + s - l * s;
317 m1 = l*2 - m2;
319 result.R = 255 * hueToRgb(m1, m2, h + 1.0f/3.0f);
320 result.G = 255 * hueToRgb(m1, m2, h);
321 result.B = 255 * hueToRgb(m1, m2, h - 1.0f/3.0f);
322 result.A = 255;
325 class CNameToCol
327 public:
328 const char *Name;
329 CRGBA Color;
330 CNameToCol(const char *name, CRGBA color) : Name(name), Color(color) {}
333 static CNameToCol htmlColorNameToRGBA[] =
335 CNameToCol("AliceBlue", CRGBA(0xF0, 0xF8, 0xFF)),
336 CNameToCol("AntiqueWhite", CRGBA(0xFA, 0xEB, 0xD7)),
337 CNameToCol("Aqua", CRGBA(0x00, 0xFF, 0xFF)),
338 CNameToCol("Aquamarine", CRGBA(0x7F, 0xFF, 0xD4)),
339 CNameToCol("Azure", CRGBA(0xF0, 0xFF, 0xFF)),
340 CNameToCol("Beige", CRGBA(0xF5, 0xF5, 0xDC)),
341 CNameToCol("Bisque", CRGBA(0xFF, 0xE4, 0xC4)),
342 CNameToCol("Black", CRGBA(0x00, 0x00, 0x00)),
343 CNameToCol("BlanchedAlmond", CRGBA(0xFF, 0xEB, 0xCD)),
344 CNameToCol("Blue", CRGBA(0x00, 0x00, 0xFF)),
345 CNameToCol("BlueViolet", CRGBA(0x8A, 0x2B, 0xE2)),
346 CNameToCol("Brown", CRGBA(0xA5, 0x2A, 0x2A)),
347 CNameToCol("BurlyWood", CRGBA(0xDE, 0xB8, 0x87)),
348 CNameToCol("CadetBlue", CRGBA(0x5F, 0x9E, 0xA0)),
349 CNameToCol("Chartreuse", CRGBA(0x7F, 0xFF, 0x00)),
350 CNameToCol("Chocolate", CRGBA(0xD2, 0x69, 0x1E)),
351 CNameToCol("Coral", CRGBA(0xFF, 0x7F, 0x50)),
352 CNameToCol("CornflowerBlue", CRGBA(0x64, 0x95, 0xED)),
353 CNameToCol("Cornsilk", CRGBA(0xFF, 0xF8, 0xDC)),
354 CNameToCol("Crimson", CRGBA(0xDC, 0x14, 0x3C)),
355 CNameToCol("Cyan", CRGBA(0x00, 0xFF, 0xFF)),
356 CNameToCol("DarkBlue", CRGBA(0x00, 0x00, 0x8B)),
357 CNameToCol("DarkCyan", CRGBA(0x00, 0x8B, 0x8B)),
358 CNameToCol("DarkGoldenRod", CRGBA(0xB8, 0x86, 0x0B)),
359 CNameToCol("DarkGray", CRGBA(0xA9, 0xA9, 0xA9)),
360 CNameToCol("DarkGreen", CRGBA(0x00, 0x64, 0x00)),
361 CNameToCol("DarkKhaki", CRGBA(0xBD, 0xB7, 0x6B)),
362 CNameToCol("DarkMagenta", CRGBA(0x8B, 0x00, 0x8B)),
363 CNameToCol("DarkOliveGreen", CRGBA(0x55, 0x6B, 0x2F)),
364 CNameToCol("Darkorange", CRGBA(0xFF, 0x8C, 0x00)),
365 CNameToCol("DarkOrchid", CRGBA(0x99, 0x32, 0xCC)),
366 CNameToCol("DarkRed", CRGBA(0x8B, 0x00, 0x00)),
367 CNameToCol("DarkSalmon", CRGBA(0xE9, 0x96, 0x7A)),
368 CNameToCol("DarkSeaGreen", CRGBA(0x8F, 0xBC, 0x8F)),
369 CNameToCol("DarkSlateBlue", CRGBA(0x48, 0x3D, 0x8B)),
370 CNameToCol("DarkSlateGray", CRGBA(0x2F, 0x4F, 0x4F)),
371 CNameToCol("DarkTurquoise", CRGBA(0x00, 0xCE, 0xD1)),
372 CNameToCol("DarkViolet", CRGBA(0x94, 0x00, 0xD3)),
373 CNameToCol("DeepPink", CRGBA(0xFF, 0x14, 0x93)),
374 CNameToCol("DeepSkyBlue", CRGBA(0x00, 0xBF, 0xFF)),
375 CNameToCol("DimGray", CRGBA(0x69, 0x69, 0x69)),
376 CNameToCol("DodgerBlue", CRGBA(0x1E, 0x90, 0xFF)),
377 CNameToCol("Feldspar", CRGBA(0xD1, 0x92, 0x75)),
378 CNameToCol("FireBrick", CRGBA(0xB2, 0x22, 0x22)),
379 CNameToCol("FloralWhite", CRGBA(0xFF, 0xFA, 0xF0)),
380 CNameToCol("ForestGreen", CRGBA(0x22, 0x8B, 0x22)),
381 CNameToCol("Fuchsia", CRGBA(0xFF, 0x00, 0xFF)),
382 CNameToCol("Gainsboro", CRGBA(0xDC, 0xDC, 0xDC)),
383 CNameToCol("GhostWhite", CRGBA(0xF8, 0xF8, 0xFF)),
384 CNameToCol("Gold", CRGBA(0xFF, 0xD7, 0x00)),
385 CNameToCol("GoldenRod", CRGBA(0xDA, 0xA5, 0x20)),
386 CNameToCol("Gray", CRGBA(0x80, 0x80, 0x80)),
387 CNameToCol("Green", CRGBA(0x00, 0x80, 0x00)),
388 CNameToCol("GreenYellow", CRGBA(0xAD, 0xFF, 0x2F)),
389 CNameToCol("HoneyDew", CRGBA(0xF0, 0xFF, 0xF0)),
390 CNameToCol("HotPink", CRGBA(0xFF, 0x69, 0xB4)),
391 CNameToCol("IndianRed ", CRGBA(0xCD, 0x5C, 0x5C)),
392 CNameToCol("Indigo ", CRGBA(0x4B, 0x00, 0x82)),
393 CNameToCol("Ivory", CRGBA(0xFF, 0xFF, 0xF0)),
394 CNameToCol("Khaki", CRGBA(0xF0, 0xE6, 0x8C)),
395 CNameToCol("Lavender", CRGBA(0xE6, 0xE6, 0xFA)),
396 CNameToCol("LavenderBlush", CRGBA(0xFF, 0xF0, 0xF5)),
397 CNameToCol("LawnGreen", CRGBA(0x7C, 0xFC, 0x00)),
398 CNameToCol("LemonChiffon", CRGBA(0xFF, 0xFA, 0xCD)),
399 CNameToCol("LightBlue", CRGBA(0xAD, 0xD8, 0xE6)),
400 CNameToCol("LightCoral", CRGBA(0xF0, 0x80, 0x80)),
401 CNameToCol("LightCyan", CRGBA(0xE0, 0xFF, 0xFF)),
402 CNameToCol("LightGoldenRodYellow", CRGBA(0xFA, 0xFA, 0xD2)),
403 CNameToCol("LightGrey", CRGBA(0xD3, 0xD3, 0xD3)),
404 CNameToCol("LightGreen", CRGBA(0x90, 0xEE, 0x90)),
405 CNameToCol("LightPink", CRGBA(0xFF, 0xB6, 0xC1)),
406 CNameToCol("LightSalmon", CRGBA(0xFF, 0xA0, 0x7A)),
407 CNameToCol("LightSeaGreen", CRGBA(0x20, 0xB2, 0xAA)),
408 CNameToCol("LightSkyBlue", CRGBA(0x87, 0xCE, 0xFA)),
409 CNameToCol("LightSlateBlue", CRGBA(0x84, 0x70, 0xFF)),
410 CNameToCol("LightSlateGray", CRGBA(0x77, 0x88, 0x99)),
411 CNameToCol("LightSteelBlue", CRGBA(0xB0, 0xC4, 0xDE)),
412 CNameToCol("LightYellow", CRGBA(0xFF, 0xFF, 0xE0)),
413 CNameToCol("Lime", CRGBA(0x00, 0xFF, 0x00)),
414 CNameToCol("LimeGreen", CRGBA(0x32, 0xCD, 0x32)),
415 CNameToCol("Linen", CRGBA(0xFA, 0xF0, 0xE6)),
416 CNameToCol("Magenta", CRGBA(0xFF, 0x00, 0xFF)),
417 CNameToCol("Maroon", CRGBA(0x80, 0x00, 0x00)),
418 CNameToCol("MediumAquaMarine", CRGBA(0x66, 0xCD, 0xAA)),
419 CNameToCol("MediumBlue", CRGBA(0x00, 0x00, 0xCD)),
420 CNameToCol("MediumOrchid", CRGBA(0xBA, 0x55, 0xD3)),
421 CNameToCol("MediumPurple", CRGBA(0x93, 0x70, 0xD8)),
422 CNameToCol("MediumSeaGreen", CRGBA(0x3C, 0xB3, 0x71)),
423 CNameToCol("MediumSlateBlue", CRGBA(0x7B, 0x68, 0xEE)),
424 CNameToCol("MediumSpringGreen", CRGBA(0x00, 0xFA, 0x9A)),
425 CNameToCol("MediumTurquoise", CRGBA(0x48, 0xD1, 0xCC)),
426 CNameToCol("MediumVioletRed", CRGBA(0xC7, 0x15, 0x85)),
427 CNameToCol("MidnightBlue", CRGBA(0x19, 0x19, 0x70)),
428 CNameToCol("MintCream", CRGBA(0xF5, 0xFF, 0xFA)),
429 CNameToCol("MistyRose", CRGBA(0xFF, 0xE4, 0xE1)),
430 CNameToCol("Moccasin", CRGBA(0xFF, 0xE4, 0xB5)),
431 CNameToCol("NavajoWhite", CRGBA(0xFF, 0xDE, 0xAD)),
432 CNameToCol("Navy", CRGBA(0x00, 0x00, 0x80)),
433 CNameToCol("OldLace", CRGBA(0xFD, 0xF5, 0xE6)),
434 CNameToCol("Olive", CRGBA(0x80, 0x80, 0x00)),
435 CNameToCol("OliveDrab", CRGBA(0x6B, 0x8E, 0x23)),
436 CNameToCol("Orange", CRGBA(0xFF, 0xA5, 0x00)),
437 CNameToCol("OrangeRed", CRGBA(0xFF, 0x45, 0x00)),
438 CNameToCol("Orchid", CRGBA(0xDA, 0x70, 0xD6)),
439 CNameToCol("PaleGoldenRod", CRGBA(0xEE, 0xE8, 0xAA)),
440 CNameToCol("PaleGreen", CRGBA(0x98, 0xFB, 0x98)),
441 CNameToCol("PaleTurquoise", CRGBA(0xAF, 0xEE, 0xEE)),
442 CNameToCol("PaleVioletRed", CRGBA(0xD8, 0x70, 0x93)),
443 CNameToCol("PapayaWhip", CRGBA(0xFF, 0xEF, 0xD5)),
444 CNameToCol("PeachPuff", CRGBA(0xFF, 0xDA, 0xB9)),
445 CNameToCol("Peru", CRGBA(0xCD, 0x85, 0x3F)),
446 CNameToCol("Pink", CRGBA(0xFF, 0xC0, 0xCB)),
447 CNameToCol("Plum", CRGBA(0xDD, 0xA0, 0xDD)),
448 CNameToCol("PowderBlue", CRGBA(0xB0, 0xE0, 0xE6)),
449 CNameToCol("Purple", CRGBA(0x80, 0x00, 0x80)),
450 CNameToCol("Red", CRGBA(0xFF, 0x00, 0x00)),
451 CNameToCol("RosyBrown", CRGBA(0xBC, 0x8F, 0x8F)),
452 CNameToCol("RoyalBlue", CRGBA(0x41, 0x69, 0xE1)),
453 CNameToCol("SaddleBrown", CRGBA(0x8B, 0x45, 0x13)),
454 CNameToCol("Salmon", CRGBA(0xFA, 0x80, 0x72)),
455 CNameToCol("SandyBrown", CRGBA(0xF4, 0xA4, 0x60)),
456 CNameToCol("SeaGreen", CRGBA(0x2E, 0x8B, 0x57)),
457 CNameToCol("SeaShell", CRGBA(0xFF, 0xF5, 0xEE)),
458 CNameToCol("Sienna", CRGBA(0xA0, 0x52, 0x2D)),
459 CNameToCol("Silver", CRGBA(0xC0, 0xC0, 0xC0)),
460 CNameToCol("SkyBlue", CRGBA(0x87, 0xCE, 0xEB)),
461 CNameToCol("SlateBlue", CRGBA(0x6A, 0x5A, 0xCD)),
462 CNameToCol("SlateGray", CRGBA(0x70, 0x80, 0x90)),
463 CNameToCol("Snow", CRGBA(0xFF, 0xFA, 0xFA)),
464 CNameToCol("SpringGreen", CRGBA(0x00, 0xFF, 0x7F)),
465 CNameToCol("SteelBlue", CRGBA(0x46, 0x82, 0xB4)),
466 CNameToCol("Tan", CRGBA(0xD2, 0xB4, 0x8C)),
467 CNameToCol("Teal", CRGBA(0x00, 0x80, 0x80)),
468 CNameToCol("Thistle", CRGBA(0xD8, 0xBF, 0xD8)),
469 CNameToCol("Tomato", CRGBA(0xFF, 0x63, 0x47)),
470 CNameToCol("Turquoise", CRGBA(0x40, 0xE0, 0xD0)),
471 CNameToCol("Violet", CRGBA(0xEE, 0x82, 0xEE)),
472 CNameToCol("VioletRed", CRGBA(0xD0, 0x20, 0x90)),
473 CNameToCol("Wheat", CRGBA(0xF5, 0xDE, 0xB3)),
474 CNameToCol("White", CRGBA(0xFF, 0xFF, 0xFF)),
475 CNameToCol("WhiteSmoke", CRGBA(0xF5, 0xF5, 0xF5)),
476 CNameToCol("Yellow", CRGBA(0xFF, 0xFF, 0x00)),
477 CNameToCol("YellowGreen", CRGBA(0x9A, 0xCD, 0x32))
480 // scan a color from a HTML form (#rrggbb format)
481 bool scanHTMLColor(const char *src, CRGBA &dest)
483 if (!src || *src == '\0') return false;
484 if (*src == '#')
486 ++src;
487 if (strlen(src) == 3 || strlen(src) == 4)
489 bool hasAlpha = (strlen(src) == 4);
490 // check RGB for valid hex
491 if (isHexa(src[0]) && isHexa(src[1]) && isHexa(src[2]))
493 // check optional A for valid hex
494 if (hasAlpha && !isHexa(src[3])) return false;
496 dest.R = convertHexa(src[0]);
497 dest.G = convertHexa(src[1]);
498 dest.B = convertHexa(src[2]);
500 dest.R = dest.R << 4 | dest.R;
501 dest.G = dest.G << 4 | dest.G;
502 dest.B = dest.B << 4 | dest.B;
504 if (hasAlpha)
506 dest.A = convertHexa(src[3]);
507 dest.A = dest.A << 4 | dest.A;
509 else
510 dest.A = 255;
512 return true;
515 return false;
518 CRGBA result;
519 src = scanColorComponent(src, result.R); if (!src) return false;
520 src = scanColorComponent(src, result.G); if (!src) return false;
521 src = scanColorComponent(src, result.B); if (!src) return false;
522 src = scanColorComponent(src, result.A);
523 if (!src)
525 // Alpha is optional
526 result.A = 255;
528 dest = result;
529 return true;
532 // TODO: CSS Colors Level 4 support
533 // Whitespace syntax, aliases: rgb == rgba, hsl == hsla
534 // rgb(51 170 51 / 0.4) /* 40% opaque green */
535 // rgb(51 170 51 / 40%) /* 40% opaque green */
537 if (strnicmp(src, "rgb(", 4) == 0 || strnicmp(src, "rgba(", 5) == 0)
539 src += 4;
540 if (*src == '(') src++;
542 std::vector<std::string> parts;
543 NLMISC::splitString(src, ",", parts);
544 if (parts.size() >= 3)
546 CRGBA result;
547 sint tmpv;
548 float tmpf;
550 // R
551 if (getPercentage(tmpv, tmpf, parts[0].c_str())) tmpv = 255 * tmpf;
552 clamp(tmpv, 0, 255);
553 result.R = tmpv;
555 // G
556 if (getPercentage(tmpv, tmpf, parts[1].c_str())) tmpv = 255 * tmpf;
557 clamp(tmpv, 0, 255);
558 result.G = tmpv;
560 // B
561 if (getPercentage(tmpv, tmpf, parts[2].c_str())) tmpv = 255 * tmpf;
562 clamp(tmpv, 0, 255);
563 result.B = tmpv;
565 // A
566 if (parts.size() == 4)
568 if (!fromString(parts[3], tmpf)) return false;
569 if (parts[3].find_first_of("%") != std::string::npos)
570 tmpf /= 100;
572 tmpv = 255 * tmpf;
573 clamp(tmpv, 0, 255);
574 result.A = tmpv;
576 else
577 result.A = 255;
579 dest = result;
580 return true;
583 return false;
586 if (strnicmp(src, "hsl(", 4) == 0 || strnicmp(src, "hsla(", 5) == 0)
588 src += 4;
589 if (*src == '(') src++;
591 std::vector<std::string> parts;
592 NLMISC::splitString(src, ",", parts);
593 if (parts.size() >= 3)
595 sint tmpv;
596 float h, s, l;
597 // hue
598 if (!fromString(parts[0], tmpv)) return false;
599 tmpv = ((tmpv % 360) + 360) % 360;
600 h = (float) tmpv / 360.0f;
602 // saturation
603 if (!getPercentage(tmpv, s, parts[1].c_str())) return false;
604 clamp(s, 0.0f, 1.0f);
606 // lightness
607 if (!getPercentage(tmpv, l, parts[2].c_str())) return false;
608 clamp(l, 0.0f, 1.0f);
610 CRGBA result;
611 hslToRgb(h, s, l, result);
613 // A
614 if (parts.size() == 4)
616 float tmpf;
617 if (!fromString(parts[3], tmpf)) return false;
618 if (parts[3].find_first_of("%") != std::string::npos)
619 tmpf /= 100;
620 clamp(tmpf, 0.0f, 1.0f);
621 result.A = 255 * tmpf;
624 dest = result;
625 return true;
628 return false;
631 if (nlstricmp(src, "transparent") == 0)
633 dest = CRGBA::Transparent;
634 return true;
638 // slow but should suffice for now
639 for(uint k = 0; k < sizeofarray(htmlColorNameToRGBA); ++k)
641 if (nlstricmp(src, htmlColorNameToRGBA[k].Name) == 0)
643 dest = htmlColorNameToRGBA[k].Color;
644 return true;
647 return false;
651 // ***************************************************************************
653 CRGBA getColor (const char *color)
655 if (strlen (color) != 7 && strlen (color) != 9 )
656 return CRGBA::White;
657 char tmp[3] = {0,0,0};
658 CRGBA dst;
659 int value;
660 tmp[0] = color[1];
661 tmp[1] = color[2];
662 sscanf (tmp, "%x", &value);
663 dst.R = uint8(value);
664 tmp[0] = color[3];
665 tmp[1] = color[4];
666 sscanf (tmp, "%x", &value);
667 dst.G = uint8(value);
668 tmp[0] = color[5];
669 tmp[1] = color[6];
670 sscanf (tmp, "%x", &value);
671 dst.B = uint8(value);
672 if (strlen (color) == 9)
674 tmp[0] = color[7];
675 tmp[1] = color[8];
676 sscanf (tmp, "%x", &value);
677 dst.A = uint8(value);
679 else
681 // extension to html ; try to parse an additional alpha
682 dst.A = 255;
684 return dst;
687 std::string getRGBAString(const CRGBA &color)
689 return toString("rgba(%d, %d, %d, %.1f)", color.R, color.G, color.B, color.A / 255.f);
692 // update HTTPCookies list
693 static void receiveCookie(const char *nsformat, const std::string &domain, bool trusted)
695 // 0 1 2 3 4 5 6
696 // domain tailmatch path secure expires name value
697 // .app.ryzom.com TRUE / FALSE 1234 ryzomId AAAAAAAA|BBBBBBBB|CCCCCCCC
698 // #HttpOnly_app.ryzom.com FALSE / FALSE 0 PHPSESSID sess-id-value
699 std::string cookie(nsformat);
701 std::vector<std::string> chunks;
702 splitString(cookie, "\t", chunks);
703 if (chunks.size() < 6)
705 nlwarning("invalid cookie format '%s'", cookie.c_str());
708 if (chunks[0].find("#HttpOnly_") == 0)
710 chunks[0] = chunks[0].substr(10);
713 // make sure domain is lowercase
714 chunks[0] = toLowerAscii(chunks[0]);
716 if (chunks[0] != domain && chunks[0] != std::string("." + domain))
718 // cookie is for different domain
719 //nlinfo("cookie for different domain ('%s')", nsformat);
720 return;
723 if (chunks[5] == "ryzomId")
725 // we receive this cookie because we are telling curl about this on send
726 // normally, this cookie should be set from client and not from headers
727 // it's used for R2 sessions
728 if (trusted && CurrentCookie != chunks[6])
730 CurrentCookie = chunks[6];
731 nlwarning("received ryzomId cookie '%s' from trusted domain '%s'", CurrentCookie.c_str(), domain.c_str());
734 else
736 uint32 expires = 0;
737 fromString(chunks[4], expires);
738 // expires == 0 is session cookie
739 if (expires > 0)
741 time_t now;
742 time(&now);
743 if (expires < (uint32)now)
745 nlwarning("cookie expired, remove from list '%s'", nsformat);
746 HTTPCookies[domain].erase(chunks[5]);
748 return;
752 // this overrides cookies with same name, but different paths
753 //nlwarning("save domain '%s' cookie '%s' value '%s'", domain.c_str(), chunks[5].c_str(), nsformat);
754 HTTPCookies[domain][chunks[5]] = nsformat;
758 // update HTTPCookies with cookies received from curl
759 void receiveCookies (CURL *curl, const std::string &domain, bool trusted)
761 struct curl_slist *cookies = NULL;
762 if (curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies) == CURLE_OK)
764 struct curl_slist *nc;
765 nc = cookies;
766 while(nc)
768 //nlwarning("received cookie '%s'", nc->data);
769 receiveCookie(nc->data, domain, trusted);
770 nc = nc->next;
773 curl_slist_free_all(cookies);
777 // add all cookies for domain to curl handle
778 void sendCookies(CURL *curl, const std::string &domain, bool trusted)
780 // enable curl cookie engine
781 curl_easy_setopt(curl, CURLOPT_COOKIELIST, "");
783 if (domain.empty())
784 return;
786 if (trusted && !CurrentCookie.empty())
788 // domain tailmatch path secure expires name value
789 // .app.ryzom.com TRUE / FALSE 1234 ryzomId AAAAAAAA|BBBBBBBB|CCCCCCCC
790 // #HttpOnly_app.ryzom.com FALSE / FALSE 0 PHPSESSID sess-id-value
791 std::string cookie;
792 // set tailmatch
793 if (domain[0] != '.' && domain[0] != '#')
794 cookie = "." + domain + "\tTRUE";
795 else
796 cookie = domain + "\tFALSE";
797 cookie += "\t/\tFALSE\t0\tryzomId\t" + CurrentCookie;
798 curl_easy_setopt(curl, CURLOPT_COOKIELIST, cookie.c_str());
799 //nlwarning("domain '%s', cookie '%s'", domain.c_str(), cookie.c_str());
802 if(!HTTPCookies[domain].empty())
804 for(std::map<std::string, std::string>::iterator it = HTTPCookies[domain].begin(); it != HTTPCookies[domain].end(); it++)
806 curl_easy_setopt(curl, CURLOPT_COOKIELIST, it->second.c_str());
807 //nlwarning("set domain '%s' cookie '%s'", domain.c_str(), it->second.c_str());
812 // ***************************************************************************