1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #ifndef _GLASS_UTILS_
  27 #define _GLASS_UTILS_
  28 
  29 #ifndef _WIN32_WINNT
  30 #   error The header should not be included directly. Do #include "common.h" instead.
  31 #endif
  32 
  33 #ifndef USER_TIMER_MINIMUM
  34 #define USER_TIMER_MINIMUM 0x0000000A
  35 #define USER_TIMER_MAXIMUM 0x7FFFFFFF
  36 #endif
  37 
  38 #if defined(DEBUG) || defined(_DEBUG)
  39 #define ASSERT(condition)   \
  40         if (!(condition)) { \
  41             fprintf(stderr, "ERROR: %s (%s, %s, line %d)\n",    \
  42                 #condition, __FUNCTION__, __FILE__, __LINE__);  \
  43             fflush(stderr); \
  44             ::DebugBreak(); \
  45         }
  46 #else
  47 #define ASSERT(condition)
  48 #endif
  49 
  50 #ifdef _WIN64
  51 #define jlong_to_ptr(a) ((void*)(a))
  52 #define ptr_to_jlong(a) ((jlong)(a))
  53 #else
  54 #define jlong_to_ptr(a) ((void*)(int)(a))
  55 #define ptr_to_jlong(a) ((jlong)(int)(a))
  56 #endif
  57 
  58 #define jbool_to_bool(a) (((a) == JNI_TRUE) ? TRUE : FALSE)
  59 #define bool_to_jbool(a) ((a) ? JNI_TRUE : JNI_FALSE)
  60 
  61 #define IS_WINVER_ATLEAST(maj, min) \
  62                           (LOBYTE(LOWORD(::GetVersion())) >  (maj) || \
  63                            LOBYTE(LOWORD(::GetVersion())) == (maj) && \
  64                            HIBYTE(LOWORD(::GetVersion())) >= (min))
  65 #define IS_WINXP IS_WINVER_ATLEAST(5, 1)
  66 #define IS_WINVISTA IS_WINVER_ATLEAST(6, 0)
  67 #define IS_WIN7 IS_WINVER_ATLEAST(6, 1)
  68 
  69 #if defined(DEBUG) || defined(_DEBUG)
  70 #define LOG(msg, ...) do { printf(msg, __VA_ARGS__); } while (0)
  71 #else
  72 #define LOG(msg, ...) do { } while (0)
  73 #endif
  74 
  75 ///////////////////////////////////////////////////////////
  76 // Java helper routines
  77 ///////////////////////////////////////////////////////////
  78 
  79 JavaVM* GetJVM();
  80 JNIEnv* GetEnv();
  81 
  82 // Returns JNI_TRUE if there are exceptions
  83 jboolean CheckAndClearException(JNIEnv *env);
  84 
  85 jint GetModifiers();
  86 
  87 class JString {
  88 public:
  89     JString(JNIEnv *env, jstring jString) {
  90         init(env, jString, true);
  91     }
  92     JString(JNIEnv *env, jstring jString, bool autoDelete) {
  93         init(env, jString, autoDelete);
  94     }
  95 
  96     ~JString() {
  97         if (m_wszStr && m_autoDelete) {
  98             delete[] m_wszStr;
  99         }
 100     }
 101 
 102     operator wchar_t*() { return m_wszStr; }
 103 
 104     int length() { return m_len; }
 105 
 106 private:
 107     void init(JNIEnv *env, jstring jString, bool autoDelete) {
 108         m_len = env->GetStringLength(jString);
 109         m_wszStr = new wchar_t[m_len + 1];
 110         env->GetStringRegion(jString, 0, m_len, (jchar *)m_wszStr);
 111         m_wszStr[m_len] = L'\0';
 112         m_autoDelete = autoDelete;
 113     }
 114 
 115     wchar_t *m_wszStr;
 116     int m_len;
 117     bool m_autoDelete;
 118 };
 119 
 120 // DNT == double null terminated
 121 class DNTString {
 122 public:
 123     DNTString(int limit) :
 124        m_limit(limit), m_length(0), m_substrings(NULL), m_count(0)
 125     {
 126         wszStr = new wchar_t[limit];
 127         memset(wszStr, 0, limit*sizeof(wchar_t));
 128     }
 129     ~DNTString() {
 130         if (wszStr) {
 131             delete[] wszStr;
 132         }
 133         if (m_substrings) {
 134             delete[] m_substrings;
 135         }
 136     }
 137 
 138     operator wchar_t*() { return wszStr; }
 139 
 140     size_t length() { return m_length; }
 141 
 142     size_t limit() { return m_limit; }
 143 
 144     void setLimit(size_t limit, bool copy = false) {
 145         wchar_t * const oldStr = wszStr;
 146         const size_t oldLimit = m_limit;
 147 
 148         m_limit = limit;
 149         wszStr = new wchar_t[limit];
 150         memset(wszStr, 0, limit*sizeof(wchar_t));
 151 
 152         if (copy && oldStr) {
 153             wmemcpy_s(wszStr, m_limit - 1, oldStr, min(oldLimit - 1, m_limit - 1));
 154             m_length = min(m_length, m_limit - 2);
 155         }
 156 
 157         if (oldStr) {
 158             delete[] oldStr;
 159         }
 160     }
 161 
 162     UINT count() {
 163         calculateSubstrings();
 164         return m_count;
 165     }
 166 
 167     wchar_t* substring(UINT i) {
 168         calculateSubstrings();
 169         return wszStr+m_substrings[i];
 170     }
 171 
 172     // appends the count characters of the src string to the DNT string
 173     void append(const wchar_t *wszSrc, const size_t count, bool allowGrow = false) {
 174         if (allowGrow) {
 175             if (m_length + count > m_limit - 2) {
 176                 const size_t GROWTH_RATE = 2; // consider parameterizing this const
 177 
 178                 setLimit((m_length + count + 2)*GROWTH_RATE, true);
 179             }
 180         }
 181 
 182         // "-1" because this is a _double_ null terminated string
 183         wcsncpy_s(wszStr + m_length, m_limit - m_length - 1, wszSrc, count);
 184         m_length += count; 
 185         if (m_length > m_limit) {
 186             m_length = m_limit;
 187         }
 188     }
 189 
 190     // recalculates the length of the DNT string
 191     // use the function when wszStr could be modified directly
 192     void calculateLength() {
 193         size_t i = 0;
 194         while(wszStr[i] != L'\0' || wszStr[i+1] != L'\0') {
 195             i++;
 196             if (i>= m_limit-1) {
 197                 i = m_limit;
 198                 break;
 199             }
 200         }
 201         m_length = i;
 202     }
 203 
 204 private:
 205 
 206     void calculateSubstrings() {
 207         if (m_substrings)
 208             return;
 209 
 210         wchar_t prevChar = '\0';
 211         for (size_t i = 0; i < m_length; i++) {
 212             if (prevChar == '\0' && wszStr[i] != '\0') { // new substring
 213                 m_count++;
 214             }
 215             prevChar = wszStr[i];
 216         }
 217 
 218         m_substrings = new size_t[m_count];
 219         m_count = 0;
 220         prevChar = '\0';
 221         for (size_t i = 0; i < m_length; i++) {
 222             if (prevChar == '\0' && wszStr[i] != '\0') { // new substring
 223                 m_substrings[m_count] = i;
 224                 m_count++;
 225             }
 226             prevChar = wszStr[i];
 227         }
 228     }
 229 
 230     wchar_t *wszStr;
 231     size_t m_length, m_limit;
 232 
 233     size_t *m_substrings;
 234     UINT m_count; // the count of the substrings
 235 };
 236 
 237 inline jstring CreateJString(JNIEnv *env, const wchar_t *wszStr) {
 238     if (wszStr == NULL)
 239         return NULL;
 240     jstring jStr = env->NewString((const jchar *)wszStr, jsize(wcslen(wszStr)));
 241     if (CheckAndClearException(env)) return NULL;
 242     return jStr;
 243 }
 244 
 245 inline jstring CreateJString(JNIEnv *env, const char *szStr) {
 246     if (szStr == NULL)
 247         return NULL;
 248     jstring jStr = env->NewStringUTF(szStr);
 249     if (CheckAndClearException(env)) return NULL;
 250     return jStr;
 251 }
 252 
 253 inline jstring ConcatJStrings(JNIEnv *env, jstring str1, jstring str2) {
 254     if (str1 == NULL || str2 == NULL)
 255         return NULL;
 256     jclass cls = env->FindClass("java/lang/String");
 257     if (CheckAndClearException(env)) {
 258         return NULL;
 259     }
 260     jmethodID mid = env->GetMethodID(cls, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
 261     if (CheckAndClearException(env)) return NULL;
 262     jstring ret = (jstring)env->CallObjectMethod(str1, mid, str2);
 263     CheckAndClearException(env);
 264 
 265     return ret;
 266 }
 267 
 268 template <class T>
 269 class JLocalRef {
 270     JNIEnv* m_env;
 271     T m_localJRef;
 272 
 273 public:
 274     JLocalRef(JNIEnv* env, T localJRef = NULL)
 275         : m_env(env),
 276         m_localJRef(localJRef)
 277     {}
 278     T Detach() {
 279         T ret = m_localJRef;
 280         m_localJRef = NULL;
 281         return ret;
 282     }
 283     void Attach(T newValue) {
 284         if (m_localJRef) {
 285             m_env->DeleteLocalRef((jobject)m_localJRef);
 286         }
 287         m_localJRef = newValue;
 288     }
 289 
 290     operator T() { return m_localJRef; }
 291     operator bool() { return NULL!=m_localJRef; }
 292     bool operator !() { return NULL==m_localJRef; }
 293 
 294     ~JLocalRef() {
 295         if (m_localJRef) {
 296             m_env->DeleteLocalRef((jobject)m_localJRef);
 297         }
 298     }
 299 };
 300 
 301 template <class T>
 302 class JGlobalRef {
 303     T m_globalJRef;
 304 
 305 public:
 306     JGlobalRef() : m_globalJRef(NULL) {}
 307 
 308     JGlobalRef(T o) : m_globalJRef(NULL) // make sure it's NULL initially
 309     {
 310         Attach(GetEnv(), o);
 311     }
 312 
 313     void Attach(JNIEnv* env, T localJRef){
 314         if (m_globalJRef) {
 315             env->DeleteGlobalRef((jobject)m_globalJRef);
 316         }
 317         m_globalJRef = (T)(localJRef 
 318             ? env->NewGlobalRef((jobject)localJRef)
 319             : NULL);
 320     }
 321 
 322     JGlobalRef<T>& operator = (T localRef)
 323     {
 324         Attach(GetEnv(), localRef);
 325         return *this;
 326     }
 327 
 328     operator T() { return m_globalJRef; }
 329     operator bool() { return NULL!=m_globalJRef; }
 330     bool operator !() { return NULL==m_globalJRef; }
 331 
 332     ~JGlobalRef() {
 333         if (m_globalJRef) {
 334             GetEnv()->DeleteGlobalRef((jobject)m_globalJRef);
 335         }
 336     }
 337 };
 338 
 339 
 340 template <class T>
 341 class MemHolder
 342 {
 343 public:
 344     MemHolder(size_t count)
 345     {
 346         m_pMem = reinterpret_cast<T *>(0==count
 347             ? NULL
 348             : malloc(count*sizeof(T)));
 349     }
 350     ~MemHolder(){
 351         free(m_pMem);
 352     }
 353 
 354     MemHolder& operator = (MemHolder &r)
 355     {
 356         if(this != &r){
 357             m_pMem = r.m_pMem;
 358             r.m_pMem = NULL;
 359         }
 360         return *this;
 361     }
 362 
 363     inline T *get()          { return m_pMem;  }
 364     inline operator T *()    { return m_pMem;  }
 365     inline operator bool()   { return NULL!=m_pMem;}
 366     inline bool operator !() { return NULL==m_pMem;}
 367 private:
 368     T *m_pMem;
 369 };
 370 
 371 typedef JLocalRef<jobject> JLObject;
 372 typedef JLocalRef<jstring> JLString;
 373 typedef JLocalRef<jclass>  JLClass;
 374 typedef JLocalRef<jobjectArray>  JLObjectArray;
 375 
 376 template <class T>
 377 class JArray {
 378     public:
 379         JArray() : data(NULL) {}
 380         ~JArray()
 381         {
 382             if (data) {
 383                 GetEnv()->ReleasePrimitiveArrayCritical(array, data, JNI_ABORT);
 384             }
 385         }
 386 
 387         void Attach(JNIEnv *env, jarray a)
 388         {
 389             array.Attach(env, a);
 390         }
 391 
 392         T* GetPtr()
 393         {
 394             if (!data && array) {
 395                 data = (T*)GetEnv()->GetPrimitiveArrayCritical(array, NULL);
 396             }
 397             return data;
 398         }
 399 
 400         operator bool() { return array; }
 401     private:
 402         JGlobalRef<jarray> array;
 403         T * data;
 404 };
 405 
 406 template <class T>
 407 class JBufferArray {
 408     public:
 409         JBufferArray() : data(NULL), offset(0) {}
 410 
 411         void Attach(JNIEnv *env, jobject buf, jarray arr, jint offs)
 412         {
 413             if (!arr) {
 414                 data = (T*)env->GetDirectBufferAddress(buf);
 415             } else {
 416                 array.Attach(env, arr);
 417                 offset = offs;
 418             }
 419         }
 420 
 421         T* GetPtr()
 422         {
 423             if (!data && array) {
 424                 data = array.GetPtr();
 425                 data += offset;
 426             }
 427             return data;
 428         }
 429 
 430         operator bool() { return data || array; }
 431 
 432     private:
 433         T* data;
 434         JArray<T> array;
 435         jint offset;
 436 };
 437 
 438 typedef struct _tagJavaIDs {
 439     struct {
 440         jmethodID notifyFocus;
 441         jmethodID notifyFocusDisabled;
 442         jmethodID notifyFocusUngrab;
 443         jmethodID notifyDestroy;
 444         jmethodID notifyDelegatePtr;
 445     } Window;
 446     struct {
 447         jmethodID notifyResize;
 448         jmethodID notifyRepaint;
 449         jmethodID notifyKey;
 450         jmethodID notifyMouse;
 451         jmethodID notifyMenu;
 452         jmethodID notifyScroll;
 453         jmethodID notifyInputMethod;
 454         jmethodID notifyInputMethodCandidatePosRequest;
 455 
 456         jmethodID notifyDragEnter;
 457         jmethodID notifyDragOver;
 458         jmethodID notifyDragLeave;
 459         jmethodID notifyDragDrop;
 460 
 461         jmethodID notifyView;
 462 
 463         jmethodID getWidth;
 464         jmethodID getHeight;
 465         jmethodID getAccessible;
 466 
 467         jfieldID  ptr;
 468     } View;
 469     struct {
 470         jmethodID init;
 471     } Size;
 472     struct {
 473         jmethodID attachData;
 474     } Pixels;
 475     struct {
 476         jmethodID getType;
 477         jmethodID getNativeCursor;
 478     } Cursor;
 479     struct {
 480         struct {
 481             jmethodID getDescription;
 482             jmethodID extensionsToArray;
 483         } ExtensionFilter;
 484         jmethodID createFileChooserResult;
 485     } CommonDialogs;
 486     struct {
 487         jmethodID run;
 488     } Runnable; 
 489     struct {
 490         jmethodID add;
 491     } List;
 492     struct {
 493         jmethodID gesturePerformedMID;
 494         jmethodID inertiaGestureFinishedMID;
 495         jmethodID notifyBeginTouchEventMID;
 496         jmethodID notifyNextTouchEventMID;
 497         jmethodID notifyEndTouchEventMID;
 498     } Gestures;
 499     struct {
 500         jmethodID init;
 501         jmethodID notifySettingsChanged;
 502     } Screen;
 503     struct {
 504         jmethodID reportExceptionMID;
 505         jmethodID notifyThemeChangedMID;
 506     } Application;
 507 } JavaIDs;
 508 
 509 extern JavaIDs javaIDs;
 510 
 511 
 512 #endif //_GLASS_UTILS_
 513