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