PEBL 2.2
Psychology Experiment Building Language - Cross-platform psychological experiment development system
PEBLUtility.cpp
Go to the documentation of this file.
1//* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
3// Name: utility/PEBLUtility.cpp
4// Purpose: Miscellaneous Utility Functions used in PEBL
5// Author: Shane T. Mueller, Ph.D.
6// Copyright: (c) 2003-2026 Shane T. Mueller <smueller@obereed.net>
7// License: GPL 2
8//
9//
10//
11// This file is part of the PEBL project.
12//
13// PEBL is free software; you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation; either version 2 of the License, or
16// (at your option) any later version.
17//
18// PEBL is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with PEBL; if not, write to the Free Software
25// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
28#ifdef PEBL_WIN32
29#include <winsock2.h> // Must be very first to avoid conflicts
30#endif
31
32//Include this before peblutility.h because is it a header-only library,
33//and the JSMN_HEADER macro disables loading of functions, so it must
34//first be loaded here to compile right.
35#include "jsmn.h"
36
37#include "PEBLUtility.h"
38#include "PError.h"
39#include "rc_ptrs.h"
40#include "../base/Variant.h"
41#include "../base/PComplexData.h"
42#include "../base/PList.h"
43#include "../objects/PCustomObject.h"
44#include "../devices/PKeyboard.h"
45#include "../apps/Globals.h"
46#include "md5.h"
47
48
49
50
51
52#include <errno.h>
53#include <ctype.h>
54#include <string>
55#include <stdlib.h>
56#include <cmath>
57#include <iostream>
58//#include <strstream> //May be depracated?
59
60#include <algorithm>
61
62//#if !defined(PEBL_OSX)
63//#include <png.h>
64//#endif
65
66#include <dirent.h>
67//#include <errno.h>
68
69
70#ifdef PEBL_WIN32
71//#include <direct.h> // Not available in MSYS2, use POSIX headers instead
72//#include <windows.h>
73//#include <bits/types.h>
74#include <shlobj.h>
75//#include <winbase.h>
76#include <sys/stat.h> // For mkdir on MSYS2
77#elif defined(PEBL_LINUX)
78#include <sys/stat.h>
79#include <unistd.h>
80#include <bits/types.h>
81#include <pwd.h>
82#elif defined (PEBL_EMSCRIPTEN)
83#include <sys/stat.h>
84#include <unistd.h>
85#include <sys/types.h>
86#include <pwd.h>
87#elif defined (PEBL_OSX)
88#include <unistd.h>
89#include <pwd.h>
90#endif
91
92#include <unistd.h>
93#include <sys/stat.h>
94#include <stdio.h>
95#include <fcntl.h> //For md5file O_RDONLY
96#include <sys/types.h>
97#include <sys/stat.h>
98
99
100
101
102//there is an included version of mman.h for windows
103//compilation--this should be available on linux/osx in
104//system libraries. This is done for the mlock function,
105//which is used in the MD5File utility function here.
106#if defined(PEBL_LINUX) or defined(PEBL_OSX) or defined(PEBL_EMSCRIPTEN)
107#include <sys/mman.h>
108#elif defined(PEBL_WIN32)
109#include "mman.h"
110#endif
111
112#include <map>
113
114//Some math libraries contain this, but let's not take any chances.
115#define PI 3.141592653589793238462643383279502884197169399375
116
117
118using std::cout;
119using std::endl;
120
121// Static keycode lookup tables to replace SDL_GetKeyFromName and SDL_GetKeyName
122// These eliminate SDL dependencies while maintaining identical functionality
123
124static PEBL_Keycode PEBL_GetKeyFromName(const char* name) {
125 static std::map<std::string, PEBL_Keycode> nameToKeycode;
126
127 // Initialize map on first use
128 if (nameToKeycode.empty()) {
129 // ASCII lowercase letters
130 nameToKeycode["a"] = PEBL_KEYCODE_a;
131 nameToKeycode["b"] = PEBL_KEYCODE_b;
132 nameToKeycode["c"] = PEBL_KEYCODE_c;
133 nameToKeycode["d"] = PEBL_KEYCODE_d;
134 nameToKeycode["e"] = PEBL_KEYCODE_e;
135 nameToKeycode["f"] = PEBL_KEYCODE_f;
136 nameToKeycode["g"] = PEBL_KEYCODE_g;
137 nameToKeycode["h"] = PEBL_KEYCODE_h;
138 nameToKeycode["i"] = PEBL_KEYCODE_i;
139 nameToKeycode["j"] = PEBL_KEYCODE_j;
140 nameToKeycode["k"] = PEBL_KEYCODE_k;
141 nameToKeycode["l"] = PEBL_KEYCODE_l;
142 nameToKeycode["m"] = PEBL_KEYCODE_m;
143 nameToKeycode["n"] = PEBL_KEYCODE_n;
144 nameToKeycode["o"] = PEBL_KEYCODE_o;
145 nameToKeycode["p"] = PEBL_KEYCODE_p;
146 nameToKeycode["q"] = PEBL_KEYCODE_q;
147 nameToKeycode["r"] = PEBL_KEYCODE_r;
148 nameToKeycode["s"] = PEBL_KEYCODE_s;
149 nameToKeycode["t"] = PEBL_KEYCODE_t;
150 nameToKeycode["u"] = PEBL_KEYCODE_u;
151 nameToKeycode["v"] = PEBL_KEYCODE_v;
152 nameToKeycode["w"] = PEBL_KEYCODE_w;
153 nameToKeycode["x"] = PEBL_KEYCODE_x;
154 nameToKeycode["y"] = PEBL_KEYCODE_y;
155 nameToKeycode["z"] = PEBL_KEYCODE_z;
156
157 // Digits
158 nameToKeycode["0"] = PEBL_KEYCODE_0;
159 nameToKeycode["1"] = PEBL_KEYCODE_1;
160 nameToKeycode["2"] = PEBL_KEYCODE_2;
161 nameToKeycode["3"] = PEBL_KEYCODE_3;
162 nameToKeycode["4"] = PEBL_KEYCODE_4;
163 nameToKeycode["5"] = PEBL_KEYCODE_5;
164 nameToKeycode["6"] = PEBL_KEYCODE_6;
165 nameToKeycode["7"] = PEBL_KEYCODE_7;
166 nameToKeycode["8"] = PEBL_KEYCODE_8;
167 nameToKeycode["9"] = PEBL_KEYCODE_9;
168
169 // Special characters
170 nameToKeycode["space"] = PEBL_KEYCODE_SPACE;
171 nameToKeycode["return"] = PEBL_KEYCODE_RETURN;
172 nameToKeycode["escape"] = PEBL_KEYCODE_ESCAPE;
173 nameToKeycode["backspace"] = PEBL_KEYCODE_BACKSPACE;
174 nameToKeycode["tab"] = PEBL_KEYCODE_TAB;
175 nameToKeycode["!"] = PEBL_KEYCODE_EXCLAIM;
176 nameToKeycode["\""] = PEBL_KEYCODE_QUOTEDBL;
177 nameToKeycode["#"] = PEBL_KEYCODE_HASH;
178 nameToKeycode["$"] = PEBL_KEYCODE_DOLLAR;
179 nameToKeycode["%"] = PEBL_KEYCODE_PERCENT;
180 nameToKeycode["&"] = PEBL_KEYCODE_AMPERSAND;
181 nameToKeycode["'"] = PEBL_KEYCODE_QUOTE;
182 nameToKeycode["("] = PEBL_KEYCODE_LEFTPAREN;
183 nameToKeycode[")"] = PEBL_KEYCODE_RIGHTPAREN;
184 nameToKeycode["*"] = PEBL_KEYCODE_ASTERISK;
185 nameToKeycode["+"] = PEBL_KEYCODE_PLUS;
186 nameToKeycode[","] = PEBL_KEYCODE_COMMA;
187 nameToKeycode["-"] = PEBL_KEYCODE_MINUS;
188 nameToKeycode["."] = PEBL_KEYCODE_PERIOD;
189 nameToKeycode["/"] = PEBL_KEYCODE_SLASH;
190 nameToKeycode[":"] = PEBL_KEYCODE_COLON;
191 nameToKeycode[";"] = PEBL_KEYCODE_SEMICOLON;
192 nameToKeycode["<"] = PEBL_KEYCODE_LESS;
193 nameToKeycode["="] = PEBL_KEYCODE_EQUALS;
194 nameToKeycode[">"] = PEBL_KEYCODE_GREATER;
195 nameToKeycode["?"] = PEBL_KEYCODE_QUESTION;
196 nameToKeycode["@"] = PEBL_KEYCODE_AT;
197 nameToKeycode["["] = PEBL_KEYCODE_LEFTBRACKET;
198 nameToKeycode["\\"] = PEBL_KEYCODE_BACKSLASH;
199 nameToKeycode["]"] = PEBL_KEYCODE_RIGHTBRACKET;
200 nameToKeycode["^"] = PEBL_KEYCODE_CARET;
201 nameToKeycode["_"] = PEBL_KEYCODE_UNDERSCORE;
202 nameToKeycode["`"] = PEBL_KEYCODE_BACKQUOTE;
203
204 // Function keys
205 nameToKeycode["f1"] = PEBL_KEYCODE_F1;
206 nameToKeycode["f2"] = PEBL_KEYCODE_F2;
207 nameToKeycode["f3"] = PEBL_KEYCODE_F3;
208 nameToKeycode["f4"] = PEBL_KEYCODE_F4;
209 nameToKeycode["f5"] = PEBL_KEYCODE_F5;
210 nameToKeycode["f6"] = PEBL_KEYCODE_F6;
211 nameToKeycode["f7"] = PEBL_KEYCODE_F7;
212 nameToKeycode["f8"] = PEBL_KEYCODE_F8;
213 nameToKeycode["f9"] = PEBL_KEYCODE_F9;
214 nameToKeycode["f10"] = PEBL_KEYCODE_F10;
215 nameToKeycode["f11"] = PEBL_KEYCODE_F11;
216 nameToKeycode["f12"] = PEBL_KEYCODE_F12;
217
218 // Arrow keys and navigation
219 nameToKeycode["up"] = PEBL_KEYCODE_UP;
220 nameToKeycode["down"] = PEBL_KEYCODE_DOWN;
221 nameToKeycode["left"] = PEBL_KEYCODE_LEFT;
222 nameToKeycode["right"] = PEBL_KEYCODE_RIGHT;
223 nameToKeycode["insert"] = PEBL_KEYCODE_INSERT;
224 nameToKeycode["delete"] = PEBL_KEYCODE_DELETE;
225 nameToKeycode["home"] = PEBL_KEYCODE_HOME;
226 nameToKeycode["end"] = PEBL_KEYCODE_END;
227 nameToKeycode["pageup"] = PEBL_KEYCODE_PAGEUP;
228 nameToKeycode["pagedown"] = PEBL_KEYCODE_PAGEDOWN;
229
230 // Modifier keys
231 nameToKeycode["capslock"] = PEBL_KEYCODE_CAPSLOCK;
232 nameToKeycode["scrolllock"] = PEBL_KEYCODE_SCROLLLOCK;
233 nameToKeycode["lshift"] = PEBL_KEYCODE_LSHIFT;
234 nameToKeycode["rshift"] = PEBL_KEYCODE_RSHIFT;
235 nameToKeycode["lctrl"] = PEBL_KEYCODE_LCTRL;
236 nameToKeycode["rctrl"] = PEBL_KEYCODE_RCTRL;
237 nameToKeycode["lalt"] = PEBL_KEYCODE_LALT;
238 nameToKeycode["ralt"] = PEBL_KEYCODE_RALT;
239 nameToKeycode["lgui"] = PEBL_KEYCODE_LGUI;
240 nameToKeycode["rgui"] = PEBL_KEYCODE_RGUI;
241
242 // Other special keys
243 nameToKeycode["pause"] = PEBL_KEYCODE_PAUSE;
244 nameToKeycode["printscreen"] = PEBL_KEYCODE_PRINTSCREEN;
245 nameToKeycode["menu"] = PEBL_KEYCODE_MENU;
246 nameToKeycode["help"] = PEBL_KEYCODE_HELP;
247 nameToKeycode["sysreq"] = PEBL_KEYCODE_SYSREQ;
248 nameToKeycode["power"] = PEBL_KEYCODE_POWER;
249 nameToKeycode["undo"] = PEBL_KEYCODE_UNDO;
250 nameToKeycode["clear"] = PEBL_KEYCODE_CLEAR;
251 nameToKeycode["mode"] = PEBL_KEYCODE_MODE;
252 }
253
254 std::map<std::string, PEBL_Keycode>::const_iterator it = nameToKeycode.find(name);
255 if (it != nameToKeycode.end()) {
256 return it->second;
257 }
259}
260
261static std::string PEBL_GetKeyName(PEBL_Keycode code) {
262 // Single character keys (a-z, 0-9, punctuation)
263 if (code >= PEBL_KEYCODE_a && code <= PEBL_KEYCODE_z) {
264 return std::string(1, (char)code);
265 }
266 if (code >= PEBL_KEYCODE_0 && code <= PEBL_KEYCODE_9) {
267 return std::string(1, (char)code);
268 }
269
270 // Punctuation and special characters
271 switch(code) {
272 case PEBL_KEYCODE_EXCLAIM: return "!";
273 case PEBL_KEYCODE_QUOTEDBL: return "\"";
274 case PEBL_KEYCODE_HASH: return "#";
275 case PEBL_KEYCODE_DOLLAR: return "$";
276 case PEBL_KEYCODE_PERCENT: return "%";
277 case PEBL_KEYCODE_AMPERSAND: return "&";
278 case PEBL_KEYCODE_QUOTE: return "'";
279 case PEBL_KEYCODE_LEFTPAREN: return "(";
280 case PEBL_KEYCODE_RIGHTPAREN: return ")";
281 case PEBL_KEYCODE_ASTERISK: return "*";
282 case PEBL_KEYCODE_PLUS: return "+";
283 case PEBL_KEYCODE_COMMA: return ",";
284 case PEBL_KEYCODE_MINUS: return "-";
285 case PEBL_KEYCODE_PERIOD: return ".";
286 case PEBL_KEYCODE_SLASH: return "/";
287 case PEBL_KEYCODE_COLON: return ":";
288 case PEBL_KEYCODE_SEMICOLON: return ";";
289 case PEBL_KEYCODE_LESS: return "<";
290 case PEBL_KEYCODE_EQUALS: return "=";
291 case PEBL_KEYCODE_GREATER: return ">";
292 case PEBL_KEYCODE_QUESTION: return "?";
293 case PEBL_KEYCODE_AT: return "@";
294 case PEBL_KEYCODE_LEFTBRACKET: return "[";
295 case PEBL_KEYCODE_BACKSLASH: return "\\";
296 case PEBL_KEYCODE_RIGHTBRACKET: return "]";
297 case PEBL_KEYCODE_CARET: return "^";
298 case PEBL_KEYCODE_UNDERSCORE: return "_";
299 case PEBL_KEYCODE_BACKQUOTE: return "`";
300
301 // Named special keys
302 case PEBL_KEYCODE_SPACE: return "Space";
303 case PEBL_KEYCODE_RETURN: return "Return";
304 case PEBL_KEYCODE_ESCAPE: return "Escape";
305 case PEBL_KEYCODE_BACKSPACE: return "Backspace";
306 case PEBL_KEYCODE_TAB: return "Tab";
307 case PEBL_KEYCODE_DELETE: return "Delete";
308
309 // Function keys
310 case PEBL_KEYCODE_F1: return "F1";
311 case PEBL_KEYCODE_F2: return "F2";
312 case PEBL_KEYCODE_F3: return "F3";
313 case PEBL_KEYCODE_F4: return "F4";
314 case PEBL_KEYCODE_F5: return "F5";
315 case PEBL_KEYCODE_F6: return "F6";
316 case PEBL_KEYCODE_F7: return "F7";
317 case PEBL_KEYCODE_F8: return "F8";
318 case PEBL_KEYCODE_F9: return "F9";
319 case PEBL_KEYCODE_F10: return "F10";
320 case PEBL_KEYCODE_F11: return "F11";
321 case PEBL_KEYCODE_F12: return "F12";
322
323 // Arrow keys
324 case PEBL_KEYCODE_UP: return "Up";
325 case PEBL_KEYCODE_DOWN: return "Down";
326 case PEBL_KEYCODE_LEFT: return "Left";
327 case PEBL_KEYCODE_RIGHT: return "Right";
328
329 // Navigation
330 case PEBL_KEYCODE_INSERT: return "Insert";
331 case PEBL_KEYCODE_HOME: return "Home";
332 case PEBL_KEYCODE_END: return "End";
333 case PEBL_KEYCODE_PAGEUP: return "PageUp";
334 case PEBL_KEYCODE_PAGEDOWN: return "PageDown";
335
336 // Modifiers
337 case PEBL_KEYCODE_CAPSLOCK: return "CapsLock";
338 case PEBL_KEYCODE_SCROLLLOCK: return "ScrollLock";
339 case PEBL_KEYCODE_LSHIFT: return "Left Shift";
340 case PEBL_KEYCODE_RSHIFT: return "Right Shift";
341 case PEBL_KEYCODE_LCTRL: return "Left Ctrl";
342 case PEBL_KEYCODE_RCTRL: return "Right Ctrl";
343 case PEBL_KEYCODE_LALT: return "Left Alt";
344 case PEBL_KEYCODE_RALT: return "Right Alt";
345 case PEBL_KEYCODE_LGUI: return "Left GUI";
346 case PEBL_KEYCODE_RGUI: return "Right GUI";
347
348 // Other special keys
349 case PEBL_KEYCODE_PAUSE: return "Pause";
350 case PEBL_KEYCODE_PRINTSCREEN: return "PrintScreen";
351 case PEBL_KEYCODE_MENU: return "Menu";
352 case PEBL_KEYCODE_HELP: return "Help";
353 case PEBL_KEYCODE_SYSREQ: return "SysReq";
354 case PEBL_KEYCODE_POWER: return "Power";
355 case PEBL_KEYCODE_UNDO: return "Undo";
356 case PEBL_KEYCODE_CLEAR: return "Clear";
357 case PEBL_KEYCODE_MODE: return "ModeSwitch";
358
359 default: return "";
360 }
361}
362
363// Pre-initialize keycode lookup tables to avoid lazy-init delay on first keypress
364// This is called during environment initialization to prevent timing measurement artifacts
365// in psychological experiments where response time accuracy is critical
367 // Force initialization of the static map in PEBL_GetKeyFromName by making a dummy call
368 (void)PEBL_GetKeyFromName("a");
369
370 // PEBL_GetKeyName uses a switch statement (no lazy init needed), but call it anyway
371 // for symmetry and in case the implementation changes
372 (void)PEBL_GetKeyName(PEBL_KEYCODE_a);
373}
374
375std::string PEBLUtility::ToUpper(const std::string & text)
376{
377 std::string newtext(text);
378 std::transform(newtext.begin(), newtext.end(), newtext.begin(), ::toupper);
379 return newtext;
380}
381
382
383
384std::string PEBLUtility::ToLower(const std::string & text)
385{
386 std::string newtext(text);
387 std::transform(newtext.begin(), newtext.end(), newtext.begin(), ::tolower);
388 return newtext;
389}
390
391
392//When given a filename, this will strip the filename from
393//the path and return the path. If given a directory name
394// (ending with a '/' or '\'), it won't strip that character.
395const std::string PEBLUtility::StripFile(const std::string & file)
396{
397
398#if defined PEBL_UNIX
399 char separator = '/';
400#else
401 char separator = '\\';
402#endif
403
404 unsigned long int lastsep = 0;
405 unsigned long int i = file.size();
406 //end
407 //Start at the end of the filename and move backward
408 while(i > 0)
409 {
410 if(file[i] == separator)
411 {
412 lastsep = i;
413 return file.substr(0,lastsep+1);
414 }
415 i--;
416 }
417 return "";
418}
419
420
421
422//When given a filename, this will strip off the path
423//and return the base filename.
424const std::string PEBLUtility::GetBaseFileName(const std::string & file)
425{
426
427#if defined PEBL_UNIX
428 char separator = '/';
429#else
430 char separator = '\\';
431#endif
432
433 unsigned long int lastsep = 0;
434 unsigned long int i = file.size();
435 //end
436 //Start at the end of the filename and move backward
437 while(i > 0)
438 {
439 if(file[i] == separator)
440 {
441 lastsep = i;
442 return file.substr(lastsep+1,-1);
443 }
444 i--;
445 }
446 return "";
447}
448
449
450
451// ///This returns a pointer to an upper-case version of the text.
452// ///buffer better be at least n items long.
453// void PEBLUtility::ToUpper(const char* text, char* buffer, int n)
454// {
455// //Go through each letter, copying the upper-case version to buffer.
456// //Stop before the last letter because we need a \0.
457// int i = 0;
458// while(text[i] != '\0' && i < (n-1))
459// {
460// buffer[i] = toupper(text[i]);
461// i++;
462// }
463// //Add an end-of-string character
464// buffer[i] = '\0';
465// }
466
467
468
469// ///This returns a pointer to a lower-case version of the text.
470// void PEBLUtility::ToLower(const char* text, char* buffer, int n)
471// {
472
473// //Go through each letter, copying the lower-case version to buffer.
474// //Stop before the last letter because we need a \0.
475// int i = 0;
476// while(text[i] != '\0' && i < (n-1))
477// {
478// buffer[i] = tolower(text[i]);
479// i++;
480// }
481
482// //Add an end-of-string character
483// buffer[i] = '\0';
484
485
486// }
487
488
489Variant PEBLUtility::Tokenize(const char* line, char separator)
490{
491 //We have a string with separators in it. Go through it character by character and
492 //form a list out of the tokens.
493
494
495 PList * plist = new PList;
496 int i = 0;
497 int begin = 0;
498 char * token;
499
500 int tokensize;
501
502 //Go through each item of the string. Cut a token whenever you get to a separator or
503 //a character that might be the end of the line.
504 while(true)
505 {
506 if(line[i] == separator
507 || line[i] == '\0'
508 || line[i] == 10
509 || line[i] == 13
510 || separator == 0)
511 {
512
513 //line[i] is the separator; the token is from
514 //begin to line[i-1]
515
516 //tokensize should be from begin to now, substracting out the separator.
517 tokensize = i-begin+(separator==0);
518
519 //if separator ==0, tokensize is really one bigger, as the separator width is 0.
520
521 token = (char*)malloc((tokensize+1) * sizeof(char));
522 strncpy(token, &line[begin], tokensize);
523 token[tokensize]= '\0';
524
525
526 plist->PushBack(Variant(token));
527 begin = i+1; //move begin to the next piece of text.
528 }
529
530
531 if(line[i] == '\0'|| line[i] == 10 || line[i] == 13)
532 break;
533
534 //we need to not copy a final empty element if separator==0
535 if(separator==0 and line[begin]=='\0')
536 {
537 break;
538 }
539 i++;
540
541 }
542
544 PComplexData * pcd = new PComplexData(tmpObj);
545 return Variant(pcd);
546}
547
548
550{
551#if defined(strold)
552 return strtold(mystring,0);
553#else
554 return (pDouble)strtod(mystring,0);
555#endif
556}
557
558
559
561{
562 return (pDouble)rand() / RAND_MAX;
563}
564
565
570{
571
572 pDouble x1 = RandomUniform();
573 pDouble x2 = RandomUniform();
574
575 return sqrt(-2 * log(x1)) * cos(2 * PI * x2);
576}
577
579{
580#if defined(log2)
581 return (pDouble)log2((pDouble)val);
582#elif defined(log2l)
583 return log2l(val);
584#else
585 return logl(val) / logl(2);
586#endif
587}
588
590{
591#if defined(round)
592 return round((pDouble)val);
593#elif defined(roundl)
594 return roundl(val);
595#else
596 return (pInt) floor(val+.5);
597#endif
598}
599
601{
602 pDouble off = pow(10,prec);
603 //cout << "Rounding " << val <<" to : " << off << endl;
604#if defined(round)
605 return (pDouble)round((pDouble)val*off)/off;
606#elif defined(roundl)
607 return (pDouble)roundl(val*off)/off;
608#else
609 return (pDouble) ((pInt)(floor(val*off+.5))/off);
610#endif
611}
612
614{
615#if defined(truncl)
616 return truncl(val);
617#elif defined(trunc)
618 return trunc((pDouble)val);
619#else
620 int sign = val < 0 ? -1: 1;
621 return sign * Round(sign * val);
622#endif
623
624}
625
626
627
629{
630 std::string letters = PEBLUtility::ToLower(let);
631
632#ifndef PEBL_VALIDATOR
633 PEBL_Keycode code = PEBL_GetKeyFromName(letters.c_str());
634#else
635 int code = 0; // Validator mode: return unknown
636#endif
637
638 //cout <<"testing letters: [" << letters << "]"<<endl;
639
640#ifndef PEBL_VALIDATOR
641 if(code==PEBL_KEYCODE_UNKNOWN)
642#else
643 if(code==0)
644#endif
645 {
646
647
648 //
649 //
650 if( letters == " " ||
651 letters == "<space>")
652 return PEBL_KEYCODE_SPACE;
653 if( letters == "<return>")
654 return PEBL_KEYCODE_RETURN;
655 if(letters == "<esc>"|| letters == "<escape>")
656 {
657 //cout << "Translating escape code\n";
658 return PEBL_KEYCODE_ESCAPE;
659 }
660 if(letters== "<anykey>")
661 return PEBL_KEYCODE_ANYKEY;
662 if(letters == "<back>" || letters == "<backspace>" )
664
665 if(letters=="<delete>") return PEBL_KEYCODE_DELETE;
666
667 if(letters == "<left>") return PEBL_KEYCODE_LEFT;
668 if(letters == "<right>") return PEBL_KEYCODE_RIGHT;
669 if(letters == "<down>") return PEBL_KEYCODE_DOWN;
670 if(letters == "<up>") return PEBL_KEYCODE_UP;
671
672 if(letters == "<f1>") return PEBL_KEYCODE_F1;
673 if(letters == "<f2>") return PEBL_KEYCODE_F2;
674 if(letters == "<f3>") return PEBL_KEYCODE_F3;
675 if(letters == "<f4>") return PEBL_KEYCODE_F4;
676 if(letters == "<f5>") return PEBL_KEYCODE_F5;
677 if(letters == "<f6>") return PEBL_KEYCODE_F6;
678 if(letters == "<f7>") return PEBL_KEYCODE_F7;
679 if(letters == "<f8>") return PEBL_KEYCODE_F8;
680 if(letters == "<f9>") return PEBL_KEYCODE_F9;
681 if(letters == "<f10>") return PEBL_KEYCODE_F10;
682 if(letters == "<f11>") return PEBL_KEYCODE_F11;
683 if(letters == "<f12>") return PEBL_KEYCODE_F12;
684
685
686 /* Key state modifier keys */
687
688 if(letters == "<numlock>") return PEBL_KEYCODE_NUMLOCK;
689 if(letters == "<capslock>") return PEBL_KEYCODE_CAPSLOCK;
690 if(letters == "<scrolllock>") return PEBL_KEYCODE_SCROLLLOCK;
691 if(letters == "<lshift>") return PEBL_KEYCODE_LSHIFT;
692 if(letters == "<rshift>") return PEBL_KEYCODE_RSHIFT;
693
694 if(letters == "<rctrl>") return PEBL_KEYCODE_RCTRL;
695 if(letters == "<lctrl>") return PEBL_KEYCODE_LCTRL;
696 if(letters == "<ralt>") return PEBL_KEYCODE_RALT;
697 if(letters == "<lalt>") return PEBL_KEYCODE_LALT;
698 // if(letters == "<rmeta>") return PEBL_KEYCODE_RMETA;
699 // if(letters == "<lmeta>") return PEBL_KEYCODE_LMETA;
700 // if(letters == "<lsuper>") return PEBL_KEYCODE_LSUPER;
701 // if(letters == "<rsuper>") return PEBL_KEYCODE_RSUPER;
702 if(letters == "<mode>") return PEBL_KEYCODE_MODE;
703 // if(letters == "<compose>") return PEBL_KEYCODE_COMPOSE;
704
705
706 if(letters == "<kp_0>") return PEBL_KEYCODE_KP_0;
707 if(letters == "<kp_1>") return PEBL_KEYCODE_KP_1;
708 if(letters == "<kp_2>") return PEBL_KEYCODE_KP_2;
709 if(letters == "<kp_3>") return PEBL_KEYCODE_KP_3;
710 if(letters == "<kp_4>") return PEBL_KEYCODE_KP_4;
711 if(letters == "<kp_5>") return PEBL_KEYCODE_KP_5;
712 if(letters == "<kp_6>") return PEBL_KEYCODE_KP_6;
713 if(letters == "<kp_7>") return PEBL_KEYCODE_KP_7;
714 if(letters == "<kp_8>") return PEBL_KEYCODE_KP_8;
715 if(letters == "<kp_9>") return PEBL_KEYCODE_KP_9;
716
717 if(letters == "<kp_period>" ) return PEBL_KEYCODE_KP_PERIOD;
718 if(letters == "<kp_divide>" ) return PEBL_KEYCODE_KP_DIVIDE;
719 if(letters == "<kp_multiply>") return PEBL_KEYCODE_KP_MULTIPLY;
720 if(letters == "<kp_minus>" ) return PEBL_KEYCODE_KP_MINUS;
721 if(letters == "<kp_plus>" ) return PEBL_KEYCODE_KP_PLUS;
722 if(letters == "<kp_equals>" ) return PEBL_KEYCODE_KP_EQUALS;
723 if(letters == "<kp_enter>" ) return PEBL_KEYCODE_KP_ENTER;
724
725 if(letters == "<insert>" ) return PEBL_KEYCODE_INSERT;
726 if(letters == "<home>" ) return PEBL_KEYCODE_HOME;
727 if(letters == "<end>" ) return PEBL_KEYCODE_END;
728 if(letters == "<pageup>" ) return PEBL_KEYCODE_PAGEUP;
729 if(letters == "<pagedown>") return PEBL_KEYCODE_PAGEDOWN;
730 std::cerr << "Unknown keycode!!!\n";
732
733 }
734 return (PEBL_Keycode)code;
735}
736
737
738
739//This returns a text-valued description of the key pressed.
740std::string PEBLUtility::TranslateKeycode(const PEBL_Keycode code, int modkeys)
741{
742
743
744
745 switch(code)
746 {
747
748 case PEBL_KEYCODE_SPACE: return " ";
749 case PEBL_KEYCODE_UNKNOWN: return "<unknown>";
750 case PEBL_KEYCODE_ANYKEY: return "<anykey>";
751 case PEBL_KEYCODE_BACKSPACE: return "<backspace>";
752 case PEBL_KEYCODE_TAB: return "<tab>";
753 case PEBL_KEYCODE_CLEAR: return "<clear>";
754 case PEBL_KEYCODE_RETURN: return "<return>";
755 case PEBL_KEYCODE_RETURN2: return "<return>";
756 case PEBL_KEYCODE_KP_ENTER: return "<return>";
757
758 case PEBL_KEYCODE_PAUSE: return "<pause>";
759 case PEBL_KEYCODE_ESCAPE: return "<esc>";
760
761 /* Arrows + Home/End pad */
762 case PEBL_KEYCODE_UP: return "<up>";
763 case PEBL_KEYCODE_DOWN: return "<down>";
764 case PEBL_KEYCODE_RIGHT: return "<right>";
765 case PEBL_KEYCODE_LEFT: return "<left>";
766 case PEBL_KEYCODE_INSERT: return "<insert>";
767 case PEBL_KEYCODE_HOME: return "<home>";
768 case PEBL_KEYCODE_END: return "<end>";
769 case PEBL_KEYCODE_PAGEUP: return "<pageup>";
770 case PEBL_KEYCODE_PAGEDOWN: return "<pagedown>";
771
772 /* Function keys */
773 case PEBL_KEYCODE_F1: return "<f1>";
774 case PEBL_KEYCODE_F2: return "<f2>";
775 case PEBL_KEYCODE_F3: return "<f3>";
776 case PEBL_KEYCODE_F4: return "<f4>";
777 case PEBL_KEYCODE_F5: return "<f5>";
778 case PEBL_KEYCODE_F6: return "<f6>";
779 case PEBL_KEYCODE_F7: return "<f7>";
780 case PEBL_KEYCODE_F8: return "<f8>";
781 case PEBL_KEYCODE_F9: return "<f9>";
782 case PEBL_KEYCODE_F10: return "<f10>";
783 case PEBL_KEYCODE_F11: return "<f11>";
784 case PEBL_KEYCODE_F12: return "<f12>";
785
786
787 /* Key state modifier keys */
788 case PEBL_KEYCODE_NUMLOCK: return "<numlock>";
789 case PEBL_KEYCODE_CAPSLOCK: return "<capslock>";
790 case PEBL_KEYCODE_SCROLLLOCK: return "<scrolllock>";
791 case PEBL_KEYCODE_RSHIFT: return "<rshift>";
792 case PEBL_KEYCODE_LSHIFT: return "<lshift>";
793 case PEBL_KEYCODE_RCTRL: return "<rctrl>";
794 case PEBL_KEYCODE_LCTRL: return "<lctrl>";
795 case PEBL_KEYCODE_RALT: return "<ralt>";
796 case PEBL_KEYCODE_LALT: return "<lalt>";
797 case PEBL_KEYCODE_MODE: return "<mode>";
798
799
800 /* Miscellaneous function keys */
801 case PEBL_KEYCODE_HELP: return "<help>";
802 case PEBL_KEYCODE_SYSREQ: return "<sysreq>";
803 case PEBL_KEYCODE_MENU: return "<menu>";
804 case PEBL_KEYCODE_POWER: return "<power>";
805 case PEBL_KEYCODE_UNDO: return "<undo>";
806
807
808 /*Keypadcodes:*/
809
810 case PEBL_KEYCODE_KP_DIVIDE: return "/";
811 case PEBL_KEYCODE_KP_MULTIPLY: return "*";
812 case PEBL_KEYCODE_KP_MINUS: return "-";
813 case PEBL_KEYCODE_KP_PLUS: return "+";
814
815 case PEBL_KEYCODE_KP_1: return "1";
816 case PEBL_KEYCODE_KP_2: return "2";
817 case PEBL_KEYCODE_KP_3: return "3";
818 case PEBL_KEYCODE_KP_4: return "4";
819 case PEBL_KEYCODE_KP_5: return "5";
820 case PEBL_KEYCODE_KP_6: return "6";
821 case PEBL_KEYCODE_KP_7: return "7";
822 case PEBL_KEYCODE_KP_8: return "8";
823 case PEBL_KEYCODE_KP_9: return "9";
824 case PEBL_KEYCODE_KP_0: return "0";
825 case PEBL_KEYCODE_KP_PERIOD: return ".";
826
827 default:
828
829#ifndef PEBL_VALIDATOR
830 std::string ltrs = PEBL_GetKeyName(code);
831 return ShiftSwitch(modkeys, ToLower(ltrs),ToUpper(ltrs));
832#else
833 return "<unknown>"; // Validator mode: return unknown
834#endif
835 }
836
837}
838
839
840
841
843{
844
845 PEBLVideoMode mode;
846
847 if(modeline == "512x384") mode =PVM_512_384;
848 else if (modeline == "640x480") mode = PVM_640_480;
849 else if (modeline == "800x600") mode = PVM_800_600;
850 else if (modeline == "960x720") mode = PVM_960_720;
851 else if (modeline == "1024x768") mode = PVM_1024_768;
852 else if (modeline == "1152x864") mode = PVM_1152_864;
853 else if (modeline == "1280x1024") mode = PVM_1280_1024;
854 else mode = PVM_800_600;
855 return mode;
856}
857
858
860{
861 PEBLVideoDepth depth;
862
863 if(depthline == "2") depth =PVD_2;
864 else if (depthline =="15") depth =PVD_15;
865 else if (depthline =="16") depth =PVD_16;
866 else if (depthline =="24") depth =PVD_24;
867 else if (depthline =="32") depth =PVD_32;
868 else depth = PVD_16;
869
870 return depth;
871}
872
873
874
875//This returns upper if a shift key is pressed, otherwise it returns lower.
876std::string PEBLUtility::ShiftSwitch(int modkeys, std::string lower, std::string upper)
877{
878 if( modkeys & PEBLMOD_SHIFT)
879 return upper;
880 else
881 return lower;
882}
883
884
886{
887 DIR *dirp;
888 //struct dirent *entry;
889 dirp = opendir(path.c_str());
890
891
892 if(dirp)
893 {
894
895 closedir(dirp);
896 return Variant(1);
897 }
898 else
899 {
900 //closedir(dirp);
901 //std::cerr << "Error type: " <<errno << std::endl;
902 return Variant(0);
903 }
904 //entry->d_type;
905
906
907
908}
909
911{
912
913 struct stat stFileInfo;
914 //may need to use _stat on windows
915 int out = stat(path.c_str(),&stFileInfo);
916 //cout << path.c_str()<<"\n";
917 //cout << "File info:" << out << endl;
918 // We can get better info about the file
919 // if we look at out.
920 return Variant(out==0);
921}
922
923
924
925
926
928{
929
930 //cout << "Getting directory listing\n";
931 DIR *dirp;
932 struct dirent *entry;
933 PList * plist = new PList();
934 PComplexData*pcd=NULL;
935
936 dirp = opendir(path.c_str());
937
938 if(dirp)
939 {
940
941 //not this is an assignment, not an equality
942 while((entry = readdir(dirp)))
943 {
944 //cout << entry->d_name << endl;
945 plist->PushBack(Variant(entry->d_name));
946 }
947 } else {
948//ERRNO CODES:
949// EACCES
950
951// EMFILE
952//
953// ENFILE
954// The entire system, or perhaps the file system which contains the directory, cannot support any additional open files at the moment. (This problem cannot happen on the GNU system.)
955// ENOMEM
956// Not enough memory available.
957
958 Variant codes = "";
959 switch (errno) {
960 case EACCES:
961 codes = "Read permission is denied for the directory named by dirname.(EACCES)";
962 break;
963
964 case EMFILE:
965 codes = "The process has too many files open (EMFILE).";
966 break;
967 case ENFILE:
968 codes = "The entire system, or perhaps the file system which contains the directory, cannot support any additional open files at the moment. (ENFILE)";
969 break;
970 case ENOMEM:
971 codes = "Not enough memory available. (ENOMEM)";
972 break;
973 default:
974 codes =Variant("Unknown error") + Variant(errno);
975 break;
976 }
977
978 PError::SignalFatalError(Variant("Unable to get Directory listing at ") + Variant(path) + codes);
979
980 }
981
982
983 closedir(dirp);
984
986 pcd = new PComplexData(tmplist);
987 Variant tmp = Variant(pcd);
988 delete pcd;
989 return tmp;
990}
991
992
993
995
996{
997
998 if(FileExists(path) && IsDirectory(path))
999 {
1000 return Variant(1);
1001 }
1002
1003#if defined(PEBL_UNIX) || defined(PEBL_EMSCRIPTEN)
1004
1005 if (mkdir(path.c_str(), 0777) == -1)
1006 {
1007 PError::SignalFatalError("Unable to create directory: " );//+ Variant(strerror(errno)));
1008 }
1009
1010#elif defined(PEBL_WIN32)
1011 if (mkdir(path.c_str()) == -1) // Windows mkdir takes only path argument
1012 {
1013 //cerr << strerror(errno)<<endl;
1014 PError::SignalFatalError("Unable to create directory: " + std::string(strerror(errno)));
1015 }
1016
1017#endif
1018
1019 return Variant(1);
1020}
1021
1023{
1024 if(FileExists(path))
1025 {
1026 if( remove( path.c_str() ) != 0 )
1027 return Variant(0);
1028 else
1029 return Variant(1);
1030 }
1031 return Variant(0);
1032
1033}
1034
1036{
1037
1038#ifdef PEBL_WIN32
1039 char path[ MAX_PATH ];
1040 if (SHGetFolderPathA( NULL, CSIDL_PROFILE, NULL, 0, path ) != S_OK)
1041 {
1042 PError::SignalFatalError("Unable to find user's home directory!");
1043 }
1044#elif defined(PEBL_LINUX) or defined(PEBL_OSX)
1045
1046 struct passwd *p=getpwuid(getuid());
1047 std::string path = p->pw_dir;
1048
1049#elif defined( PEBL_EMSCRIPTEN)
1050
1051 //this may be wrong?
1052 std::string path ="~/";
1053
1054#endif
1055
1056 return Variant(path);
1057}
1058
1060{
1061#if defined(PEBL_WIN32) or defined(PEBL_OSX)
1062 //maybe this will work given we compile with g++
1063
1064 char *path=NULL;
1065 size_t size = 0;
1066 path=getcwd(path,size);
1067
1068
1069#elif defined(PEBL_UNIX) //linux/osx
1070
1071 char* path = get_current_dir_name();
1072
1073#elif defined (PEBL_EMSCRIPTEN)
1074 // Emscripten supports getcwd() with its virtual filesystem (MEMFS)
1075 char buffer[PATH_MAX];
1076 char* path = getcwd(buffer, sizeof(buffer));
1077 if (path == NULL) {
1078 // If getcwd fails, default to root of virtual filesystem
1079 return Variant("/");
1080 }
1081#endif
1082
1083 return Variant(path);
1084}
1085
1087{
1088#ifdef PEBL_WIN32
1089
1090 if(::SetCurrentDirectory(path.c_str()) == FALSE)
1091 PError::SignalFatalError("Unable to Set Working Directory: " + path);
1092 //GetLastError should help more here.
1093#else
1094 int result = chdir(path.c_str());
1095 if(result != 0)
1096 {
1097 PError::SignalFatalError("Unable to Set Working Directory: " + path);
1098 }
1099#endif
1100
1101 return Variant(true);
1102}
1103
1104
1105
1107{
1108
1109 int x;
1110 //cout << "Running launchfile\n";
1111#if defined(PEBL_WIN32)
1112 HINSTANCE hInst = ShellExecute(0,
1113 "open", // Operation to perform
1114 file.c_str(), // document name???Application name
1115 NULL, // Additional parameters
1116 0, // Default directory
1117 SW_SHOW);
1118 //cout<< "LaunchFile:{" << file <<"}{"<< hInst << endl;
1119
1120 if ((INT_PTR)hInst == SE_ERR_NOASSOC ||
1121 (INT_PTR)hInst == SE_ERR_ASSOCINCOMPLETE ||
1122 (INT_PTR)hInst == SE_ERR_ACCESSDENIED)
1123 {
1124 SHELLEXECUTEINFO exeInfo = {0};
1125 exeInfo.cbSize = sizeof(SHELLEXECUTEINFO);
1126 exeInfo.lpVerb = "openas";
1127 exeInfo.lpFile = file.c_str();
1128 exeInfo.fMask = SEE_MASK_INVOKEIDLIST;
1129 exeInfo.nShow = SW_SHOWDEFAULT;
1130
1131 // Open up the open as window
1132 if (ShellExecuteEx(&exeInfo) == FALSE);
1133 {
1134 x = false ;
1135 }
1136 } else {
1137
1138 x = ((INT_PTR)hInst > 32); //hInst returns an error code > 32 on success.
1139 }
1140#elif defined(PEBL_LINUX)
1141
1142
1143 std::string call2 = "xdg-open " + file;
1144 int ret = system(call2.c_str()); //do a system call with the argument string.
1145 x = !ret;
1146
1147
1148
1149#elif defined(PEBL_OSX)
1150 std::string call2 = "open " + file;
1151 int ret = system(call2.c_str()); //do a s string.
1152 x = !ret;
1153#endif
1154
1155 return Variant(x);
1156}
1157
1158
1159Variant PEBLUtility::SystemCall(std::string call, std::string args)
1160{
1161 // cout << "Systemcalling inner\n";
1162
1163
1164#if defined( PEBL_UNIX )
1165
1166 std::string tmp = call + " " + args;
1167
1168 const char* call2 = tmp.c_str();
1169 int x = system(call2); //do a system call with the argument string.
1170
1171#elif defined (PEBL_WIN32)
1172 std::string tmp = "cmd.exe /c " + call + " " + args;
1173
1174 // cout << "["<<tmp <<"]"<< std::endl;
1175 STARTUPINFO info={sizeof(info)};
1176 PROCESS_INFORMATION processInfo;
1177 char* callstring = const_cast<char *>(tmp.c_str());
1178
1179 if (CreateProcess(NULL,callstring, NULL, NULL, TRUE,
1180 ABOVE_NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW,
1181 NULL, NULL, &info, &processInfo))
1182// if (CreateProcess(NULL,callstring, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
1183 {
1184 ::WaitForSingleObject(processInfo.hProcess, INFINITE);
1185 CloseHandle(processInfo.hProcess);
1186 CloseHandle(processInfo.hThread);
1187 } else {
1188 // cout << "createprocess failed\n";
1189 std::cerr << GetLastError() << std::endl;
1190 }
1191 int x=0;
1192#elif defined (PEBL_EMSCRIPTEN)
1193 std::cerr << "Cannot perform system call in web mode\n";
1194 int x = 0;
1195#endif
1196
1197 return Variant(x);
1198
1199}
1200
1201
1202
1203#ifdef PEBL_WINDOWS
1204
1205
1206PROCESS_INFORMATION PEBLUtility::SystemCallAndReturn(std::string call, std::string args)
1207{
1208
1209 std::string tmp = "cmd.exe /c " + call + " " + args;
1210
1211 STARTUPINFO info={sizeof(info)};
1212 PROCESS_INFORMATION processInfo;
1213
1214
1215 ZeroMemory( &info, sizeof(info) );
1216 info.cb = sizeof(info);
1217 ZeroMemory( &processInfo,sizeof(processInfo) );
1218
1219 char* callstring = const_cast<char *>(tmp.c_str());
1220
1221 if (CreateProcess(NULL,callstring, NULL, NULL, TRUE,
1222 ABOVE_NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW,
1223 NULL, NULL, &info, &processInfo))
1224// if (CreateProcess(NULL,callstring, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
1225 {
1226 ::WaitForSingleObject(processInfo.hProcess, 10);
1227
1228 } else {
1229 // cout << "createprocess failed\n";
1230 std::cerr << GetLastError() << std::endl;
1231 }
1232 int x=0;
1233
1234 return processInfo;
1235
1236}
1237
1238#endif
1239// unicode reverse functions adapted from
1240// http://stackoverflow.com/questions/198199/how-do-you-reverse-a-string-in-place-in-c-or-c
1241//
1242
1243#define SWP(x,y) (x^=y, y^=x, x^=y)
1244
1246{
1247 char *q = p;
1248 while(q && *q) ++q; /* find eos */
1249 for(--q; p < q; ++p, --q) SWP(*p, *q);
1250}
1251
1252
1253// The following is adapted from code put on
1254// http://stackoverflow.com/questions/1031645/how-to-detect-utf-8-in-plain-c
1255// It has an implied public domain license
1256//It probably can be replaced by something from the utf8 library we now include.
1257
1258bool PEBLUtility::is_utf8(std::string str)
1259{
1260
1261
1262 if(str.length()==0)
1263 return false;
1264
1265 const unsigned char * bytes = (const unsigned char *)(str.c_str());
1266 while(*bytes)
1267 {
1268 if( (// ASCII
1269 bytes[0] == 0x09 ||
1270 bytes[0] == 0x0A ||
1271 bytes[0] == 0x0D ||
1272 (0x20 <= bytes[0] && bytes[0] <= 0x7E)
1273 )
1274 ) {
1275 bytes += 1;
1276 continue;
1277 }
1278
1279 if( (// non-overlong 2-byte
1280 (0xC2 <= bytes[0] && bytes[0] <= 0xDF) &&
1281 (0x80 <= bytes[1] && bytes[1] <= 0xBF)
1282 )
1283 ) {
1284 bytes += 2;
1285 continue;
1286 }
1287
1288 if( (// excluding overlongs
1289 bytes[0] == 0xE0 &&
1290 (0xA0 <= bytes[1] && bytes[1] <= 0xBF) &&
1291 (0x80 <= bytes[2] && bytes[2] <= 0xBF)
1292 ) ||
1293 (// straight 3-byte
1294 ((0xE1 <= bytes[0] && bytes[0] <= 0xEC) ||
1295 bytes[0] == 0xEE ||
1296 bytes[0] == 0xEF) &&
1297 (0x80 <= bytes[1] && bytes[1] <= 0xBF) &&
1298 (0x80 <= bytes[2] && bytes[2] <= 0xBF)
1299 ) ||
1300 (// excluding surrogates
1301 bytes[0] == 0xED &&
1302 (0x80 <= bytes[1] && bytes[1] <= 0x9F) &&
1303 (0x80 <= bytes[2] && bytes[2] <= 0xBF)
1304 )
1305 ) {
1306 bytes += 3;
1307 continue;
1308 }
1309
1310 if( (// planes 1-3
1311 bytes[0] == 0xF0 &&
1312 (0x90 <= bytes[1] && bytes[1] <= 0xBF) &&
1313 (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
1314 (0x80 <= bytes[3] && bytes[3] <= 0xBF)
1315 ) ||
1316 (// planes 4-15
1317 (0xF1 <= bytes[0] && bytes[0] <= 0xF3) &&
1318 (0x80 <= bytes[1] && bytes[1] <= 0xBF) &&
1319 (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
1320 (0x80 <= bytes[3] && bytes[3] <= 0xBF)
1321 ) ||
1322 (// plane 16
1323 bytes[0] == 0xF4 &&
1324 (0x80 <= bytes[1] && bytes[1] <= 0x8F) &&
1325 (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
1326 (0x80 <= bytes[3] && bytes[3] <= 0xBF)
1327 )
1328 ) {
1329 bytes += 4;
1330 continue;
1331 }
1332
1333 return false;
1334 }
1335
1336 return true;
1337}
1338
1339
1340
1342{
1343 char *q = p;
1344 strrev(p); /* call base case */
1345
1346 /* Ok, now fix bass-ackwards UTF chars. */
1347 while(q && *q) ++q; /* find eos */
1348 while(p < --q)
1349 switch( (*q & 0xF0) >> 4 ) {
1350 case 0xF: /* U+010000-U+10FFFF: four bytes. */
1351 SWP(*(q-0), *(q-3));
1352 SWP(*(q-1), *(q-2));
1353 q -= 3;
1354 break;
1355 case 0xE: /* U+000800-U+00FFFF: three bytes. */
1356 SWP(*(q-0), *(q-2));
1357 q -= 2;
1358 break;
1359 case 0xC: /* fall-through */
1360 case 0xD: /* U+000080-U+0007FF: two bytes. */
1361 SWP(*(q-0), *(q-1));
1362 q--;
1363 break;
1364 }
1365}
1366std::string PEBLUtility::strrev(std::string p)
1367{
1368
1369 std::string q = std::string(p);
1370 std::reverse(q.begin(),q.end());
1371 return q;
1372}
1373
1374std::string PEBLUtility::strrev_utf8(std::string p)
1375{
1376
1377
1378 std::wstring q(p.length(), L' '); // Make room for characters
1379 // Copy string to wstring.
1380 std::copy(p.begin(), p.end(), q.begin());
1381
1382 // reverse:
1383 std::reverse(q.begin(),q.end());
1384
1385 cout << "[";
1386 std::wstring::iterator i;
1387
1388 for(i = q.begin();i<=q.end();i++)
1389 {
1390 cout << *i << "|";
1391 }
1392 cout << "]\n";
1393
1394 std::string ns(q.begin(), q.end());
1395 cout << ns << std::endl;
1396 return ns;
1397
1398
1399// std::string::iterator qq = q.end();
1400
1401// /* Ok, now fix backwards UTF chars. */
1402
1403// while(qq >= q.begin())
1404// {
1405
1406// switch( (*qq & 0xF0) >> 4 )
1407// {
1408
1409// case 0xF: /* U+010000-U+10FFFF: four bytes. */
1410// std::swap(*qq,*(qq-3));
1411// std::swap(*(qq-1),*(qq-2));
1412// //q.replace(qq,qq-3,q,1);
1413// //q.replace(qq-1,qq-2,q,1);
1414// qq -= 3;
1415// break;
1416
1417// case 0xE: /* U+000800-U+00FFFF: three bytes. */
1418// std::swap(*qq,*(qq-2));
1419// //q.replace(qq,qq-2,q,1);
1420// qq -= 2;
1421// break;
1422
1423// case 0xC: /* fall-through */
1424// case 0xD: /* U+000080-U+0007FF: two bytes. */
1425// std::swap(*qq,*(qq-1));
1426// //q.replace(qq,qq-1,q,1);
1427// qq--;
1428// break;
1429// default:
1430// qq--;
1431// }
1432// }
1433// return q;
1434}
1435
1436// Get the size of the file by its file descriptor
1437unsigned long get_size_by_fd(int fd) {
1438 struct stat statbuf;
1439 if(fstat(fd, &statbuf) < 0) exit(-1);
1440 return statbuf.st_size;
1441}
1442
1443std::string PEBLUtility::MD5File(const std::string & filename)
1444{
1445
1446 if(FileExists(filename))
1447 {
1448
1449#ifdef PEBL_WIN32
1450 // Windows: use standard file I/O instead of mmap
1451 std::ifstream file(filename.c_str(), std::ios::binary | std::ios::ate);
1452 if (!file.is_open())
1453 {
1454 PError::SignalFatalError("File does not exist in MD5file\n");
1455 return "";
1456 }
1457
1458 std::streamsize file_size = file.tellg();
1459 file.seekg(0, std::ios::beg);
1460
1461 char* file_buffer = new char[file_size];
1462 if (!file.read(file_buffer, file_size))
1463 {
1464 delete[] file_buffer;
1465 PError::SignalFatalError("Failed to read file in MD5file\n");
1466 return "";
1467 }
1468 file.close();
1469
1470 MD5 *md5 = new MD5();
1471 md5->update((unsigned char*)file_buffer,(unsigned int)file_size);
1472 md5->finalize();
1473 std::string hex = md5->hexdigest();
1474 delete md5;
1475 delete[] file_buffer;
1476 md5=NULL;
1477 return hex;
1478#else
1479 // Unix/Linux: use mmap
1480 int file_descript;
1481 unsigned long int file_size;
1482 char* file_buffer;
1483
1484 //printf("using file:\t%s\n", filename);
1485
1486 file_descript = open(filename.c_str(), O_RDONLY);
1487 if(file_descript < 0)
1488 {
1489 PError::SignalFatalError("File does not exist in MD5file\n");
1490 return "";
1491 }
1492
1493 file_size = get_size_by_fd(file_descript);
1494 //printf("file size:\t%lu\n", file_size);
1495
1496 file_buffer = (char*)mmap(0, file_size, PROT_READ, MAP_SHARED,
1497 file_descript, 0);
1498
1499
1500 MD5 *md5 = new MD5();
1501 md5->update((unsigned char*)file_buffer,(unsigned int)file_size);
1502 //std::string result = md5((unsigned char*) file_buffer);
1503 md5->finalize();
1504 std::string hex = md5->hexdigest();
1505 delete md5;
1506 md5=NULL;
1507 return hex;
1508#endif
1509 }else{
1510
1511 return "0";
1512 }
1513
1514}
1515
1516
1517std::string PEBLUtility::MD5String(const std::string & text)
1518{
1519 return md5(text);
1520}
1521
1522
1523void PEBLUtility::CopyToClipboard(const std::string & text)
1524{
1525
1526}
1527
1528
1529
1530//This handles the current token/tokens. That is, if the token is a list or
1531//an object, it handles the entire subsequent set, recursively.
1532
1533Variant PEBLUtility::ExtractJSONObject(const std::string & text,int remaining,
1534 jsmntok_t **t, int start, int end)
1535{
1536
1537 //A primitive is number, a boolean, or NULL.
1538 if ((*t)->type == JSMN_PRIMITIVE) {
1539 //cout << "->->->->->->->->->->->->->->->->->-> Parsing primitive\n";
1540 //cout << "t1: " << (*t)->start << " to " << (*t)->end << " size: "<< (*t)->size << endl;
1541 //cout << "Primitive: " << (*t)->start << "|" << (*t)->end << "---["
1542 //<< text.substr((*t)->start,(*t)->end-(*t)->start) <<"]"<< endl;
1543
1544
1545
1546 std::string label = text.substr((*t)->start,(*t)->end - (*t)->start);
1547 Variant out = 0;
1548
1549 if(label[0]=='t') //true; this sholudn't be capitalized.
1550 {
1551 out = 1;
1552 }else if(label[0]=='f' || label[0] == 'N')
1553 {
1554 //PEBL has no NULL (except empty list), so
1555 //treat these as 0. We may need to handl null in an other way.
1556 out= 0;
1557 }else{
1558 // Parse as double first
1559 pDouble numVal = PEBLUtility::StringToPDouble(label.c_str());
1560
1561 // Check if it's actually an integer (no decimal point in string and value equals its floor)
1562 if(label.find('.') == std::string::npos &&
1563 label.find('e') == std::string::npos &&
1564 label.find('E') == std::string::npos &&
1565 numVal == floor(numVal))
1566 {
1567 // Store as integer
1568 out = Variant((pInt)numVal);
1569 } else {
1570 // Store as double
1571 out = Variant(numVal);
1572 }
1573 }
1574
1575 (*t)++;
1576
1577 //We may need to convert to a number here too.
1578 return out;
1579
1580
1581 } else if ((*t)->type == JSMN_STRING) {
1582 //cout << "->>->->->->->->->-> Parsing string\n";
1583 //cout << "t2: " << (*t)->start << " to " << (*t)->end << " size: "<< (*t)->size << endl;
1584 //cout << "String: " << (*t)->start << "|" << ((*t)->end-(*t)->start) << "---[" << text.substr((*t)->start,(*t)->end - (*t)->start) <<"]"<< endl;
1585
1586 Variant out = Variant(text.substr((*t)->start,(*t)->end-(*t)->start));
1587 (*t)++; //Increment to next token so all paths do this the same.
1588 return out;
1589
1590
1591 } else if ((*t)->type == JSMN_OBJECT) {
1592 // cout << "------------------->>>_>_>_>_>_>_>_>_Parsing object\n";
1593 // cout << "<<<" << text.substr((*t)->start,(*t)->end-(*t)->start) <<">>>"<< endl;
1594
1595 //Get the top-level object:
1596 std::string name = "JSON Object";
1597 PCustomObject * pobj = new PCustomObject(name);
1598 //We need an (inconspicuous) element added to any JSON object called ELEMENTORDER,
1599 //that will keep track of the order of the element names. JSON technically has
1600 //no restriction on the input order, but this will make editing the files more convenient.
1601 //as a round trip read-write should maintain order.
1602 //This needs to be a plist of variants.
1603 PList * elementOrder = new PList();
1604
1605 remaining = (*t)->size * 2;//this is how many sub-objects the current object has.
1606 //per high-level entry.
1607 //cout << "Remaining: " << remaining << endl;
1608 //Advance to the first subtoken:
1609 (*t)++;
1610 //We need to iterate through all sub-elements of the object
1611 while(remaining > 0)
1612 {
1613 //cout << ">>>>>>>>>>>>>>>>>.Remaining1:" << remaining << endl;
1614 //cout << "t3: " << (*t)->start << " to " << (*t)->end << " size: " << (*t)->size << endl;
1615
1616 std::string objname = text.substr((*t)->start,(*t)->end-(*t)->start);
1617 //cout << "Naame:" << objname << endl;
1618 elementOrder->PushBack(objname);//add name to end of elementorder object.
1619
1620
1621 (*t)++;
1622 remaining-=1;
1623
1624 //cout << ">>>>>>>>>>>>>>>>>.Remaining2 :" << remaining << endl;
1625 //cout << "t5: " << (*t)->start << " to " << (*t)->end << " size: " << (*t)->size << endl;
1626
1627
1628
1629 //Call recursively. This should increment t to the next token:
1631 (*t)->size-1,
1632 t,(*t)->start,(*t)->end);
1633
1634 //cout << "New vaule of t: " << (*t)->start << " to " << (*t)->end << "\n";
1635 //std::cout << "Setting[" << objname << "-->" << objValue << std::endl;
1636 pobj->SetProperty((objname),objValue);
1637 remaining--;
1638 //cout << "t6: " << (*t)->start << " to " << (*t)->end << " size: " <<(*t)->size << endl;
1639 }
1640
1641
1643 PComplexData * pcd = new PComplexData(tmpObject);
1644 Variant tmp = Variant(pcd);
1645 delete pcd;
1646 pcd=NULL;
1647 //cout << "<_<_<_<_<_<_<_<_<_<_<_<_<_<_<_<_<DONE PARSING OBJECT\n";
1648
1649
1650 return tmp;
1651
1652
1653 } else if ((*t)->type == JSMN_ARRAY) {
1654 // cout << "-------------->->->->->->_>->->-Parsing ARRAY\n";
1655 remaining = (*t)->size ;
1656 //cout << "Remaining: " << remaining << endl;
1657
1658
1659 //cout << "t7: " << (*t)->start << " to " << (*t)->end << " size: "<< (*t)->size ;
1660 //cout << "---> <<<"<< Variant(text.substr((*t)->start,(*t)->end-(*t)->start))<<">>>\n";
1661
1662
1663 PList * plist = new PList();
1664 //We need to iterate through all sub-elements of the array.
1665 (*t)++;
1666 while(remaining > 0)
1667 {
1668 //cout << " Array loop: remaining: " << remaining << endl;
1669 //cout << "t8: " << (*t)->start << " to " << (*t)->end << " size: "<< (*t)->size << endl;
1670
1671 //This increments (*t) automatically:
1673 remaining,
1674 t, (*t)->start,(*t)->end);
1675 //cout << "t8AFTER: " << (*t)->start << " to " << (*t)->end << " size: "<< (*t)->size << endl;
1676 //cout << "Adding: " << objValue << endl;
1677 plist->PushBack(objValue);
1678 //cout << "not incrementing t: \n" ;
1679
1680 remaining -= 1; //array size is in objects, not flattened tokens.
1681 }
1682
1683
1685 PComplexData * pcd = new PComplexData(tmpObject);
1686 Variant tmp = Variant(pcd);
1687 delete pcd;
1688 pcd=NULL;
1689 //cout << "<<<<-----------------------DONE Parsing ARRAY\n";
1690 return tmp;
1691
1692 }
1693 return Variant(int(0));
1694}
1695
1696
1697
1698Variant PEBLUtility::ParseJSON(const std::string &text)
1699{
1700 jsmn_parser p;
1701
1702 jsmntok_t * t;
1703 t= (jsmntok_t*) malloc(sizeof(*t)*(size_t)10000); /* We expect no more than 10000 tokens */
1704 /*Increased from 1000 to handle large scale JSON files*/
1705 jsmntok_t ** tt = &t;
1706 int r;
1707 //std::cout <<"Parsing:" << text << endl;
1708
1709 jsmn_init(&p);
1710 r = jsmn_parse(&p, text.c_str(), text.length(),*tt,10000);
1711 //cout << "number of tokens:" << r << endl;
1712 if (r < 0) {
1713 printf("Failed to parse JSON: %d\n", r);
1714 return 1;
1715 }
1716 //Now, t contains a bunch of parsed tokens.
1717
1718 /* Assume the top-level element is an object */
1719 if (r < 1 || t[0].type != JSMN_OBJECT) {
1720 printf("Object expected\n");
1721 return 1;
1722 }
1723
1724 //skip past the first token, and extract the rest (r-1 remaining; token 1)
1725 Variant out = ExtractJSONObject(text, r-1,tt,0,text.length());
1726 return out;
1727}
1728
1729// Detect script from UTF-8 text content
1730// Returns ISO 15924 4-letter script code, or empty string for Latin/unknown
1731// Used to enable proper text rendering for complex scripts
1732std::string PEBLUtility::DetectScript(const std::string & text) {
1733 if (!is_utf8(text)) {
1734 return ""; // Can't reliably detect in non-UTF8
1735 }
1736
1737 // Walk through UTF-8 string looking for script-specific codepoints
1738 const unsigned char *bytes = (const unsigned char *)text.c_str();
1739 while (*bytes) {
1740 // Hebrew: U+0590 to U+05FF (0xD6 0x90 to 0xD7 0xBF in UTF-8)
1741 if ((bytes[0] == 0xD6 && bytes[1] >= 0x90) ||
1742 (bytes[0] == 0xD7 && bytes[1] <= 0xBF)) {
1743 return "Hebr";
1744 }
1745
1746 // Arabic: U+0600 to U+06FF (0xD8 0x80 to 0xDB 0xBF in UTF-8)
1747 if (bytes[0] >= 0xD8 && bytes[0] <= 0xDB) {
1748 return "Arab";
1749 }
1750
1751 // Devanagari: U+0900 to U+097F (0xE0 0xA4 0x80 to 0xE0 0xA5 0xBF)
1752 if (bytes[0] == 0xE0 && bytes[1] == 0xA4) {
1753 return "Deva";
1754 }
1755
1756 // Thai: U+0E00 to U+0E7F (0xE0 0xB8 0x80 to 0xE0 0xB9 0xBF)
1757 if (bytes[0] == 0xE0 && bytes[1] == 0xB8) {
1758 return "Thai";
1759 }
1760
1761 // Bengali: U+0980 to U+09FF (0xE0 0xA6 0x80 to 0xE0 0xA7 0xBF)
1762 if (bytes[0] == 0xE0 && bytes[1] == 0xA6) {
1763 return "Beng";
1764 }
1765
1766 // Georgian: U+10A0 to U+10FF (0xE1 0x82 0xA0 to 0xE1 0x83 0xBF)
1767 if (bytes[0] == 0xE1 && (bytes[1] == 0x82 || bytes[1] == 0x83)) {
1768 return "Geor";
1769 }
1770
1771 // Hiragana: U+3040 to U+309F (0xE3 0x81 0x80 to 0xE3 0x82 0x9F)
1772 if (bytes[0] == 0xE3 && (bytes[1] == 0x81 || bytes[1] == 0x82)) {
1773 return "Hira"; // Japanese Hiragana
1774 }
1775
1776 // Katakana: U+30A0 to U+30FF (0xE3 0x82 0xA0 to 0xE3 0x83 0xBF)
1777 if (bytes[0] == 0xE3 && bytes[1] == 0x83) {
1778 return "Kana"; // Japanese Katakana
1779 }
1780
1781 // Hangul Syllables: U+AC00 to U+D7AF (0xEA 0xB0 0x80 to 0xED 0x9E 0xAF)
1782 if (bytes[0] >= 0xEA && bytes[0] <= 0xED) {
1783 return "Hang"; // Korean Hangul
1784 }
1785
1786 // CJK Unified Ideographs: U+4E00 to U+9FFF
1787 // (0xE4 0xB8 0x80 to 0xE9 0xBF 0xBF)
1788 if (bytes[0] >= 0xE4 && bytes[0] <= 0xE9) {
1789 return "Hani"; // Han (Chinese/Japanese/Korean)
1790 }
1791
1792 // Skip to next codepoint
1793 if (bytes[0] < 0x80) bytes += 1;
1794 else if ((bytes[0] & 0xE0) == 0xC0) bytes += 2;
1795 else if ((bytes[0] & 0xF0) == 0xE0) bytes += 3;
1796 else if ((bytes[0] & 0xF8) == 0xF0) bytes += 4;
1797 else bytes += 1; // Invalid UTF-8, skip
1798 }
1799
1800 return ""; // Default: Latin/unknown, no special script needed
1801}
1802
1803// Determine if script is right-to-left
1804bool PEBLUtility::IsRTLScript(const std::string & script) {
1805 return (script == "Hebr" || script == "Arab");
1806}
1807
1808// Get appropriate font for a language code (2-letter ISO 639-1) or script code (4-letter ISO 15924)
1809// fontType: 0=sans-serif, 1=monospace, 2=serif
1810// Returns font filename appropriate for the language/script
1811std::string PEBLUtility::GetFontForLanguageOrScript(const std::string & code, int fontType) {
1812 std::string upperCode = code;
1813 std::transform(upperCode.begin(), upperCode.end(), upperCode.begin(), ::toupper);
1814
1815 // Default fonts (Western scripts - Latin, Cyrillic, Greek)
1816 std::string defaultSans = "DejaVuSans.ttf";
1817 std::string defaultMono = "DejaVuSansMono.ttf";
1818 std::string defaultSerif = "DejaVuSerif.ttf";
1819
1820 // CJK fonts
1821 std::string cjkSans = "NotoSansCJK-Regular.ttc";
1822 std::string cjkMono = "NotoSansMono-Regular.ttf";
1823 std::string cjkSerif = "NotoSerif-Regular.ttf";
1824
1825 // Check if it's a 2-letter language code or 4-letter script code
1826 if (upperCode.length() == 2) {
1827 // Language code - map to appropriate font
1828 if (upperCode == "AR") {
1829 // Arabic - DejaVu has excellent Arabic + Latin support
1830 return (fontType == 0) ? defaultSans : (fontType == 1) ? defaultMono : defaultSerif;
1831 }
1832 else if (upperCode == "HE" || upperCode == "IW") {
1833 // Hebrew - DejaVu has excellent Hebrew + Latin support
1834 return (fontType == 0) ? defaultSans : (fontType == 1) ? defaultMono : defaultSerif;
1835 }
1836 else if (upperCode == "TH") {
1837 // Thai
1838 return (fontType == 0) ? "NotoSansThai-Regular.ttf" :
1839 (fontType == 1) ? cjkMono : cjkSerif;
1840 }
1841 else if (upperCode == "HI" || upperCode == "MR" || upperCode == "NE") {
1842 // Devanagari (Hindi, Marathi, Nepali)
1843 return (fontType == 0) ? "NotoSansDevanagari-Regular.ttf" :
1844 (fontType == 1) ? cjkMono : cjkSerif;
1845 }
1846 else if (upperCode == "BN") {
1847 // Bengali
1848 return (fontType == 0) ? "NotoSansBengali-Regular.ttf" :
1849 (fontType == 1) ? cjkMono : cjkSerif;
1850 }
1851 else if (upperCode == "KA") {
1852 // Georgian - DejaVu has excellent Georgian + Latin support
1853 return (fontType == 0) ? defaultSans : (fontType == 1) ? defaultMono : defaultSerif;
1854 }
1855 else if (upperCode == "ZH" || upperCode == "CN" || upperCode == "TW") {
1856 // Chinese
1857 return (fontType == 0) ? cjkSans : (fontType == 1) ? cjkMono : cjkSerif;
1858 }
1859 else if (upperCode == "JA" || upperCode == "JP") {
1860 // Japanese
1861 return (fontType == 0) ? cjkSans : (fontType == 1) ? cjkMono : cjkSerif;
1862 }
1863 else if (upperCode == "KO" || upperCode == "KR" || upperCode == "KP") {
1864 // Korean
1865 return (fontType == 0) ? cjkSans : (fontType == 1) ? cjkMono : cjkSerif;
1866 }
1867 else {
1868 // Default to Western fonts for unrecognized language codes
1869 return (fontType == 0) ? defaultSans : (fontType == 1) ? defaultMono : defaultSerif;
1870 }
1871 }
1872 else if (upperCode.length() == 4) {
1873 // Script code (ISO 15924) - map to appropriate font
1874 if (upperCode == "ARAB") {
1875 // Arabic script - DejaVu supports Arabic
1876 return (fontType == 0) ? defaultSans : (fontType == 1) ? defaultMono : defaultSerif;
1877 }
1878 else if (upperCode == "HEBR") {
1879 // Hebrew script - DejaVu supports Hebrew
1880 return (fontType == 0) ? defaultSans : (fontType == 1) ? defaultMono : defaultSerif;
1881 }
1882 else if (upperCode == "THAI") {
1883 // Thai script
1884 return (fontType == 0) ? "NotoSansThai-Regular.ttf" :
1885 (fontType == 1) ? cjkMono : cjkSerif;
1886 }
1887 else if (upperCode == "DEVA") {
1888 // Devanagari script
1889 return (fontType == 0) ? "NotoSansDevanagari-Regular.ttf" :
1890 (fontType == 1) ? cjkMono : cjkSerif;
1891 }
1892 else if (upperCode == "BENG") {
1893 // Bengali script
1894 return (fontType == 0) ? "NotoSansBengali-Regular.ttf" :
1895 (fontType == 1) ? cjkMono : cjkSerif;
1896 }
1897 else if (upperCode == "GEOR") {
1898 // Georgian script - DejaVu supports Georgian
1899 return (fontType == 0) ? defaultSans : (fontType == 1) ? defaultMono : defaultSerif;
1900 }
1901 else if (upperCode == "HIRA" || upperCode == "KANA" || upperCode == "HANI") {
1902 // Japanese scripts (Hiragana, Katakana, Han/Kanji)
1903 return (fontType == 0) ? cjkSans : (fontType == 1) ? cjkMono : cjkSerif;
1904 }
1905 else if (upperCode == "HANG") {
1906 // Korean Hangul script
1907 return (fontType == 0) ? cjkSans : (fontType == 1) ? cjkMono : cjkSerif;
1908 }
1909 else {
1910 // Default to Western fonts (Latin and unknown scripts)
1911 return (fontType == 0) ? defaultSans : (fontType == 1) ? defaultMono : defaultSerif;
1912 }
1913 }
1914 else {
1915 // Invalid code length - return default
1916 return (fontType == 0) ? defaultSans : (fontType == 1) ? defaultMono : defaultSerif;
1917 }
1918}
1919
1920// Resolve a property chain like "HEADER.TEXT" by recursively traversing objects
1921// Returns the final property value
1922Variant PEBLUtility::ResolvePropertyChain(Variant obj, const std::string& propertyChain)
1923{
1924 // Handle empty chain (shouldn't happen, but be defensive)
1925 if(propertyChain.empty())
1926 {
1927 PError::SignalFatalError("Internal error: empty property chain in ResolvePropertyChain");
1928 return Variant(0);
1929 }
1930
1931 // Find first dot to split chain
1932 std::string::size_type dotPos = propertyChain.find(".");
1933
1934 if(dotPos == std::string::npos)
1935 {
1936 // Base case: single property, no more dots
1937 PComplexData * pcd = obj.GetComplexData();
1938 if(pcd == NULL)
1939 {
1940 PError::SignalFatalError("Attempted to access property [" +
1941 propertyChain + "] of non-object");
1942 return Variant(0);
1943 }
1944 return pcd->GetProperty(propertyChain);
1945 }
1946 else
1947 {
1948 // Recursive case: get first property, then recurse on remainder
1949 std::string firstProp = propertyChain.substr(0, dotPos);
1950 std::string remainingChain = propertyChain.substr(dotPos + 1);
1951
1952 PComplexData * pcd = obj.GetComplexData();
1953 if(pcd == NULL)
1954 {
1955 PError::SignalFatalError("Attempted to access property [" +
1956 firstProp + "] of non-object in chain [" + propertyChain + "]");
1957 return Variant(0);
1958 }
1959
1960 Variant intermediateObj = pcd->GetProperty(firstProp);
1961
1962 // Recursively resolve the rest of the chain
1963 return ResolvePropertyChain(intermediateObj, remainingChain);
1964 }
1965}
1966
1967// Set a property chain like "HEADER.TEXT" by recursively traversing to parent and setting final property
1968void PEBLUtility::SetPropertyChain(Variant obj, const std::string& propertyChain, Variant value)
1969{
1970 // Handle empty chain (shouldn't happen, but be defensive)
1971 if(propertyChain.empty())
1972 {
1973 PError::SignalFatalError("Internal error: empty property chain in SetPropertyChain");
1974 return;
1975 }
1976
1977 // Find first dot to split chain
1978 std::string::size_type dotPos = propertyChain.find(".");
1979
1980 if(dotPos == std::string::npos)
1981 {
1982 // Base case: single property, set it directly
1983 PComplexData * pcd = obj.GetComplexData();
1984 if(pcd == NULL)
1985 {
1986 PError::SignalFatalError("Attempted to set property [" +
1987 propertyChain + "] on non-object");
1988 return;
1989 }
1990 pcd->SetProperty(propertyChain, value);
1991 }
1992 else
1993 {
1994 // Recursive case: get intermediate object, then recurse on remainder
1995 std::string firstProp = propertyChain.substr(0, dotPos);
1996 std::string remainingChain = propertyChain.substr(dotPos + 1);
1997
1998 PComplexData * pcd = obj.GetComplexData();
1999 if(pcd == NULL)
2000 {
2001 PError::SignalFatalError("Attempted to access property [" +
2002 firstProp + "] of non-object in chain [" + propertyChain + "]");
2003 return;
2004 }
2005
2006 Variant intermediateObj = pcd->GetProperty(firstProp);
2007
2008 // Recursively set on the rest of the chain
2009 SetPropertyChain(intermediateObj, remainingChain, value);
2010 }
2011}
#define NULL
Definition BinReloc.cpp:317
#define pInt
Definition Defs.h:8
#define pDouble
Definition Defs.h:7
PEBLVideoDepth
Definition Globals.h:69
@ PVD_15
Definition Globals.h:71
@ PVD_32
Definition Globals.h:74
@ PVD_2
Definition Globals.h:70
@ PVD_24
Definition Globals.h:73
@ PVD_16
Definition Globals.h:72
PEBLVideoMode
Definition Globals.h:58
@ PVM_640_480
Definition Globals.h:60
@ PVM_960_720
Definition Globals.h:62
@ PVM_800_600
Definition Globals.h:61
@ PVM_1152_864
Definition Globals.h:64
@ PVM_512_384
Definition Globals.h:59
@ PVM_1024_768
Definition Globals.h:63
@ PVM_1280_1024
Definition Globals.h:65
#define SWP(x, y)
unsigned long get_size_by_fd(int fd)
#define PI
PEBL_Keycode
Definition PKeyboard.h:78
@ PEBL_KEYCODE_LALT
Definition PKeyboard.h:286
@ PEBL_KEYCODE_BACKSLASH
Definition PKeyboard.h:121
@ PEBL_KEYCODE_EQUALS
Definition PKeyboard.h:113
@ PEBL_KEYCODE_j
Definition PKeyboard.h:135
@ PEBL_KEYCODE_HOME
Definition PKeyboard.h:169
@ PEBL_KEYCODE_KP_3
Definition PKeyboard.h:186
@ PEBL_KEYCODE_PAGEUP
Definition PKeyboard.h:170
@ PEBL_KEYCODE_RETURN2
Definition PKeyboard.h:231
@ PEBL_KEYCODE_p
Definition PKeyboard.h:141
@ PEBL_KEYCODE_m
Definition PKeyboard.h:138
@ PEBL_KEYCODE_KP_MINUS
Definition PKeyboard.h:181
@ PEBL_KEYCODE_HASH
Definition PKeyboard.h:87
@ PEBL_KEYCODE_AT
Definition PKeyboard.h:116
@ PEBL_KEYCODE_COLON
Definition PKeyboard.h:110
@ PEBL_KEYCODE_UNDERSCORE
Definition PKeyboard.h:124
@ PEBL_KEYCODE_KP_PERIOD
Definition PKeyboard.h:194
@ PEBL_KEYCODE_F6
Definition PKeyboard.h:158
@ PEBL_KEYCODE_KP_MULTIPLY
Definition PKeyboard.h:180
@ PEBL_KEYCODE_KP_7
Definition PKeyboard.h:190
@ PEBL_KEYCODE_PERCENT
Definition PKeyboard.h:88
@ PEBL_KEYCODE_BACKQUOTE
Definition PKeyboard.h:125
@ PEBL_KEYCODE_a
Definition PKeyboard.h:126
@ PEBL_KEYCODE_QUOTEDBL
Definition PKeyboard.h:86
@ PEBL_KEYCODE_RIGHTBRACKET
Definition PKeyboard.h:122
@ PEBL_KEYCODE_f
Definition PKeyboard.h:131
@ PEBL_KEYCODE_UNDO
Definition PKeyboard.h:216
@ PEBL_KEYCODE_LESS
Definition PKeyboard.h:112
@ PEBL_KEYCODE_KP_PLUS
Definition PKeyboard.h:182
@ PEBL_KEYCODE_KP_9
Definition PKeyboard.h:192
@ PEBL_KEYCODE_DELETE
Definition PKeyboard.h:171
@ PEBL_KEYCODE_KP_0
Definition PKeyboard.h:193
@ PEBL_KEYCODE_0
Definition PKeyboard.h:100
@ PEBL_KEYCODE_DOWN
Definition PKeyboard.h:176
@ PEBL_KEYCODE_i
Definition PKeyboard.h:134
@ PEBL_KEYCODE_F9
Definition PKeyboard.h:161
@ PEBL_KEYCODE_F7
Definition PKeyboard.h:159
@ PEBL_KEYCODE_n
Definition PKeyboard.h:139
@ PEBL_KEYCODE_ASTERISK
Definition PKeyboard.h:94
@ PEBL_KEYCODE_RALT
Definition PKeyboard.h:290
@ PEBL_KEYCODE_r
Definition PKeyboard.h:143
@ PEBL_KEYCODE_KP_4
Definition PKeyboard.h:187
@ PEBL_KEYCODE_RIGHTPAREN
Definition PKeyboard.h:93
@ PEBL_KEYCODE_SCROLLLOCK
Definition PKeyboard.h:166
@ PEBL_KEYCODE_MENU
Definition PKeyboard.h:212
@ PEBL_KEYCODE_LGUI
Definition PKeyboard.h:287
@ PEBL_KEYCODE_F3
Definition PKeyboard.h:155
@ PEBL_KEYCODE_LEFTBRACKET
Definition PKeyboard.h:120
@ PEBL_KEYCODE_PLUS
Definition PKeyboard.h:95
@ PEBL_KEYCODE_x
Definition PKeyboard.h:149
@ PEBL_KEYCODE_F11
Definition PKeyboard.h:163
@ PEBL_KEYCODE_RGUI
Definition PKeyboard.h:291
@ PEBL_KEYCODE_g
Definition PKeyboard.h:132
@ PEBL_KEYCODE_5
Definition PKeyboard.h:105
@ PEBL_KEYCODE_EXCLAIM
Definition PKeyboard.h:85
@ PEBL_KEYCODE_F4
Definition PKeyboard.h:156
@ PEBL_KEYCODE_d
Definition PKeyboard.h:129
@ PEBL_KEYCODE_RCTRL
Definition PKeyboard.h:288
@ PEBL_KEYCODE_k
Definition PKeyboard.h:136
@ PEBL_KEYCODE_o
Definition PKeyboard.h:140
@ PEBL_KEYCODE_KP_5
Definition PKeyboard.h:188
@ PEBL_KEYCODE_UNKNOWN
Definition PKeyboard.h:79
@ PEBL_KEYCODE_POWER
Definition PKeyboard.h:196
@ PEBL_KEYCODE_SYSREQ
Definition PKeyboard.h:227
@ PEBL_KEYCODE_ANYKEY
Definition PKeyboard.h:329
@ PEBL_KEYCODE_6
Definition PKeyboard.h:106
@ PEBL_KEYCODE_PRINTSCREEN
Definition PKeyboard.h:165
@ PEBL_KEYCODE_SPACE
Definition PKeyboard.h:84
@ PEBL_KEYCODE_CARET
Definition PKeyboard.h:123
@ PEBL_KEYCODE_QUOTE
Definition PKeyboard.h:91
@ PEBL_KEYCODE_RSHIFT
Definition PKeyboard.h:289
@ PEBL_KEYCODE_F8
Definition PKeyboard.h:160
@ PEBL_KEYCODE_SLASH
Definition PKeyboard.h:99
@ PEBL_KEYCODE_F5
Definition PKeyboard.h:157
@ PEBL_KEYCODE_e
Definition PKeyboard.h:130
@ PEBL_KEYCODE_ESCAPE
Definition PKeyboard.h:81
@ PEBL_KEYCODE_KP_ENTER
Definition PKeyboard.h:183
@ PEBL_KEYCODE_HELP
Definition PKeyboard.h:211
@ PEBL_KEYCODE_LEFTPAREN
Definition PKeyboard.h:92
@ PEBL_KEYCODE_MODE
Definition PKeyboard.h:292
@ PEBL_KEYCODE_KP_EQUALS
Definition PKeyboard.h:197
@ PEBL_KEYCODE_CLEAR
Definition PKeyboard.h:229
@ PEBL_KEYCODE_1
Definition PKeyboard.h:101
@ PEBL_KEYCODE_NUMLOCK
Definition PKeyboard.h:330
@ PEBL_KEYCODE_KP_8
Definition PKeyboard.h:191
@ PEBL_KEYCODE_u
Definition PKeyboard.h:146
@ PEBL_KEYCODE_b
Definition PKeyboard.h:127
@ PEBL_KEYCODE_F10
Definition PKeyboard.h:162
@ PEBL_KEYCODE_KP_1
Definition PKeyboard.h:184
@ PEBL_KEYCODE_LEFT
Definition PKeyboard.h:175
@ PEBL_KEYCODE_RIGHT
Definition PKeyboard.h:174
@ PEBL_KEYCODE_F12
Definition PKeyboard.h:164
@ PEBL_KEYCODE_F2
Definition PKeyboard.h:154
@ PEBL_KEYCODE_2
Definition PKeyboard.h:102
@ PEBL_KEYCODE_PERIOD
Definition PKeyboard.h:98
@ PEBL_KEYCODE_KP_DIVIDE
Definition PKeyboard.h:179
@ PEBL_KEYCODE_3
Definition PKeyboard.h:103
@ PEBL_KEYCODE_y
Definition PKeyboard.h:150
@ PEBL_KEYCODE_END
Definition PKeyboard.h:172
@ PEBL_KEYCODE_7
Definition PKeyboard.h:107
@ PEBL_KEYCODE_CAPSLOCK
Definition PKeyboard.h:152
@ PEBL_KEYCODE_4
Definition PKeyboard.h:104
@ PEBL_KEYCODE_INSERT
Definition PKeyboard.h:168
@ PEBL_KEYCODE_BACKSPACE
Definition PKeyboard.h:82
@ PEBL_KEYCODE_t
Definition PKeyboard.h:145
@ PEBL_KEYCODE_w
Definition PKeyboard.h:148
@ PEBL_KEYCODE_COMMA
Definition PKeyboard.h:96
@ PEBL_KEYCODE_l
Definition PKeyboard.h:137
@ PEBL_KEYCODE_DOLLAR
Definition PKeyboard.h:89
@ PEBL_KEYCODE_c
Definition PKeyboard.h:128
@ PEBL_KEYCODE_F1
Definition PKeyboard.h:153
@ PEBL_KEYCODE_v
Definition PKeyboard.h:147
@ PEBL_KEYCODE_9
Definition PKeyboard.h:109
@ PEBL_KEYCODE_q
Definition PKeyboard.h:142
@ PEBL_KEYCODE_h
Definition PKeyboard.h:133
@ PEBL_KEYCODE_GREATER
Definition PKeyboard.h:114
@ PEBL_KEYCODE_AMPERSAND
Definition PKeyboard.h:90
@ PEBL_KEYCODE_QUESTION
Definition PKeyboard.h:115
@ PEBL_KEYCODE_KP_2
Definition PKeyboard.h:185
@ PEBL_KEYCODE_MINUS
Definition PKeyboard.h:97
@ PEBL_KEYCODE_s
Definition PKeyboard.h:144
@ PEBL_KEYCODE_RETURN
Definition PKeyboard.h:80
@ PEBL_KEYCODE_KP_6
Definition PKeyboard.h:189
@ PEBL_KEYCODE_TAB
Definition PKeyboard.h:83
@ PEBL_KEYCODE_8
Definition PKeyboard.h:108
@ PEBL_KEYCODE_UP
Definition PKeyboard.h:177
@ PEBL_KEYCODE_PAUSE
Definition PKeyboard.h:167
@ PEBL_KEYCODE_z
Definition PKeyboard.h:151
@ PEBL_KEYCODE_LCTRL
Definition PKeyboard.h:284
@ PEBL_KEYCODE_LSHIFT
Definition PKeyboard.h:285
@ PEBL_KEYCODE_SEMICOLON
Definition PKeyboard.h:111
@ PEBL_KEYCODE_PAGEDOWN
Definition PKeyboard.h:173
#define PEBLMOD_SHIFT
Definition PKeyboard.h:66
bool is_utf8(std::string str)
Definition md5.h:54
Variant GetProperty(std::string prop) const
void SetProperty(std::string, Variant v)
This class simply represent an abstract text-based object.
virtual bool SetProperty(std::string, Variant v)
Definition PList.h:45
void PushBack(const Variant &v)
Definition PList.cpp:149
PComplexData * GetComplexData() const
Definition Variant.cpp:1299
@ JSMN_PRIMITIVE
Definition jsmn.h:51
@ JSMN_OBJECT
Definition jsmn.h:48
@ JSMN_ARRAY
Definition jsmn.h:49
@ JSMN_STRING
Definition jsmn.h:50
JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, jsmntok_t *tokens, const unsigned int num_tokens)
Definition jsmn.h:265
JSMN_API void jsmn_init(jsmn_parser *parser)
Definition jsmn.h:456
std::string md5(const std::string str)
Definition md5.cpp:360
#define PROT_READ
Definition mman.h:27
#define MAP_SHARED
Definition mman.h:32
void * mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
Variant SystemCall(std::string path, std::string args)
pDouble StringToPDouble(const char *mystring)
Variant ResolvePropertyChain(Variant obj, const std::string &propertyChain)
Variant LaunchFile(std::string file)
void strrev(char *p)
Variant GetHomeDirectory()
PEBL_Keycode TranslateString(const std::string &letters)
PEBLVideoDepth GetVideoDepth(std::string depthline)
const std::string GetBaseFileName(const std::string &file)
bool is_utf8(const std::string str)
pDouble Log2(pDouble val)
void SetPropertyChain(Variant obj, const std::string &propertyChain, Variant value)
pDouble RandomUniform()
pDouble RandomNormal()
const std::string StripFile(const std::string &file)
std::string TranslateKeycode(const PEBL_Keycode key, int modkeys)
void InitializeKeycodeLookups()
std::string ToUpper(const std::string &text)
Variant SetWorkingDirectory(std::string path)
void strrev_utf8(char *p)
std::string DetectScript(const std::string &text)
Variant DeleteMyFile(std::string path)
Variant ParseJSON(const std::string &text)
std::string MD5String(const std::string &text)
Variant ExtractJSONObject(const std::string &text, int remaining, jsmntok_t **t, int start, int end)
bool IsRTLScript(const std::string &script)
std::string MD5File(const std::string &filename)
Variant FileExists(std::string path)
void CopyToClipboard(const std::string &text)
std::string ShiftSwitch(int modkeys, std::string lower, std::string upper)
pInt Round(pDouble val)
Variant Tokenize(const char *line, char separator)
Variant GetDirectoryListing(std::string path)
std::string GetFontForLanguageOrScript(const std::string &code, int fontType)
Variant GetWorkingDirectory()
pInt Truncate(pDouble val)
Variant MakeDirectory(std::string path)
std::string ToLower(const std::string &text)
Variant IsDirectory(std::string path)
PEBLVideoMode GetVideoMode(std::string modeline)
void SignalFatalError(const std::string &message)
int start
Definition jsmn.h:71