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