1 /* 2 * Copyright (c) 2014, 2017, 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 TString LinuxPlatform::GetSystemJRE() { 152 if (GetAppCDSState() != cdsDisabled) { 153 //TODO throw exception 154 return _T(""); 155 } 156 157 TString result; 158 TString jreHome = GetEnv("JRE_HOME"); 159 160 if (jreHome.empty() == false) { 161 result = FilePath::IncludeTrailingSeparater(jreHome); 162 163 if (FilePath::FileExists(result + _T("lib/rt.jar")) == false) { 164 result = FilePath::IncludeTrailingSeparater(jreHome) + _T("jre"); 165 166 if (FilePath::FileExists(result + _T("/lib/rt.jar")) == false) { 167 //check redhat location 168 if (FilePath::FileExists(_T("/usr/java/latest/jre/lib/rt.jar")) == true) { 169 result = _T("/usr/java/latest/jre"); 170 } 171 else if (FilePath::FileExists(_T("/usr/lib/jvm/default-java/jre/lib/rt.jar")) == true) { 172 result = _T("/usr/lib/jvm/default-java/jre"); 173 } 174 else { 175 result = _T(""); 176 } 177 } 178 } 179 } 180 181 return result; 182 } 183 184 TString LinuxPlatform::GetSystemJVMLibraryFileName() { 185 TString result; 186 TString jreHome = GetSystemJRE(); 187 188 if (jreHome.empty() == false && FilePath::DirectoryExists(jreHome) == true) { 189 result = FilePath::IncludeTrailingSeparater(jreHome) + 190 _T("/lib/"JAVAARCH"/client/libjvm.so"); 191 192 if (FilePath::FileExists(result) == false) { 193 result = FilePath::IncludeTrailingSeparater(jreHome) + 194 _T("/lib/"JAVAARCH"/server/libjvm.so"); 195 } 196 } 197 198 return result; 199 } 200 201 bool LinuxPlatform::IsMainThread() { 202 bool result = (FMainThread == pthread_self()); 203 return result; 204 } 205 206 const char* LinuxPlatform::getTmpDirString() { 207 return LINUX_PACKAGER_TMP_DIR; 208 } 209 210 void LinuxPlatform::reactivateAnotherInstance() { 211 if (singleInstanceProcessId == 0) { 212 printf("Unable to reactivate another instance, PID is undefined"); 213 return; 214 } 215 Display* dsp = XOpenDisplay(NULL); 216 ProcessReactivator processReactivator(dsp, singleInstanceProcessId); 217 processReactivator.reactivateProcess(); 218 XCloseDisplay(dsp); 219 } 220 221 TPlatformNumber LinuxPlatform::GetMemorySize() { 222 long pages = sysconf(_SC_PHYS_PAGES); 223 long page_size = sysconf(_SC_PAGE_SIZE); 224 TPlatformNumber result = pages * page_size; 225 result = result / 1048576; // Convert from bytes to megabytes. 226 return result; 227 } 228 229 #ifdef DEBUG 230 bool LinuxPlatform::IsNativeDebuggerPresent() { 231 // gdb opens file descriptors stdin=3, stdout=4, stderr=5 whereas 232 // a typical prog uses only stdin=0, stdout=1, stderr=2. 233 bool result = false; 234 FILE *fd = fopen("/tmp", "r"); 235 236 if (fileno(fd) > 5) { 237 result = true; 238 } 239 240 fclose(fd); 241 return result; 242 } 243 244 int LinuxPlatform::GetProcessID() { 245 int pid = getpid(); 246 return pid; 247 } 248 #endif //DEBUG 249 250 //-------------------------------------------------------------------------------------------------- 251 252 #ifndef __UNIX_DEPLOY_PLATFORM__ 253 #define __UNIX_DEPLOY_PLATFORM__ 254 255 /** Provide an abstraction for difference in the platform APIs, 256 e.g. string manipulation functions, etc. */ 257 #include <stdio.h> 258 #include <string.h> 259 #include <strings.h> 260 #include <sys/stat.h> 261 262 #define TCHAR char 263 264 #define _T(x) x 265 266 #define DEPLOY_MULTIBYTE_SNPRINTF snprintf 267 268 #define DEPLOY_SNPRINTF(buffer, sizeOfBuffer, count, format, ...) \ 269 snprintf((buffer), (count), (format), __VA_ARGS__) 270 271 #define DEPLOY_PRINTF(format, ...) \ 272 printf((format), ##__VA_ARGS__) 273 274 #define DEPLOY_FPRINTF(dest, format, ...) \ 275 fprintf((dest), (format), __VA_ARGS__) 276 277 #define DEPLOY_SSCANF(buf, format, ...) \ 278 sscanf((buf), (format), __VA_ARGS__) 279 280 #define DEPLOY_STRDUP(strSource) \ 281 strdup((strSource)) 282 283 //return "error code" (like on Windows) 284 static int DEPLOY_STRNCPY(char *strDest, size_t numberOfElements, const char *strSource, size_t count) { 285 char *s = strncpy(strDest, strSource, count); 286 // Duplicate behavior of the Windows' _tcsncpy_s() by adding a NULL 287 // terminator at the end of the string. 288 if (count < numberOfElements) { 289 s[count] = '\0'; 290 } else { 291 s[numberOfElements - 1] = '\0'; 292 } 293 return (s == strDest) ? 0 : 1; 294 } 295 296 static int DEPLOY_STRNCAT(char *strDest, size_t numberOfElements, const char *strSource, size_t count) { 297 // strncat always return null terminated string 298 char *s = strncat(strDest, strSource, count); 299 return (s == strDest) ? 0 : 1; 300 } 301 302 #define DEPLOY_STRICMP(x, y) \ 303 strcasecmp((x), (y)) 304 305 #define DEPLOY_STRNICMP(x, y, cnt) \ 306 strncasecmp((x), (y), (cnt)) 307 308 #define DEPLOY_STRNCMP(x, y, cnt) \ 309 strncmp((x), (y), (cnt)) 310 311 #define DEPLOY_STRLEN(x) \ 312 strlen((x)) 313 314 #define DEPLOY_STRSTR(x, y) \ 315 strstr((x), (y)) 316 317 #define DEPLOY_STRCHR(x, y) \ 318 strchr((x), (y)) 319 320 #define DEPLOY_STRRCHR(x, y) \ 321 strrchr((x), (y)) 322 323 #define DEPLOY_STRPBRK(x, y) \ 324 strpbrk((x), (y)) 325 326 #define DEPLOY_GETENV(x) \ 327 getenv((x)) 328 329 #define DEPLOY_PUTENV(x) \ 330 putenv((x)) 331 332 #define DEPLOY_STRCMP(x, y) \ 333 strcmp((x), (y)) 334 335 #define DEPLOY_STRCPY(x, y) \ 336 strcpy((x), (y)) 337 338 #define DEPLOY_STRCAT(x, y) \ 339 strcat((x), (y)) 340 341 #define DEPLOY_ATOI(x) \ 342 atoi((x)) 343 344 static int getFileSize(TCHAR* filename) { 345 struct stat statBuf; 346 if (stat(filename, &statBuf) == 0) { 347 return statBuf.st_size; 348 } 349 return -1; 350 } 351 352 #define DEPLOY_FILE_SIZE(filename) getFileSize(filename) 353 354 #define DEPLOY_FOPEN(x, y) \ 355 fopen((x), (y)) 356 357 #define DEPLOY_FGETS(x, y, z) \ 358 fgets((x), (y), (z)) 359 360 #define DEPLOY_REMOVE(x) \ 361 remove((x)) 362 363 #define DEPLOY_SPAWNV(mode, cmd, args) \ 364 spawnv((mode), (cmd), (args)) 365 366 #define DEPLOY_ISDIGIT(ch) isdigit(ch) 367 368 // for non-unicode, just return the input string for 369 // the following 2 conversions 370 #define DEPLOY_NEW_MULTIBYTE(message) message 371 372 #define DEPLOY_NEW_FROM_MULTIBYTE(message) message 373 374 // for non-unicode, no-op for the relase operation 375 // since there is no memory allocated for the 376 // string conversions 377 #define DEPLOY_RELEASE_MULTIBYTE(tmpMBCS) 378 379 #define DEPLOY_RELEASE_FROM_MULTIBYTE(tmpMBCS) 380 381 // The size will be used for converting from 1 byte to 1 byte encoding. 382 // Ensure have space for zero-terminator. 383 #define DEPLOY_GET_SIZE_FOR_ENCODING(message, theLength) (theLength + 1) 384 385 #endif 386 #define xmlTagType 0 387 #define xmlPCDataType 1 388 389 typedef struct _xmlNode XMLNode; 390 typedef struct _xmlAttribute XMLAttribute; 391 392 struct _xmlNode { 393 int _type; // Type of node: tag, pcdata, cdate 394 TCHAR* _name; // Contents of node 395 XMLNode* _next; // Next node at same level 396 XMLNode* _sub; // First sub-node 397 XMLAttribute* _attributes; // List of attributes 398 }; 399 400 struct _xmlAttribute { 401 TCHAR* _name; // Name of attribute 402 TCHAR* _value; // Value of attribute 403 XMLAttribute* _next; // Next attribute for this tag 404 }; 405 406 // Public interface 407 static void RemoveNonAsciiUTF8FromBuffer(char *buf); 408 XMLNode* ParseXMLDocument (TCHAR* buf); 409 void FreeXMLDocument (XMLNode* root); 410 411 // Utility methods for parsing document 412 XMLNode* FindXMLChild (XMLNode* root, const TCHAR* name); 413 TCHAR* FindXMLAttribute (XMLAttribute* attr, const TCHAR* name); 414 415 // Debugging 416 void PrintXMLDocument(XMLNode* node, int indt); 417 418 419 #include <sys/types.h> 420 #include <sys/stat.h> 421 #include <setjmp.h> 422 #include <stdlib.h> 423 #include <wctype.h> 424 425 426 #define JWS_assert(s, msg) \ 427 if (!(s)) { Abort(msg); } 428 429 430 // Internal declarations 431 static XMLNode* ParseXMLElement(void); 432 static XMLAttribute* ParseXMLAttribute(void); 433 static TCHAR* SkipWhiteSpace(TCHAR *p); 434 static TCHAR* SkipXMLName(TCHAR *p); 435 static TCHAR* SkipXMLComment(TCHAR *p); 436 static TCHAR* SkipXMLDocType(TCHAR *p); 437 static TCHAR* SkipXMLProlog(TCHAR *p); 438 static TCHAR* SkipPCData(TCHAR *p); 439 static int IsPCData(TCHAR *p); 440 static void ConvertBuiltInEntities(TCHAR* p); 441 static void SetToken(int type, TCHAR* start, TCHAR* end); 442 static void GetNextToken(void); 443 static XMLNode* CreateXMLNode(int type, TCHAR* name); 444 static XMLAttribute* CreateXMLAttribute(TCHAR *name, TCHAR* value); 445 static XMLNode* ParseXMLElement(void); 446 static XMLAttribute* ParseXMLAttribute(void); 447 static void FreeXMLAttribute(XMLAttribute* attr); 448 static void PrintXMLAttributes(XMLAttribute* attr); 449 static void indent(int indt); 450 451 static jmp_buf jmpbuf; 452 static XMLNode* root_node = NULL; 453 454 /** definition of error codes for setjmp/longjmp, 455 * that can be handled in ParseXMLDocument() 456 */ 457 #define JMP_NO_ERROR 0 458 #define JMP_OUT_OF_RANGE 1 459 460 #define NEXT_CHAR(p) {if (*p != 0) { p++;} else {longjmp(jmpbuf, JMP_OUT_OF_RANGE);}} 461 #define NEXT_CHAR_OR_BREAK(p) {if (*p != 0) { p++;} else {break;}} 462 #define NEXT_CHAR_OR_RETURN(p) {if (*p != 0) { p++;} else {return;}} 463 #define SKIP_CHARS(p,n) {int i; for (i = 0; i < (n); i++) \ 464 {if (*p != 0) { p++;} else \ 465 {longjmp(jmpbuf, JMP_OUT_OF_RANGE);}}} 466 #define SKIP_CHARS_OR_BREAK(p,n) {int i; for (i = 0; i < (n); i++) \ 467 {if (*p != 0) { p++;} else {break;}} \ 468 {if (i < (n)) {break;}}} 469 470 /** Iterates through the null-terminated buffer (i.e., C string) and replaces all 471 * UTF-8 encoded character >255 with 255 472 * 473 * UTF-8 encoding: 474 * 475 * Range A: 0x0000 - 0x007F 476 * 0 | bits 0 - 7 477 * Range B : 0x0080 - 0x07FF : 478 * 110 | bits 6 - 10 479 * 10 | bits 0 - 5 480 * Range C : 0x0800 - 0xFFFF : 481 * 1110 | bits 12-15 482 * 10 | bits 6-11 483 * 10 | bits 0-5 484 */ 485 static void RemoveNonAsciiUTF8FromBuffer(char *buf) { 486 char* p; 487 char* q; 488 char c; 489 p = q = buf; 490 /* We are not using NEXT_CHAR() to check if *q is NULL, as q is output location 491 and offset for q is smaller than for p. */ 492 while(*p != '\0') { 493 c = *p; 494 if ( (c & 0x80) == 0) { 495 /* Range A */ 496 *q++ = *p; 497 NEXT_CHAR(p); 498 } else if ((c & 0xE0) == 0xC0){ 499 /* Range B */ 500 *q++ = (char)0xFF; 501 NEXT_CHAR(p); 502 NEXT_CHAR_OR_BREAK(p); 503 } else { 504 /* Range C */ 505 *q++ = (char)0xFF; 506 NEXT_CHAR(p); 507 SKIP_CHARS_OR_BREAK(p, 2); 508 } 509 } 510 /* Null terminate string */ 511 *q = '\0'; 512 } 513 514 /* --------------------------------------------------------------------- */ 515 516 static TCHAR* SkipWhiteSpace(TCHAR *p) { 517 if (p != NULL) { 518 while(iswspace(*p)) 519 NEXT_CHAR_OR_BREAK(p); 520 } 521 return p; 522 } 523 524 static TCHAR* SkipXMLName(TCHAR *p) { 525 TCHAR c = *p; 526 /* Check if start of token */ 527 if ( ('a' <= c && c <= 'z') || 528 ('A' <= c && c <= 'Z') || 529 c == '_' || c == ':') { 530 531 while( ('a' <= c && c <= 'z') || 532 ('A' <= c && c <= 'Z') || 533 ('0' <= c && c <= '9') || 534 c == '_' || c == ':' || c == '.' || c == '-' ) { 535 NEXT_CHAR(p); 536 c = *p; 537 if (c == '\0') break; 538 } 539 } 540 return p; 541 } 542 543 static TCHAR* SkipXMLComment(TCHAR *p) { 544 if (p != NULL) { 545 if (DEPLOY_STRNCMP(p, _T("<!--"), 4) == 0) { 546 SKIP_CHARS(p, 4); 547 do { 548 if (DEPLOY_STRNCMP(p, _T("-->"), 3) == 0) { 549 SKIP_CHARS(p, 3); 550 return p; 551 } 552 NEXT_CHAR(p); 553 } while(*p != '\0'); 554 } 555 } 556 return p; 557 } 558 559 static TCHAR* SkipXMLDocType(TCHAR *p) { 560 if (p != NULL) { 561 if (DEPLOY_STRNCMP(p, _T("<!"), 2) == 0) { 562 SKIP_CHARS(p, 2); 563 while (*p != '\0') { 564 if (*p == '>') { 565 NEXT_CHAR(p); 566 return p; 567 } 568 NEXT_CHAR(p); 569 } 570 } 571 } 572 return p; 573 } 574 575 static TCHAR* SkipXMLProlog(TCHAR *p) { 576 if (p != NULL) { 577 if (DEPLOY_STRNCMP(p, _T("<?"), 2) == 0) { 578 SKIP_CHARS(p, 2); 579 do { 580 if (DEPLOY_STRNCMP(p, _T("?>"), 2) == 0) { 581 SKIP_CHARS(p, 2); 582 return p; 583 } 584 NEXT_CHAR(p); 585 } while(*p != '\0'); 586 } 587 } 588 return p; 589 } 590 591 /* Search for the built-in XML entities: 592 * & (&), < (<), > (>), ' ('), and "e(") 593 * and convert them to a real TCHARacter 594 */ 595 static void ConvertBuiltInEntities(TCHAR* p) { 596 TCHAR* q; 597 q = p; 598 /* We are not using NEXT_CHAR() to check if *q is NULL, as q is output location 599 and offset for q is smaller than for p. */ 600 while(*p) { 601 if (IsPCData(p)) { 602 /* dont convert &xxx values within PData */ 603 TCHAR *end; 604 end = SkipPCData(p); 605 while(p < end) { 606 *q++ = *p; 607 NEXT_CHAR(p); 608 } 609 } else { 610 if (DEPLOY_STRNCMP(p, _T("&"), 5) == 0) { 611 *q++ = '&'; 612 SKIP_CHARS(p, 5); 613 } else if (DEPLOY_STRNCMP(p, _T("<"), 4) == 0) { 614 *q = '<'; 615 SKIP_CHARS(p, 4); 616 } else if (DEPLOY_STRNCMP(p, _T(">"), 4) == 0) { 617 *q = '>'; 618 SKIP_CHARS(p, 4); 619 } else if (DEPLOY_STRNCMP(p, _T("'"), 6) == 0) { 620 *q = '\''; 621 SKIP_CHARS(p, 6); 622 } else if (DEPLOY_STRNCMP(p, _T(""e;"), 7) == 0) { 623 *q = '\"'; 624 SKIP_CHARS(p, 7); 625 } else { 626 *q++ = *p; 627 NEXT_CHAR(p); 628 } 629 } 630 } 631 *q = '\0'; 632 } 633 634 /* ------------------------------------------------------------- */ 635 /* XML tokenizer */ 636 637 #define TOKEN_UNKNOWN 0 638 #define TOKEN_BEGIN_TAG 1 /* <tag */ 639 #define TOKEN_END_TAG 2 /* </tag */ 640 #define TOKEN_CLOSE_BRACKET 3 /* > */ 641 #define TOKEN_EMPTY_CLOSE_BRACKET 4 /* /> */ 642 #define TOKEN_PCDATA 5 /* pcdata */ 643 #define TOKEN_CDATA 6 /* cdata */ 644 #define TOKEN_EOF 7 645 646 static TCHAR* CurPos = NULL; 647 static TCHAR* CurTokenName = NULL; 648 static int CurTokenType; 649 static int MaxTokenSize = -1; 650 651 /* Copy token from buffer to Token variable */ 652 static void SetToken(int type, TCHAR* start, TCHAR* end) { 653 int len = end - start; 654 if (len > MaxTokenSize) { 655 if (CurTokenName != NULL) free(CurTokenName); 656 CurTokenName = (TCHAR *)malloc((len + 1) * sizeof(TCHAR)); 657 if (CurTokenName == NULL ) { 658 return; 659 } 660 MaxTokenSize = len; 661 } 662 663 CurTokenType = type; 664 DEPLOY_STRNCPY(CurTokenName, len + 1, start, len); 665 CurTokenName[len] = '\0'; 666 } 667 668 /* Skip XML comments, doctypes, and prolog tags */ 669 static TCHAR* SkipFilling(void) { 670 TCHAR *q = CurPos; 671 672 /* Skip white space and comment sections */ 673 do { 674 q = CurPos; 675 CurPos = SkipWhiteSpace(CurPos); 676 CurPos = SkipXMLComment(CurPos); /* Must be called befor DocTypes */ 677 CurPos = SkipXMLDocType(CurPos); /* <! ... > directives */ 678 CurPos = SkipXMLProlog(CurPos); /* <? ... ?> directives */ 679 } while(CurPos != q); 680 681 return CurPos; 682 } 683 684 /* Parses next token and initializes the global token variables above 685 The tokennizer automatically skips comments (<!-- comment -->) and 686 <! ... > directives. 687 */ 688 static void GetNextToken(void) { 689 TCHAR *p, *q; 690 691 /* Skip white space and comment sections */ 692 p = SkipFilling(); 693 694 if (p == NULL || *p == '\0') { 695 CurTokenType = TOKEN_EOF; 696 return; 697 } else if (p[0] == '<' && p[1] == '/') { 698 /* TOKEN_END_TAG */ 699 q = SkipXMLName(p + 2); 700 SetToken(TOKEN_END_TAG, p + 2, q); 701 p = q; 702 } else if (*p == '<') { 703 /* TOKEN_BEGIN_TAG */ 704 q = SkipXMLName(p + 1); 705 SetToken(TOKEN_BEGIN_TAG, p + 1, q); 706 p = q; 707 } else if (p[0] == '>') { 708 CurTokenType = TOKEN_CLOSE_BRACKET; 709 NEXT_CHAR(p); 710 } else if (p[0] == '/' && p[1] == '>') { 711 CurTokenType = TOKEN_EMPTY_CLOSE_BRACKET; 712 SKIP_CHARS(p, 2); 713 } else { 714 /* Search for end of data */ 715 q = p + 1; 716 while(*q && *q != '<') { 717 if (IsPCData(q)) { 718 q = SkipPCData(q); 719 } else { 720 NEXT_CHAR(q); 721 } 722 } 723 SetToken(TOKEN_PCDATA, p, q); 724 /* Convert all entities inside token */ 725 ConvertBuiltInEntities(CurTokenName); 726 p = q; 727 } 728 /* Advance pointer to beginning of next token */ 729 CurPos = p; 730 } 731 732 static XMLNode* CreateXMLNode(int type, TCHAR* name) { 733 XMLNode* node; 734 node = (XMLNode*)malloc(sizeof(XMLNode)); 735 if (node == NULL) { 736 return NULL; 737 } 738 node->_type = type; 739 node->_name = name; 740 node->_next = NULL; 741 node->_sub = NULL; 742 node->_attributes = NULL; 743 return node; 744 } 745 746 static XMLAttribute* CreateXMLAttribute(TCHAR *name, TCHAR* value) { 747 XMLAttribute* attr; 748 attr = (XMLAttribute*)malloc(sizeof(XMLAttribute)); 749 if (attr == NULL) { 750 return NULL; 751 } 752 attr->_name = name; 753 attr->_value = value; 754 attr->_next = NULL; 755 return attr; 756 } 757 758 XMLNode* ParseXMLDocument(TCHAR* buf) { 759 XMLNode* root; 760 int err_code = setjmp(jmpbuf); 761 switch (err_code) 762 { 763 case JMP_NO_ERROR: 764 #ifndef _UNICODE 765 /* Remove UTF-8 encoding from buffer */ 766 RemoveNonAsciiUTF8FromBuffer(buf); 767 #endif 768 769 /* Get first Token */ 770 CurPos = buf; 771 GetNextToken(); 772 773 /* Parse document*/ 774 root = ParseXMLElement(); 775 break; 776 case JMP_OUT_OF_RANGE: 777 /* cleanup: */ 778 if (root_node != NULL) { 779 FreeXMLDocument(root_node); 780 root_node = NULL; 781 } 782 if (CurTokenName != NULL) free(CurTokenName); 783 fprintf(stderr,"Error during parsing jnlp file...\n"); 784 exit(-1); 785 break; 786 default: 787 root = NULL; 788 break; 789 } 790 791 return root; 792 } 793 794 static XMLNode* ParseXMLElement(void) { 795 XMLNode* node = NULL; 796 XMLNode* subnode = NULL; 797 XMLNode* nextnode = NULL; 798 XMLAttribute* attr = NULL; 799 800 if (CurTokenType == TOKEN_BEGIN_TAG) { 801 802 /* Create node for new element tag */ 803 node = CreateXMLNode(xmlTagType, DEPLOY_STRDUP(CurTokenName)); 804 /* We need to save root node pointer to be able to cleanup 805 if an error happens during parsing */ 806 if(!root_node) { 807 root_node = node; 808 } 809 /* Parse attributes. This section eats a all input until 810 EOF, a > or a /> */ 811 attr = ParseXMLAttribute(); 812 while(attr != NULL) { 813 attr->_next = node->_attributes; 814 node->_attributes = attr; 815 attr = ParseXMLAttribute(); 816 } 817 818 /* This will eihter be a TOKEN_EOF, TOKEN_CLOSE_BRACKET, or a 819 * TOKEN_EMPTY_CLOSE_BRACKET */ 820 GetNextToken(); 821 822 /* Skip until '>', '/>' or EOF. This should really be an error, */ 823 /* but we are loose */ 824 // if(CurTokenType == TOKEN_EMPTY_CLOSE_BRACKET || 825 // CurTokenType == TOKEN_CLOSE_BRACKET || 826 // CurTokenType == TOKEN_EOF) { 827 // println("XML Parsing error: wrong kind of token found"); 828 // return NULL; 829 // } 830 831 if (CurTokenType == TOKEN_EMPTY_CLOSE_BRACKET) { 832 GetNextToken(); 833 /* We are done with the sublevel - fall through to continue */ 834 /* parsing tags at the same level */ 835 } else if (CurTokenType == TOKEN_CLOSE_BRACKET) { 836 GetNextToken(); 837 838 /* Parse until end tag if found */ 839 node->_sub = ParseXMLElement(); 840 841 if (CurTokenType == TOKEN_END_TAG) { 842 /* Find closing bracket '>' for end tag */ 843 do { 844 GetNextToken(); 845 } while(CurTokenType != TOKEN_EOF && CurTokenType != TOKEN_CLOSE_BRACKET); 846 GetNextToken(); 847 } 848 } 849 850 /* Continue parsing rest on same level */ 851 if (CurTokenType != TOKEN_EOF) { 852 /* Parse rest of stream at same level */ 853 node->_next = ParseXMLElement(); 854 } 855 return node; 856 857 } else if (CurTokenType == TOKEN_PCDATA) { 858 /* Create node for pcdata */ 859 node = CreateXMLNode(xmlPCDataType, DEPLOY_STRDUP(CurTokenName)); 860 /* We need to save root node pointer to be able to cleanup 861 if an error happens during parsing */ 862 if(!root_node) { 863 root_node = node; 864 } 865 GetNextToken(); 866 return node; 867 } 868 869 /* Something went wrong. */ 870 return NULL; 871 } 872 873 /* Parses an XML attribute. */ 874 static XMLAttribute* ParseXMLAttribute(void) { 875 TCHAR* q = NULL; 876 TCHAR* name = NULL; 877 TCHAR* PrevPos = NULL; 878 879 do 880 { 881 /* We need to check this condition to avoid endless loop 882 in case if an error happend during parsing. */ 883 if (PrevPos == CurPos) { 884 if (name != NULL) { 885 free(name); 886 name = NULL; 887 } 888 889 return NULL; 890 } 891 892 PrevPos = CurPos; 893 894 /* Skip whitespace etc. */ 895 SkipFilling(); 896 897 /* Check if we are done witht this attribute section */ 898 if (CurPos[0] == '\0' || 899 CurPos[0] == '>' || 900 CurPos[0] == '/' && CurPos[1] == '>') { 901 902 if (name != NULL) { 903 free(name); 904 name = NULL; 905 } 906 907 return NULL; 908 } 909 910 /* Find end of name */ 911 q = CurPos; 912 while(*q && !iswspace(*q) && *q !='=') NEXT_CHAR(q); 913 914 SetToken(TOKEN_UNKNOWN, CurPos, q); 915 if (name) { 916 free(name); 917 name = NULL; 918 } 919 name = DEPLOY_STRDUP(CurTokenName); 920 921 /* Skip any whitespace */ 922 CurPos = q; 923 CurPos = SkipFilling(); 924 925 /* Next TCHARacter must be '=' for a valid attribute. 926 If it is not, this is really an error. 927 We ignore this, and just try to parse an attribute 928 out of the rest of the string. 929 */ 930 } while(*CurPos != '='); 931 932 NEXT_CHAR(CurPos); 933 CurPos = SkipWhiteSpace(CurPos); 934 /* Parse CDATA part of attribute */ 935 if ((*CurPos == '\"') || (*CurPos == '\'')) { 936 TCHAR quoteChar = *CurPos; 937 q = ++CurPos; 938 while(*q != '\0' && *q != quoteChar) NEXT_CHAR(q); 939 SetToken(TOKEN_CDATA, CurPos, q); 940 CurPos = q + 1; 941 } else { 942 q = CurPos; 943 while(*q != '\0' && !iswspace(*q)) NEXT_CHAR(q); 944 SetToken(TOKEN_CDATA, CurPos, q); 945 CurPos = q; 946 } 947 948 //Note: no need to free name and CurTokenName duplicate; they're assigned 949 // to an XMLAttribute structure in CreateXMLAttribute 950 951 return CreateXMLAttribute(name, DEPLOY_STRDUP(CurTokenName)); 952 } 953 954 void FreeXMLDocument(XMLNode* root) { 955 if (root == NULL) return; 956 FreeXMLDocument(root->_sub); 957 FreeXMLDocument(root->_next); 958 FreeXMLAttribute(root->_attributes); 959 free(root->_name); 960 free(root); 961 } 962 963 static void FreeXMLAttribute(XMLAttribute* attr) { 964 if (attr == NULL) return; 965 free(attr->_name); 966 free(attr->_value); 967 FreeXMLAttribute(attr->_next); 968 free(attr); 969 } 970 971 /* Find element at current level with a given name */ 972 XMLNode* FindXMLChild(XMLNode* root, const TCHAR* name) { 973 if (root == NULL) return NULL; 974 975 if (root->_type == xmlTagType && DEPLOY_STRCMP(root->_name, name) == 0) { 976 return root; 977 } 978 979 return FindXMLChild(root->_next, name); 980 } 981 982 /* Search for an attribute with the given name and returns the contents. Returns NULL if 983 * attribute is not found 984 */ 985 TCHAR* FindXMLAttribute(XMLAttribute* attr, const TCHAR* name) { 986 if (attr == NULL) return NULL; 987 if (DEPLOY_STRCMP(attr->_name, name) == 0) return attr->_value; 988 return FindXMLAttribute(attr->_next, name); 989 } 990 991 992 void PrintXMLDocument(XMLNode* node, int indt) { 993 if (node == NULL) return; 994 995 if (node->_type == xmlTagType) { 996 DEPLOY_PRINTF(_T("\n")); 997 indent(indt); 998 DEPLOY_PRINTF(_T("<%s"), node->_name); 999 PrintXMLAttributes(node->_attributes); 1000 if (node->_sub == NULL) { 1001 DEPLOY_PRINTF(_T("/>\n")); 1002 } else { 1003 DEPLOY_PRINTF(_T(">")); 1004 PrintXMLDocument(node->_sub, indt + 1); 1005 indent(indt); 1006 DEPLOY_PRINTF(_T("</%s>"), node->_name); 1007 } 1008 } else { 1009 DEPLOY_PRINTF(_T("%s"), node->_name); 1010 } 1011 PrintXMLDocument(node->_next, indt); 1012 } 1013 1014 static void PrintXMLAttributes(XMLAttribute* attr) { 1015 if (attr == NULL) return; 1016 1017 DEPLOY_PRINTF(_T(" %s=\"%s\""), attr->_name, attr->_value); 1018 PrintXMLAttributes(attr->_next); 1019 } 1020 1021 static void indent(int indt) { 1022 int i; 1023 for(i = 0; i < indt; i++) { 1024 DEPLOY_PRINTF(_T(" ")); 1025 } 1026 } 1027 1028 const TCHAR *CDStart = _T("<![CDATA["); 1029 const TCHAR *CDEnd = _T("]]>"); 1030 1031 1032 static TCHAR* SkipPCData(TCHAR *p) { 1033 TCHAR *end = DEPLOY_STRSTR(p, CDEnd); 1034 if (end != NULL) { 1035 return end+sizeof(CDEnd); 1036 } 1037 return (++p); 1038 } 1039 1040 static int IsPCData(TCHAR *p) { 1041 return (DEPLOY_STRNCMP(CDStart, p, sizeof(CDStart)) == 0); 1042 } 1043 1044 //-------------------------------------------------------------------------------------------------- 1045 1046 LinuxJavaUserPreferences::LinuxJavaUserPreferences(void) : JavaUserPreferences() { 1047 } 1048 1049 LinuxJavaUserPreferences::~LinuxJavaUserPreferences(void) { 1050 } 1051 1052 TString LinuxJavaUserPreferences::GetUserPrefFileName(TString Appid) { 1053 TString result; 1054 struct passwd *pw = getpwuid(getuid()); 1055 TString homedir = pw->pw_dir; 1056 TString userOverrideFileName = FilePath::IncludeTrailingSeparater(homedir) + 1057 FilePath::IncludeTrailingSeparater(_T(".java/.userPrefs")) + 1058 FilePath::IncludeTrailingSeparater(Appid) + 1059 _T("JVMUserOptions/prefs.xml"); 1060 1061 if (FilePath::FileExists(userOverrideFileName) == true) { 1062 result = userOverrideFileName; 1063 } 1064 1065 return result; 1066 } 1067 1068 OrderedMap<TString, TString> ReadNode(XMLNode* node) { 1069 OrderedMap<TString, TString> result; 1070 XMLNode* keyNode = FindXMLChild(node->_sub, _T("entry")); 1071 1072 while (keyNode != NULL) { 1073 TString key = FindXMLAttribute(keyNode->_attributes, _T("key")); 1074 TString value = FindXMLAttribute(keyNode->_attributes, _T("value")); 1075 keyNode = keyNode->_next; 1076 1077 if (key.empty() == false) { 1078 result.Append(key, value); 1079 } 1080 } 1081 1082 return result; 1083 } 1084 1085 OrderedMap<TString, TString> GetJvmUserArgs(TString filename) { 1086 OrderedMap<TString, TString> result; 1087 1088 if (FilePath::FileExists(filename) == true) { 1089 //scan file for the key 1090 FILE* fp = fopen(PlatformString(filename).toPlatformString(), "r"); 1091 1092 if (fp != NULL) { 1093 fseek(fp, 0, SEEK_END); 1094 long fsize = ftell(fp); 1095 rewind(fp); 1096 DynamicBuffer<char> buffer(fsize + 1); 1097 fread(buffer.GetData(), fsize, 1, fp); 1098 fclose(fp); 1099 buffer[fsize] = 0; 1100 1101 XMLNode* node = NULL; 1102 XMLNode* doc = ParseXMLDocument(buffer.GetData()); 1103 1104 if (doc != NULL) { 1105 node = FindXMLChild(doc, _T("map")); 1106 1107 if (node != NULL) { 1108 result = ReadNode(node); 1109 } 1110 } 1111 } 1112 } 1113 1114 return result; 1115 } 1116 1117 bool LinuxJavaUserPreferences::Load(TString Appid) { 1118 bool result = false; 1119 TString filename = GetUserPrefFileName(Appid); 1120 1121 if (FilePath::FileExists(filename) == true) { 1122 FMap = GetJvmUserArgs(filename); 1123 result = true; 1124 } 1125 1126 return result; 1127 } 1128 1129 ProcessReactivator::ProcessReactivator(Display* display, pid_t pid): 1130 _pid(pid), _display(display) { 1131 1132 _atomPid = XInternAtom(display, "_NET_WM_PID", True); 1133 1134 if (_atomPid == None) { 1135 return; 1136 } 1137 searchWindowHelper(XDefaultRootWindow(display)); 1138 } 1139 1140 void ProcessReactivator::searchWindowHelper(Window w) { 1141 Atom type; 1142 int format; 1143 unsigned long num, bytesAfter; 1144 unsigned char* propPid = 0; 1145 if (Success == XGetWindowProperty(_display, w, _atomPid, 0, 1, False, XA_CARDINAL, 1146 &type, &format, &num, &bytesAfter, &propPid)) { 1147 if (propPid != 0) { 1148 if (_pid == *((pid_t *)propPid)) { 1149 _result.push_back(w); 1150 } 1151 XFree(propPid); 1152 } 1153 } 1154 1155 Window root, parent; 1156 Window* child; 1157 unsigned int numChildren; 1158 if (0 != XQueryTree(_display, w, &root, &parent, &child, &numChildren)) { 1159 for (unsigned int i = 0; i < numChildren; i++) { 1160 searchWindowHelper(child[i]); 1161 } 1162 } 1163 } 1164 1165 void ProcessReactivator::reactivateProcess() { 1166 for (std::list<Window>::const_iterator it = _result.begin(); it != _result.end(); it++) { 1167 // try sending an event to activate window, 1168 // after that we can try to raise it. 1169 XEvent xev; 1170 Atom atom = XInternAtom (_display, "_NET_ACTIVE_WINDOW", False); 1171 xev.xclient.type = ClientMessage; 1172 xev.xclient.serial = 0; 1173 xev.xclient.send_event = True; 1174 xev.xclient.display = _display; 1175 xev.xclient.window = *it; 1176 xev.xclient.message_type = atom; 1177 xev.xclient.format = 32; 1178 xev.xclient.data.l[0] = 2; 1179 xev.xclient.data.l[1] = 0; 1180 xev.xclient.data.l[2] = 0; 1181 xev.xclient.data.l[3] = 0; 1182 xev.xclient.data.l[4] = 0; 1183 XWindowAttributes attr; 1184 XGetWindowAttributes(_display, *it, &attr); 1185 XSendEvent(_display, attr.root, False, 1186 SubstructureRedirectMask | SubstructureNotifyMask, &xev); 1187 XRaiseWindow(_display, *it); 1188 } 1189 } 1190 1191 //-------------------------------------------------------------------------------------------------- 1192 1193 #endif // LINUX