1 /* 2 * Copyright (c) 2014, 2018, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 34 #include "Platform.h" 35 36 #ifdef LINUX 37 38 #include "JavaVirtualMachine.h" 39 #include "LinuxPlatform.h" 40 #include "PlatformString.h" 41 42 43 #include <stdlib.h> 44 #include <pwd.h> 45 #include <sys/file.h> 46 #include <sys/stat.h> 47 #include <errno.h> 48 #include <unistd.h> 49 #include <sys/types.h> 50 #include <limits.h> 51 52 #define LINUX_PACKAGER_TMP_DIR "/.java/packager/tmp" 53 54 55 TString GetEnv(const TString &name) { 56 TString result; 57 58 char *value = ::getenv((TCHAR*)name.c_str()); 59 60 if (value != NULL) { 61 result = value; 62 } 63 64 return result; 65 } 66 67 LinuxPlatform::LinuxPlatform(void) : Platform(), GenericPlatform(), PosixPlatform() { 68 FMainThread = pthread_self(); 69 } 70 71 LinuxPlatform::~LinuxPlatform(void) { 72 } 73 74 void LinuxPlatform::ShowMessage(TString title, TString description) { 75 printf("%s %s\n", PlatformString(title).toPlatformString(), PlatformString(description).toPlatformString()); 76 fflush(stdout); 77 } 78 79 void LinuxPlatform::ShowMessage(TString description) { 80 TString appname = GetModuleFileName(); 81 appname = FilePath::ExtractFileName(appname); 82 ShowMessage(PlatformString(appname).toPlatformString(), PlatformString(description).toPlatformString()); 83 } 84 85 TCHAR* LinuxPlatform::ConvertStringToFileSystemString(TCHAR* Source, bool &release) { 86 // Not Implemented. 87 return NULL; 88 } 89 90 TCHAR* LinuxPlatform::ConvertFileSystemStringToString(TCHAR* Source, bool &release) { 91 // Not Implemented. 92 return NULL; 93 } 94 95 TString LinuxPlatform::GetModuleFileName() { 96 size_t len = 0; 97 TString result; 98 DynamicBuffer<TCHAR> buffer(MAX_PATH); 99 100 if ((len = readlink("/proc/self/exe", buffer.GetData(), MAX_PATH - 1)) != -1) { 101 buffer[len] = '\0'; 102 result = buffer.GetData(); 103 } 104 105 return result; 106 } 107 108 void LinuxPlatform::SetCurrentDirectory(TString Value) { 109 chdir(PlatformString(Value).toPlatformString()); 110 } 111 112 TString LinuxPlatform::GetPackageRootDirectory() { 113 TString filename = GetModuleFileName(); 114 return FilePath::ExtractFilePath(filename); 115 } 116 117 TString LinuxPlatform::GetAppDataDirectory() { 118 TString result; 119 TString home = GetEnv(_T("HOME")); 120 121 if (home.empty() == false) { 122 result += FilePath::IncludeTrailingSeparater(home) + _T(".local"); 123 } 124 125 return result; 126 } 127 128 ISectionalPropertyContainer* LinuxPlatform::GetConfigFile(TString FileName) { 129 IniFile *result = new IniFile(); 130 131 if (result->LoadFromFile(FileName) == false) { 132 // New property file format was not found, attempt to load old property file format. 133 Helpers::LoadOldConfigFile(FileName, result); 134 } 135 136 return result; 137 } 138 139 TString LinuxPlatform::GetBundledJVMLibraryFileName(TString RuntimePath) { 140 TString result = FilePath::IncludeTrailingSeparater(RuntimePath) + 141 "lib/jli/libjli.so"; 142 143 if (FilePath::FileExists(result) == false) { 144 result = FilePath::IncludeTrailingSeparater(RuntimePath) + 145 "lib/jli/libjli.so"; 146 } 147 148 return result; 149 } 150 151 bool LinuxPlatform::IsMainThread() { 152 bool result = (FMainThread == pthread_self()); 153 return result; 154 } 155 156 TString LinuxPlatform::getTmpDirString() { 157 return TString(LINUX_PACKAGER_TMP_DIR); 158 } 159 160 void LinuxPlatform::reactivateAnotherInstance() { 161 if (singleInstanceProcessId == 0) { 162 printf("Unable to reactivate another instance, PID is undefined"); 163 return; 164 } 165 166 const ProcessReactivator reactivator(singleInstanceProcessId); 167 } 168 169 TPlatformNumber LinuxPlatform::GetMemorySize() { 170 long pages = sysconf(_SC_PHYS_PAGES); 171 long page_size = sysconf(_SC_PAGE_SIZE); 172 TPlatformNumber result = pages * page_size; 173 result = result / 1048576; // Convert from bytes to megabytes. 174 return result; 175 } 176 177 #ifdef DEBUG 178 bool LinuxPlatform::IsNativeDebuggerPresent() { 179 // gdb opens file descriptors stdin=3, stdout=4, stderr=5 whereas 180 // a typical prog uses only stdin=0, stdout=1, stderr=2. 181 bool result = false; 182 FILE *fd = fopen("/tmp", "r"); 183 184 if (fileno(fd) > 5) { 185 result = true; 186 } 187 188 fclose(fd); 189 return result; 190 } 191 192 int LinuxPlatform::GetProcessID() { 193 int pid = getpid(); 194 return pid; 195 } 196 #endif //DEBUG 197 198 //-------------------------------------------------------------------------------------------------- 199 200 #ifndef __UNIX_DEPLOY_PLATFORM__ 201 #define __UNIX_DEPLOY_PLATFORM__ 202 203 /** Provide an abstraction for difference in the platform APIs, 204 e.g. string manipulation functions, etc. */ 205 #include <stdio.h> 206 #include <string.h> 207 #include <strings.h> 208 #include <sys/stat.h> 209 210 #define TCHAR char 211 212 #define _T(x) x 213 214 #define DEPLOY_MULTIBYTE_SNPRINTF snprintf 215 216 #define DEPLOY_SNPRINTF(buffer, sizeOfBuffer, count, format, ...) \ 217 snprintf((buffer), (count), (format), __VA_ARGS__) 218 219 #define DEPLOY_PRINTF(format, ...) \ 220 printf((format), ##__VA_ARGS__) 221 222 #define DEPLOY_FPRINTF(dest, format, ...) \ 223 fprintf((dest), (format), __VA_ARGS__) 224 225 #define DEPLOY_SSCANF(buf, format, ...) \ 226 sscanf((buf), (format), __VA_ARGS__) 227 228 #define DEPLOY_STRDUP(strSource) \ 229 strdup((strSource)) 230 231 //return "error code" (like on Windows) 232 static int DEPLOY_STRNCPY(char *strDest, size_t numberOfElements, const char *strSource, size_t count) { 233 char *s = strncpy(strDest, strSource, count); 234 // Duplicate behavior of the Windows' _tcsncpy_s() by adding a NULL 235 // terminator at the end of the string. 236 if (count < numberOfElements) { 237 s[count] = '\0'; 238 } else { 239 s[numberOfElements - 1] = '\0'; 240 } 241 return (s == strDest) ? 0 : 1; 242 } 243 244 static int DEPLOY_STRNCAT(char *strDest, size_t numberOfElements, const char *strSource, size_t count) { 245 // strncat always return null terminated string 246 char *s = strncat(strDest, strSource, count); 247 return (s == strDest) ? 0 : 1; 248 } 249 250 #define DEPLOY_STRICMP(x, y) \ 251 strcasecmp((x), (y)) 252 253 #define DEPLOY_STRNICMP(x, y, cnt) \ 254 strncasecmp((x), (y), (cnt)) 255 256 #define DEPLOY_STRNCMP(x, y, cnt) \ 257 strncmp((x), (y), (cnt)) 258 259 #define DEPLOY_STRLEN(x) \ 260 strlen((x)) 261 262 #define DEPLOY_STRSTR(x, y) \ 263 strstr((x), (y)) 264 265 #define DEPLOY_STRCHR(x, y) \ 266 strchr((x), (y)) 267 268 #define DEPLOY_STRRCHR(x, y) \ 269 strrchr((x), (y)) 270 271 #define DEPLOY_STRPBRK(x, y) \ 272 strpbrk((x), (y)) 273 274 #define DEPLOY_GETENV(x) \ 275 getenv((x)) 276 277 #define DEPLOY_PUTENV(x) \ 278 putenv((x)) 279 280 #define DEPLOY_STRCMP(x, y) \ 281 strcmp((x), (y)) 282 283 #define DEPLOY_STRCPY(x, y) \ 284 strcpy((x), (y)) 285 286 #define DEPLOY_STRCAT(x, y) \ 287 strcat((x), (y)) 288 289 #define DEPLOY_ATOI(x) \ 290 atoi((x)) 291 292 static int getFileSize(TCHAR* filename) { 293 struct stat statBuf; 294 if (stat(filename, &statBuf) == 0) { 295 return statBuf.st_size; 296 } 297 return -1; 298 } 299 300 #define DEPLOY_FILE_SIZE(filename) getFileSize(filename) 301 302 #define DEPLOY_FOPEN(x, y) \ 303 fopen((x), (y)) 304 305 #define DEPLOY_FGETS(x, y, z) \ 306 fgets((x), (y), (z)) 307 308 #define DEPLOY_REMOVE(x) \ 309 remove((x)) 310 311 #define DEPLOY_SPAWNV(mode, cmd, args) \ 312 spawnv((mode), (cmd), (args)) 313 314 #define DEPLOY_ISDIGIT(ch) isdigit(ch) 315 316 // for non-unicode, just return the input string for 317 // the following 2 conversions 318 #define DEPLOY_NEW_MULTIBYTE(message) message 319 320 #define DEPLOY_NEW_FROM_MULTIBYTE(message) message 321 322 // for non-unicode, no-op for the relase operation 323 // since there is no memory allocated for the 324 // string conversions 325 #define DEPLOY_RELEASE_MULTIBYTE(tmpMBCS) 326 327 #define DEPLOY_RELEASE_FROM_MULTIBYTE(tmpMBCS) 328 329 // The size will be used for converting from 1 byte to 1 byte encoding. 330 // Ensure have space for zero-terminator. 331 #define DEPLOY_GET_SIZE_FOR_ENCODING(message, theLength) (theLength + 1) 332 333 #endif 334 #define xmlTagType 0 335 #define xmlPCDataType 1 336 337 typedef struct _xmlNode XMLNode; 338 typedef struct _xmlAttribute XMLAttribute; 339 340 struct _xmlNode { 341 int _type; // Type of node: tag, pcdata, cdate 342 TCHAR* _name; // Contents of node 343 XMLNode* _next; // Next node at same level 344 XMLNode* _sub; // First sub-node 345 XMLAttribute* _attributes; // List of attributes 346 }; 347 348 struct _xmlAttribute { 349 TCHAR* _name; // Name of attribute 350 TCHAR* _value; // Value of attribute 351 XMLAttribute* _next; // Next attribute for this tag 352 }; 353 354 // Public interface 355 static void RemoveNonAsciiUTF8FromBuffer(char *buf); 356 XMLNode* ParseXMLDocument (TCHAR* buf); 357 void FreeXMLDocument (XMLNode* root); 358 359 // Utility methods for parsing document 360 XMLNode* FindXMLChild (XMLNode* root, const TCHAR* name); 361 TCHAR* FindXMLAttribute (XMLAttribute* attr, const TCHAR* name); 362 363 // Debugging 364 void PrintXMLDocument(XMLNode* node, int indt); 365 366 367 #include <sys/types.h> 368 #include <sys/stat.h> 369 #include <setjmp.h> 370 #include <stdlib.h> 371 #include <wctype.h> 372 373 374 #define JWS_assert(s, msg) \ 375 if (!(s)) { Abort(msg); } 376 377 378 // Internal declarations 379 static XMLNode* ParseXMLElement(void); 380 static XMLAttribute* ParseXMLAttribute(void); 381 static TCHAR* SkipWhiteSpace(TCHAR *p); 382 static TCHAR* SkipXMLName(TCHAR *p); 383 static TCHAR* SkipXMLComment(TCHAR *p); 384 static TCHAR* SkipXMLDocType(TCHAR *p); 385 static TCHAR* SkipXMLProlog(TCHAR *p); 386 static TCHAR* SkipPCData(TCHAR *p); 387 static int IsPCData(TCHAR *p); 388 static void ConvertBuiltInEntities(TCHAR* p); 389 static void SetToken(int type, TCHAR* start, TCHAR* end); 390 static void GetNextToken(void); 391 static XMLNode* CreateXMLNode(int type, TCHAR* name); 392 static XMLAttribute* CreateXMLAttribute(TCHAR *name, TCHAR* value); 393 static XMLNode* ParseXMLElement(void); 394 static XMLAttribute* ParseXMLAttribute(void); 395 static void FreeXMLAttribute(XMLAttribute* attr); 396 static void PrintXMLAttributes(XMLAttribute* attr); 397 static void indent(int indt); 398 399 static jmp_buf jmpbuf; 400 static XMLNode* root_node = NULL; 401 402 /** definition of error codes for setjmp/longjmp, 403 * that can be handled in ParseXMLDocument() 404 */ 405 #define JMP_NO_ERROR 0 406 #define JMP_OUT_OF_RANGE 1 407 408 #define NEXT_CHAR(p) {if (*p != 0) { p++;} else {longjmp(jmpbuf, JMP_OUT_OF_RANGE);}} 409 #define NEXT_CHAR_OR_BREAK(p) {if (*p != 0) { p++;} else {break;}} 410 #define NEXT_CHAR_OR_RETURN(p) {if (*p != 0) { p++;} else {return;}} 411 #define SKIP_CHARS(p,n) {int i; for (i = 0; i < (n); i++) \ 412 {if (*p != 0) { p++;} else \ 413 {longjmp(jmpbuf, JMP_OUT_OF_RANGE);}}} 414 #define SKIP_CHARS_OR_BREAK(p,n) {int i; for (i = 0; i < (n); i++) \ 415 {if (*p != 0) { p++;} else {break;}} \ 416 {if (i < (n)) {break;}}} 417 418 /** Iterates through the null-terminated buffer (i.e., C string) and replaces all 419 * UTF-8 encoded character >255 with 255 420 * 421 * UTF-8 encoding: 422 * 423 * Range A: 0x0000 - 0x007F 424 * 0 | bits 0 - 7 425 * Range B : 0x0080 - 0x07FF : 426 * 110 | bits 6 - 10 427 * 10 | bits 0 - 5 428 * Range C : 0x0800 - 0xFFFF : 429 * 1110 | bits 12-15 430 * 10 | bits 6-11 431 * 10 | bits 0-5 432 */ 433 static void RemoveNonAsciiUTF8FromBuffer(char *buf) { 434 char* p; 435 char* q; 436 char c; 437 p = q = buf; 438 /* We are not using NEXT_CHAR() to check if *q is NULL, as q is output location 439 and offset for q is smaller than for p. */ 440 while(*p != '\0') { 441 c = *p; 442 if ( (c & 0x80) == 0) { 443 /* Range A */ 444 *q++ = *p; 445 NEXT_CHAR(p); 446 } else if ((c & 0xE0) == 0xC0){ 447 /* Range B */ 448 *q++ = (char)0xFF; 449 NEXT_CHAR(p); 450 NEXT_CHAR_OR_BREAK(p); 451 } else { 452 /* Range C */ 453 *q++ = (char)0xFF; 454 NEXT_CHAR(p); 455 SKIP_CHARS_OR_BREAK(p, 2); 456 } 457 } 458 /* Null terminate string */ 459 *q = '\0'; 460 } 461 462 /* --------------------------------------------------------------------- */ 463 464 static TCHAR* SkipWhiteSpace(TCHAR *p) { 465 if (p != NULL) { 466 while(iswspace(*p)) 467 NEXT_CHAR_OR_BREAK(p); 468 } 469 return p; 470 } 471 472 static TCHAR* SkipXMLName(TCHAR *p) { 473 TCHAR c = *p; 474 /* Check if start of token */ 475 if ( ('a' <= c && c <= 'z') || 476 ('A' <= c && c <= 'Z') || 477 c == '_' || c == ':') { 478 479 while( ('a' <= c && c <= 'z') || 480 ('A' <= c && c <= 'Z') || 481 ('0' <= c && c <= '9') || 482 c == '_' || c == ':' || c == '.' || c == '-' ) { 483 NEXT_CHAR(p); 484 c = *p; 485 if (c == '\0') break; 486 } 487 } 488 return p; 489 } 490 491 static TCHAR* SkipXMLComment(TCHAR *p) { 492 if (p != NULL) { 493 if (DEPLOY_STRNCMP(p, _T("<!--"), 4) == 0) { 494 SKIP_CHARS(p, 4); 495 do { 496 if (DEPLOY_STRNCMP(p, _T("-->"), 3) == 0) { 497 SKIP_CHARS(p, 3); 498 return p; 499 } 500 NEXT_CHAR(p); 501 } while(*p != '\0'); 502 } 503 } 504 return p; 505 } 506 507 static TCHAR* SkipXMLDocType(TCHAR *p) { 508 if (p != NULL) { 509 if (DEPLOY_STRNCMP(p, _T("<!"), 2) == 0) { 510 SKIP_CHARS(p, 2); 511 while (*p != '\0') { 512 if (*p == '>') { 513 NEXT_CHAR(p); 514 return p; 515 } 516 NEXT_CHAR(p); 517 } 518 } 519 } 520 return p; 521 } 522 523 static TCHAR* SkipXMLProlog(TCHAR *p) { 524 if (p != NULL) { 525 if (DEPLOY_STRNCMP(p, _T("<?"), 2) == 0) { 526 SKIP_CHARS(p, 2); 527 do { 528 if (DEPLOY_STRNCMP(p, _T("?>"), 2) == 0) { 529 SKIP_CHARS(p, 2); 530 return p; 531 } 532 NEXT_CHAR(p); 533 } while(*p != '\0'); 534 } 535 } 536 return p; 537 } 538 539 /* Search for the built-in XML entities: 540 * & (&), < (<), > (>), ' ('), and "e(") 541 * and convert them to a real TCHARacter 542 */ 543 static void ConvertBuiltInEntities(TCHAR* p) { 544 TCHAR* q; 545 q = p; 546 /* We are not using NEXT_CHAR() to check if *q is NULL, as q is output location 547 and offset for q is smaller than for p. */ 548 while(*p) { 549 if (IsPCData(p)) { 550 /* dont convert &xxx values within PData */ 551 TCHAR *end; 552 end = SkipPCData(p); 553 while(p < end) { 554 *q++ = *p; 555 NEXT_CHAR(p); 556 } 557 } else { 558 if (DEPLOY_STRNCMP(p, _T("&"), 5) == 0) { 559 *q++ = '&'; 560 SKIP_CHARS(p, 5); 561 } else if (DEPLOY_STRNCMP(p, _T("<"), 4) == 0) { 562 *q = '<'; 563 SKIP_CHARS(p, 4); 564 } else if (DEPLOY_STRNCMP(p, _T(">"), 4) == 0) { 565 *q = '>'; 566 SKIP_CHARS(p, 4); 567 } else if (DEPLOY_STRNCMP(p, _T("'"), 6) == 0) { 568 *q = '\''; 569 SKIP_CHARS(p, 6); 570 } else if (DEPLOY_STRNCMP(p, _T(""e;"), 7) == 0) { 571 *q = '\"'; 572 SKIP_CHARS(p, 7); 573 } else { 574 *q++ = *p; 575 NEXT_CHAR(p); 576 } 577 } 578 } 579 *q = '\0'; 580 } 581 582 /* ------------------------------------------------------------- */ 583 /* XML tokenizer */ 584 585 #define TOKEN_UNKNOWN 0 586 #define TOKEN_BEGIN_TAG 1 /* <tag */ 587 #define TOKEN_END_TAG 2 /* </tag */ 588 #define TOKEN_CLOSE_BRACKET 3 /* > */ 589 #define TOKEN_EMPTY_CLOSE_BRACKET 4 /* /> */ 590 #define TOKEN_PCDATA 5 /* pcdata */ 591 #define TOKEN_CDATA 6 /* cdata */ 592 #define TOKEN_EOF 7 593 594 static TCHAR* CurPos = NULL; 595 static TCHAR* CurTokenName = NULL; 596 static int CurTokenType; 597 static int MaxTokenSize = -1; 598 599 /* Copy token from buffer to Token variable */ 600 static void SetToken(int type, TCHAR* start, TCHAR* end) { 601 int len = end - start; 602 if (len > MaxTokenSize) { 603 if (CurTokenName != NULL) free(CurTokenName); 604 CurTokenName = (TCHAR *)malloc((len + 1) * sizeof(TCHAR)); 605 if (CurTokenName == NULL ) { 606 return; 607 } 608 MaxTokenSize = len; 609 } 610 611 CurTokenType = type; 612 DEPLOY_STRNCPY(CurTokenName, len + 1, start, len); 613 CurTokenName[len] = '\0'; 614 } 615 616 /* Skip XML comments, doctypes, and prolog tags */ 617 static TCHAR* SkipFilling(void) { 618 TCHAR *q = CurPos; 619 620 /* Skip white space and comment sections */ 621 do { 622 q = CurPos; 623 CurPos = SkipWhiteSpace(CurPos); 624 CurPos = SkipXMLComment(CurPos); /* Must be called befor DocTypes */ 625 CurPos = SkipXMLDocType(CurPos); /* <! ... > directives */ 626 CurPos = SkipXMLProlog(CurPos); /* <? ... ?> directives */ 627 } while(CurPos != q); 628 629 return CurPos; 630 } 631 632 /* Parses next token and initializes the global token variables above 633 The tokennizer automatically skips comments (<!-- comment -->) and 634 <! ... > directives. 635 */ 636 static void GetNextToken(void) { 637 TCHAR *p, *q; 638 639 /* Skip white space and comment sections */ 640 p = SkipFilling(); 641 642 if (p == NULL || *p == '\0') { 643 CurTokenType = TOKEN_EOF; 644 return; 645 } else if (p[0] == '<' && p[1] == '/') { 646 /* TOKEN_END_TAG */ 647 q = SkipXMLName(p + 2); 648 SetToken(TOKEN_END_TAG, p + 2, q); 649 p = q; 650 } else if (*p == '<') { 651 /* TOKEN_BEGIN_TAG */ 652 q = SkipXMLName(p + 1); 653 SetToken(TOKEN_BEGIN_TAG, p + 1, q); 654 p = q; 655 } else if (p[0] == '>') { 656 CurTokenType = TOKEN_CLOSE_BRACKET; 657 NEXT_CHAR(p); 658 } else if (p[0] == '/' && p[1] == '>') { 659 CurTokenType = TOKEN_EMPTY_CLOSE_BRACKET; 660 SKIP_CHARS(p, 2); 661 } else { 662 /* Search for end of data */ 663 q = p + 1; 664 while(*q && *q != '<') { 665 if (IsPCData(q)) { 666 q = SkipPCData(q); 667 } else { 668 NEXT_CHAR(q); 669 } 670 } 671 SetToken(TOKEN_PCDATA, p, q); 672 /* Convert all entities inside token */ 673 ConvertBuiltInEntities(CurTokenName); 674 p = q; 675 } 676 /* Advance pointer to beginning of next token */ 677 CurPos = p; 678 } 679 680 static XMLNode* CreateXMLNode(int type, TCHAR* name) { 681 XMLNode* node; 682 node = (XMLNode*)malloc(sizeof(XMLNode)); 683 if (node == NULL) { 684 return NULL; 685 } 686 node->_type = type; 687 node->_name = name; 688 node->_next = NULL; 689 node->_sub = NULL; 690 node->_attributes = NULL; 691 return node; 692 } 693 694 static XMLAttribute* CreateXMLAttribute(TCHAR *name, TCHAR* value) { 695 XMLAttribute* attr; 696 attr = (XMLAttribute*)malloc(sizeof(XMLAttribute)); 697 if (attr == NULL) { 698 return NULL; 699 } 700 attr->_name = name; 701 attr->_value = value; 702 attr->_next = NULL; 703 return attr; 704 } 705 706 XMLNode* ParseXMLDocument(TCHAR* buf) { 707 XMLNode* root; 708 int err_code = setjmp(jmpbuf); 709 switch (err_code) 710 { 711 case JMP_NO_ERROR: 712 #ifndef _UNICODE 713 /* Remove UTF-8 encoding from buffer */ 714 RemoveNonAsciiUTF8FromBuffer(buf); 715 #endif 716 717 /* Get first Token */ 718 CurPos = buf; 719 GetNextToken(); 720 721 /* Parse document*/ 722 root = ParseXMLElement(); 723 break; 724 case JMP_OUT_OF_RANGE: 725 /* cleanup: */ 726 if (root_node != NULL) { 727 FreeXMLDocument(root_node); 728 root_node = NULL; 729 } 730 if (CurTokenName != NULL) free(CurTokenName); 731 fprintf(stderr,"Error during parsing jnlp file...\n"); 732 exit(-1); 733 break; 734 default: 735 root = NULL; 736 break; 737 } 738 739 return root; 740 } 741 742 static XMLNode* ParseXMLElement(void) { 743 XMLNode* node = NULL; 744 XMLNode* subnode = NULL; 745 XMLNode* nextnode = NULL; 746 XMLAttribute* attr = NULL; 747 748 if (CurTokenType == TOKEN_BEGIN_TAG) { 749 750 /* Create node for new element tag */ 751 node = CreateXMLNode(xmlTagType, DEPLOY_STRDUP(CurTokenName)); 752 /* We need to save root node pointer to be able to cleanup 753 if an error happens during parsing */ 754 if(!root_node) { 755 root_node = node; 756 } 757 /* Parse attributes. This section eats a all input until 758 EOF, a > or a /> */ 759 attr = ParseXMLAttribute(); 760 while(attr != NULL) { 761 attr->_next = node->_attributes; 762 node->_attributes = attr; 763 attr = ParseXMLAttribute(); 764 } 765 766 /* This will eihter be a TOKEN_EOF, TOKEN_CLOSE_BRACKET, or a 767 * TOKEN_EMPTY_CLOSE_BRACKET */ 768 GetNextToken(); 769 770 /* Skip until '>', '/>' or EOF. This should really be an error, */ 771 /* but we are loose */ 772 // if(CurTokenType == TOKEN_EMPTY_CLOSE_BRACKET || 773 // CurTokenType == TOKEN_CLOSE_BRACKET || 774 // CurTokenType == TOKEN_EOF) { 775 // println("XML Parsing error: wrong kind of token found"); 776 // return NULL; 777 // } 778 779 if (CurTokenType == TOKEN_EMPTY_CLOSE_BRACKET) { 780 GetNextToken(); 781 /* We are done with the sublevel - fall through to continue */ 782 /* parsing tags at the same level */ 783 } else if (CurTokenType == TOKEN_CLOSE_BRACKET) { 784 GetNextToken(); 785 786 /* Parse until end tag if found */ 787 node->_sub = ParseXMLElement(); 788 789 if (CurTokenType == TOKEN_END_TAG) { 790 /* Find closing bracket '>' for end tag */ 791 do { 792 GetNextToken(); 793 } while(CurTokenType != TOKEN_EOF && CurTokenType != TOKEN_CLOSE_BRACKET); 794 GetNextToken(); 795 } 796 } 797 798 /* Continue parsing rest on same level */ 799 if (CurTokenType != TOKEN_EOF) { 800 /* Parse rest of stream at same level */ 801 node->_next = ParseXMLElement(); 802 } 803 return node; 804 805 } else if (CurTokenType == TOKEN_PCDATA) { 806 /* Create node for pcdata */ 807 node = CreateXMLNode(xmlPCDataType, DEPLOY_STRDUP(CurTokenName)); 808 /* We need to save root node pointer to be able to cleanup 809 if an error happens during parsing */ 810 if(!root_node) { 811 root_node = node; 812 } 813 GetNextToken(); 814 return node; 815 } 816 817 /* Something went wrong. */ 818 return NULL; 819 } 820 821 /* Parses an XML attribute. */ 822 static XMLAttribute* ParseXMLAttribute(void) { 823 TCHAR* q = NULL; 824 TCHAR* name = NULL; 825 TCHAR* PrevPos = NULL; 826 827 do 828 { 829 /* We need to check this condition to avoid endless loop 830 in case if an error happend during parsing. */ 831 if (PrevPos == CurPos) { 832 if (name != NULL) { 833 free(name); 834 name = NULL; 835 } 836 837 return NULL; 838 } 839 840 PrevPos = CurPos; 841 842 /* Skip whitespace etc. */ 843 SkipFilling(); 844 845 /* Check if we are done witht this attribute section */ 846 if (CurPos[0] == '\0' || 847 CurPos[0] == '>' || 848 CurPos[0] == '/' && CurPos[1] == '>') { 849 850 if (name != NULL) { 851 free(name); 852 name = NULL; 853 } 854 855 return NULL; 856 } 857 858 /* Find end of name */ 859 q = CurPos; 860 while(*q && !iswspace(*q) && *q !='=') NEXT_CHAR(q); 861 862 SetToken(TOKEN_UNKNOWN, CurPos, q); 863 if (name) { 864 free(name); 865 name = NULL; 866 } 867 name = DEPLOY_STRDUP(CurTokenName); 868 869 /* Skip any whitespace */ 870 CurPos = q; 871 CurPos = SkipFilling(); 872 873 /* Next TCHARacter must be '=' for a valid attribute. 874 If it is not, this is really an error. 875 We ignore this, and just try to parse an attribute 876 out of the rest of the string. 877 */ 878 } while(*CurPos != '='); 879 880 NEXT_CHAR(CurPos); 881 CurPos = SkipWhiteSpace(CurPos); 882 /* Parse CDATA part of attribute */ 883 if ((*CurPos == '\"') || (*CurPos == '\'')) { 884 TCHAR quoteChar = *CurPos; 885 q = ++CurPos; 886 while(*q != '\0' && *q != quoteChar) NEXT_CHAR(q); 887 SetToken(TOKEN_CDATA, CurPos, q); 888 CurPos = q + 1; 889 } else { 890 q = CurPos; 891 while(*q != '\0' && !iswspace(*q)) NEXT_CHAR(q); 892 SetToken(TOKEN_CDATA, CurPos, q); 893 CurPos = q; 894 } 895 896 //Note: no need to free name and CurTokenName duplicate; they're assigned 897 // to an XMLAttribute structure in CreateXMLAttribute 898 899 return CreateXMLAttribute(name, DEPLOY_STRDUP(CurTokenName)); 900 } 901 902 void FreeXMLDocument(XMLNode* root) { 903 if (root == NULL) return; 904 FreeXMLDocument(root->_sub); 905 FreeXMLDocument(root->_next); 906 FreeXMLAttribute(root->_attributes); 907 free(root->_name); 908 free(root); 909 } 910 911 static void FreeXMLAttribute(XMLAttribute* attr) { 912 if (attr == NULL) return; 913 free(attr->_name); 914 free(attr->_value); 915 FreeXMLAttribute(attr->_next); 916 free(attr); 917 } 918 919 /* Find element at current level with a given name */ 920 XMLNode* FindXMLChild(XMLNode* root, const TCHAR* name) { 921 if (root == NULL) return NULL; 922 923 if (root->_type == xmlTagType && DEPLOY_STRCMP(root->_name, name) == 0) { 924 return root; 925 } 926 927 return FindXMLChild(root->_next, name); 928 } 929 930 /* Search for an attribute with the given name and returns the contents. Returns NULL if 931 * attribute is not found 932 */ 933 TCHAR* FindXMLAttribute(XMLAttribute* attr, const TCHAR* name) { 934 if (attr == NULL) return NULL; 935 if (DEPLOY_STRCMP(attr->_name, name) == 0) return attr->_value; 936 return FindXMLAttribute(attr->_next, name); 937 } 938 939 940 void PrintXMLDocument(XMLNode* node, int indt) { 941 if (node == NULL) return; 942 943 if (node->_type == xmlTagType) { 944 DEPLOY_PRINTF(_T("\n")); 945 indent(indt); 946 DEPLOY_PRINTF(_T("<%s"), node->_name); 947 PrintXMLAttributes(node->_attributes); 948 if (node->_sub == NULL) { 949 DEPLOY_PRINTF(_T("/>\n")); 950 } else { 951 DEPLOY_PRINTF(_T(">")); 952 PrintXMLDocument(node->_sub, indt + 1); 953 indent(indt); 954 DEPLOY_PRINTF(_T("</%s>"), node->_name); 955 } 956 } else { 957 DEPLOY_PRINTF(_T("%s"), node->_name); 958 } 959 PrintXMLDocument(node->_next, indt); 960 } 961 962 static void PrintXMLAttributes(XMLAttribute* attr) { 963 if (attr == NULL) return; 964 965 DEPLOY_PRINTF(_T(" %s=\"%s\""), attr->_name, attr->_value); 966 PrintXMLAttributes(attr->_next); 967 } 968 969 static void indent(int indt) { 970 int i; 971 for(i = 0; i < indt; i++) { 972 DEPLOY_PRINTF(_T(" ")); 973 } 974 } 975 976 const TCHAR *CDStart = _T("<![CDATA["); 977 const TCHAR *CDEnd = _T("]]>"); 978 979 980 static TCHAR* SkipPCData(TCHAR *p) { 981 TCHAR *end = DEPLOY_STRSTR(p, CDEnd); 982 if (end != NULL) { 983 return end+sizeof(CDEnd); 984 } 985 return (++p); 986 } 987 988 static int IsPCData(TCHAR *p) { 989 return (DEPLOY_STRNCMP(CDStart, p, sizeof(CDStart)) == 0); 990 } 991 992 //-------------------------------------------------------------------------------------------------- 993 994 LinuxJavaUserPreferences::LinuxJavaUserPreferences(void) : JavaUserPreferences() { 995 } 996 997 LinuxJavaUserPreferences::~LinuxJavaUserPreferences(void) { 998 } 999 1000 TString LinuxJavaUserPreferences::GetUserPrefFileName(TString Appid) { 1001 TString result; 1002 struct passwd *pw = getpwuid(getuid()); 1003 TString homedir = pw->pw_dir; 1004 TString userOverrideFileName = FilePath::IncludeTrailingSeparater(homedir) + 1005 FilePath::IncludeTrailingSeparater(_T(".java/.userPrefs")) + 1006 FilePath::IncludeTrailingSeparater(Appid) + 1007 _T("JVMUserOptions/prefs.xml"); 1008 1009 if (FilePath::FileExists(userOverrideFileName) == true) { 1010 result = userOverrideFileName; 1011 } 1012 1013 return result; 1014 } 1015 1016 OrderedMap<TString, TString> ReadNode(XMLNode* node) { 1017 OrderedMap<TString, TString> result; 1018 XMLNode* keyNode = FindXMLChild(node->_sub, _T("entry")); 1019 1020 while (keyNode != NULL) { 1021 TString key = FindXMLAttribute(keyNode->_attributes, _T("key")); 1022 TString value = FindXMLAttribute(keyNode->_attributes, _T("value")); 1023 keyNode = keyNode->_next; 1024 1025 if (key.empty() == false) { 1026 result.Append(key, value); 1027 } 1028 } 1029 1030 return result; 1031 } 1032 1033 OrderedMap<TString, TString> GetJvmUserArgs(TString filename) { 1034 OrderedMap<TString, TString> result; 1035 1036 if (FilePath::FileExists(filename) == true) { 1037 //scan file for the key 1038 FILE* fp = fopen(PlatformString(filename).toPlatformString(), "r"); 1039 1040 if (fp != NULL) { 1041 fseek(fp, 0, SEEK_END); 1042 long fsize = ftell(fp); 1043 rewind(fp); 1044 DynamicBuffer<char> buffer(fsize + 1); 1045 fread(buffer.GetData(), fsize, 1, fp); 1046 fclose(fp); 1047 buffer[fsize] = 0; 1048 1049 XMLNode* node = NULL; 1050 XMLNode* doc = ParseXMLDocument(buffer.GetData()); 1051 1052 if (doc != NULL) { 1053 node = FindXMLChild(doc, _T("map")); 1054 1055 if (node != NULL) { 1056 result = ReadNode(node); 1057 } 1058 } 1059 } 1060 } 1061 1062 return result; 1063 } 1064 1065 bool LinuxJavaUserPreferences::Load(TString Appid) { 1066 bool result = false; 1067 TString filename = GetUserPrefFileName(Appid); 1068 1069 if (FilePath::FileExists(filename) == true) { 1070 FMap = GetJvmUserArgs(filename); 1071 result = true; 1072 } 1073 1074 return result; 1075 } 1076 1077 namespace { 1078 template<class funcType> 1079 class DllFunction { 1080 const Library& lib; 1081 funcType funcPtr; 1082 std::string theName; 1083 1084 public: 1085 DllFunction(const Library& library, const std::string &funcName): lib(library) { 1086 funcPtr = reinterpret_cast<funcType>(lib.GetProcAddress(funcName)); 1087 if (!funcPtr) { 1088 throw std::runtime_error("Failed to load function \"" + funcName + "\" from \"" + library.GetName() + "\" library"); 1089 } 1090 } 1091 1092 operator funcType() const { 1093 return funcPtr; 1094 } 1095 }; 1096 } // namespace 1097 1098 extern "C" { 1099 typedef Status (*XInitThreadsFuncPtr)(); 1100 typedef Display* (*XOpenDisplayFuncPtr)(char *display_name); 1101 1102 typedef Atom (*XInternAtomFuncPtr)(Display *display, char *atom_name, Bool only_if_exists); 1103 1104 typedef Window (*XDefaultRootWindowFuncPtr)(Display *display); 1105 1106 typedef int (*XCloseDisplayFuncPtr)(Display *display); 1107 } 1108 1109 ProcessReactivator::ProcessReactivator(pid_t pid): _pid(pid) { 1110 const std::string libname = "libX11.so"; 1111 if(!libX11.Load(libname)) { 1112 throw std::runtime_error("Failed to load \"" + libname + "\" library"); 1113 } 1114 1115 DllFunction<XInitThreadsFuncPtr> XInitThreadsFunc(libX11, "XInitThreads"); 1116 1117 XInitThreadsFunc(); 1118 1119 DllFunction<XOpenDisplayFuncPtr> XOpenDisplayFunc(libX11, "XOpenDisplay"); 1120 1121 _display = XOpenDisplayFunc(NULL); 1122 1123 DllFunction<XInternAtomFuncPtr> XInternAtomFunc(libX11, "XInternAtom"); 1124 1125 _atomPid = XInternAtomFunc(_display, "_NET_WM_PID", True); 1126 1127 if (_atomPid == None) { 1128 return; 1129 } 1130 1131 DllFunction<XDefaultRootWindowFuncPtr> XDefaultRootWindowFunc(libX11, "XDefaultRootWindow"); 1132 1133 searchWindowHelper(XDefaultRootWindowFunc(_display)); 1134 1135 reactivateProcess(); 1136 1137 DllFunction<XCloseDisplayFuncPtr> XCloseDisplayFunc(libX11, "XCloseDisplay"); 1138 1139 XCloseDisplayFunc(_display); 1140 } 1141 1142 extern "C" { 1143 typedef int (*XGetWindowPropertyFuncPtr)(Display *display, Window w, Atom property, 1144 long long_offset, long long_length, Bool d, Atom req_type, Atom *actual_type_return, 1145 int *actual_format_return, unsigned long *nitems_return, 1146 unsigned long *bytes_after_return, unsigned char **prop_return); 1147 1148 typedef Status (*XQueryTreeFuncPtr)(Display *display, Window w, Window *root_return, 1149 Window *parent_return, Window **children_return, unsigned int *nchildren_return); 1150 1151 typedef int (*XFreeFuncPtr)(void *data); 1152 } 1153 1154 void ProcessReactivator::searchWindowHelper(Window w) { 1155 1156 DllFunction<XGetWindowPropertyFuncPtr> XGetWindowPropertyFunc(libX11, "XGetWindowProperty"); 1157 1158 DllFunction<XFreeFuncPtr> XFreeFunc(libX11, "XFree"); 1159 1160 Atom type; 1161 int format; 1162 unsigned long num, bytesAfter; 1163 unsigned char* propPid = 0; 1164 if (Success == XGetWindowPropertyFunc(_display, w, _atomPid, 0, 1, False, XA_CARDINAL, 1165 &type, &format, &num, &bytesAfter, &propPid)) { 1166 if (propPid != 0) { 1167 if (_pid == *((pid_t *)propPid)) { 1168 _result.push_back(w); 1169 } 1170 XFreeFunc(propPid); 1171 } 1172 } 1173 1174 DllFunction<XQueryTreeFuncPtr> XQueryTreeFunc(libX11, "XQueryTree"); 1175 1176 Window root, parent; 1177 Window* child; 1178 unsigned int numChildren; 1179 if (0 != XQueryTreeFunc(_display, w, &root, &parent, &child, &numChildren)) { 1180 for (unsigned int i = 0; i < numChildren; i++) { 1181 searchWindowHelper(child[i]); 1182 } 1183 } 1184 } 1185 1186 1187 extern "C" { 1188 typedef Status (*XGetWindowAttributesFuncPtr)(Display *display, Window w, 1189 XWindowAttributes *window_attributes_return); 1190 1191 typedef Status (*XSendEventFuncPtr)(Display *display, Window w, Bool propagate, 1192 long event_mask, XEvent *event_send); 1193 1194 typedef int (*XRaiseWindowFuncPtr)(Display *display, Window w); 1195 } 1196 1197 void ProcessReactivator::reactivateProcess() { 1198 1199 DllFunction<XGetWindowAttributesFuncPtr> XGetWindowAttributesFunc(libX11, "XGetWindowAttributes"); 1200 1201 DllFunction<XSendEventFuncPtr> XSendEventFunc(libX11, "XSendEvent"); 1202 1203 DllFunction<XRaiseWindowFuncPtr> XRaiseWindowFunc(libX11, "XRaiseWindow"); 1204 1205 DllFunction<XInternAtomFuncPtr> XInternAtomFunc(libX11, "XInternAtom"); 1206 1207 for (std::list<Window>::const_iterator it = _result.begin(); it != _result.end(); it++) { 1208 // try sending an event to activate window, 1209 // after that we can try to raise it. 1210 XEvent xev; 1211 Atom atom = XInternAtomFunc (_display, "_NET_ACTIVE_WINDOW", False); 1212 xev.xclient.type = ClientMessage; 1213 xev.xclient.serial = 0; 1214 xev.xclient.send_event = True; 1215 xev.xclient.display = _display; 1216 xev.xclient.window = *it; 1217 xev.xclient.message_type = atom; 1218 xev.xclient.format = 32; 1219 xev.xclient.data.l[0] = 2; 1220 xev.xclient.data.l[1] = 0; 1221 xev.xclient.data.l[2] = 0; 1222 xev.xclient.data.l[3] = 0; 1223 xev.xclient.data.l[4] = 0; 1224 XWindowAttributes attr; 1225 XGetWindowAttributesFunc(_display, *it, &attr); 1226 XSendEventFunc(_display, attr.root, False, 1227 SubstructureRedirectMask | SubstructureNotifyMask, &xev); 1228 XRaiseWindowFunc(_display, *it); 1229 } 1230 } 1231 1232 //-------------------------------------------------------------------------------------------------- 1233 1234 #endif // LINUX