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