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