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