/** * Destroys thread local variables, sets exit event and dereferences * the thread handle. */ STATIC void THREAD_Cleanup(ThrData* thr) { /* invoke destructors for thread local variables */ int i, n = 1; for (i=0; i<MAX_DESTRUCTOR_ITERATIONS && n > 0; i++) { int k; n = 0; for (k=0; k<VECTOR_Size(&thr->cleanupList); k++) { ThrKey key = VECTOR_Get(&thr->cleanupList, k); void * value = TlsGetValue(key->index); if (value) { TlsSetValue(key->index, NULL); #ifdef _USE_EXCEPTION_HANDLING __try { #endif /* _USE_EXCEPTION_HANDLING */ key->clean(value); ASSERT(!TlsGetValue(key->index)); #ifdef _USE_EXCEPTION_HANDLING } __except(EXCEPTION_EXECUTE_HANDLER) { TlsSetValue(key->index,NULL); ASSMSG1("EXCEPTION %08lX in cleanup proc!", GetExceptionCode()); } #endif /* _USE_EXCEPTION_HANDLING */ n++; } } } ASSERT(i<MAX_DESTRUCTOR_ITERATIONS); /* Dereference ThrKey structures */ while ((n = VECTOR_Size(&thr->cleanupList)) > 0) { ThrKey key = VECTOR_Remove(&thr->cleanupList, n-1); if (InterlockedDecrement(&key->ref) == 0) { ASSERT(key->index == TLS_OUT_OF_INDEXES); MEM_Free(key); } } InterlockedDecrement(&WIN32_ThreadCount); VECTOR_Destroy(&thr->cleanupList); EVENT_Set(&thr->exitEvent); THREAD_Deref(thr); }
STATIC void EXPAT_StartElement(void * ctx, XML_Str tag, XML_Str * atts) { ExpatContext * expat = (ExpatContext *)ctx; if (expat->cb.startElem) { XMLAttr aset; XML_Str * s = atts; BUFFER_Clear(&expat->buf); VECTOR_Clear(&expat->atts); while (*s) { Char tmp; const XML_Char * c = (*s); /* * store offset in the vector - later will be replaces with the * pointer. Cannot store the pointers now because buffer may be * reallocated during conversion. */ int off = BUFFER_Size(&expat->buf)/sizeof(Char); VECTOR_Add(&expat->atts,(VElement)(PtrWord)off); /* * Pretty naive convertion of attribute names and values from * XML_Str to Str. This part may need some improvement... */ while (*c) { tmp = (Char)*c; BUFFER_Put(&expat->buf, &tmp, sizeof(tmp), False); c++; } tmp = 0; BUFFER_Put(&expat->buf, &tmp, sizeof(tmp), False); s++; } ASSERT(!(VECTOR_Size(&expat->atts)%2)); aset.storage = (Char*)BUFFER_Access(&expat->buf); aset.size = BUFFER_Size(&expat->buf); aset.off = (int*)VECTOR_GetElements(&expat->atts); aset.n = VECTOR_Size(&expat->atts)/2; EXPAT_ConvertTag(&expat->sb, tag); (*expat->cb.startElem)(expat->ctx, STRBUF_Text(&expat->sb), &aset); } }
/* * XML_Handle parses well-formed XML stream returning the root tag context * on success, NULL on failure. The endTag callback provided by the root tag * handler can be used to deallocate the root tag can context without any * side effects. However, in order to extract any useful information from the * root tag context, each object providing root tag handler would normally * provide a function that would exract such information from the root tag * (and deallocate everything else). * * The last parameter is a context parameter passed to the root tag callback * as the first argument. The code calling XML_Handle or the XMLHandleRoot * callback directly must know that XMLHandleRoot expects as a context * parameter. Typically, this is not a problem, but the use of this parameter * is discouraged. The XML stream should be self-sufficient, i.e. it should * contain all the information necessary to completely parse it. The context * parameter exists primarily to support for legacy XML file formats that * require extra parsing information in addition to the information contained * in the XML stream itself. */ XMLTag * XML_Handle(File * f, Str tag, XMLHandleRoot root, void * ctx) { XMLTag * rootTag = NULL; XMLContext context; memset(&context, 0, sizeof(context)); context.rootTagName = tag; context.rootHandler = root; context.rootContext = ctx; if (VECTOR_Init(&context.stack, 0, NULL, XML_VectorFreeTagContext)) { XMLCallbacks cb; memset(&cb, 0, sizeof(cb)); cb.startElem = XML_HandleStartElem; cb.endElem = XML_HandleEndElem; cb.charData = XML_HandleCharData; if (!XML_ParseStream(f, &cb, &context)) { context.error = True; } if (!context.error) { rootTag = context.rootTag; } else if (context.rootTag) { if (context.rootTag->endTag) { context.rootTag->endTag(context.rootTag, NULL); } else { MEM_Free(context.rootTag); } } /* * VECTOR_Destroy would destroy the elements starting with the * first element. We must start with the last element, which is * a natural cleanup order for a stack. If parsing was successful, * the vector is already empty. However, if parsing failed, the * vector may be non-empty and the order in which we deallocate the * tags must be opposite to the order in which they were created. */ while (!VECTOR_IsEmpty(&context.stack)) { VECTOR_Remove(&context.stack, VECTOR_Size(&context.stack)-1); } VECTOR_Destroy(&context.stack); } return rootTag; }
/** * Character handler for XML_Handle. Passes the data to the current * element handler. */ STATIC void XML_HandleCharData(void * ctx, const wchar_t * s, int len) { XMLContext * context = (XMLContext*)ctx; int depth = VECTOR_Size(&context->stack); ASSERT(depth > 0); if (depth > 0 && !context->error) { XMLTagCtx * tagContext; tagContext = (XMLTagCtx*)VECTOR_Get(&context->stack,depth-1); ASSERT(tagContext && tagContext->context == context); /* * if the handler does not expect any character data, we ignore those * characters, although it might be considered an error... */ if (tagContext->tag->handleChars) { if (!tagContext->tag->handleChars(tagContext->tag, s, len)) { context->error = True; } } } }
/** * "End element" callback for XML_Handle. If this tag has been "skipped" by * XML_StartElemCB, simply decrements skipDepth. Otherwise, calls the client * callback to deallocate the tag context. */ STATIC void XML_HandleEndElem(void * ctx, Str tag) { XMLContext * context = (XMLContext*)ctx; UNREF(tag); if (context->error && context->skipDepth > 0) { context->skipDepth--; } else { int depth = VECTOR_Size(&context->stack); ASSERT(depth > 0); if (depth == 1 && !context->error) { XMLTagCtx * root; root = (XMLTagCtx*)VECTOR_Get(&context->stack,0); ASSERT(root && root->context == context); ASSERT(!context->rootTag); /* prevent XML_VectorFreeTagContext from deallocating the tag */ context->rootTag = root->tag; root->tag = NULL; } if (depth > 0) { VECTOR_Remove(&context->stack, depth-1); } } }
/** * This does essentially the same as JVM_Find2, only additional directories * are passed in as a variable list of strings. The list of directories * must be NULL terminated, for example: * * JVM_FindVa("../lib/jre", NULL); */ JVMSet * JVM_FindVa(Str dir1, ...) { if (!dir1) { return JVM_Find2(NULL, 0); } else { JVMSet* jvms; Str arg = dir1; va_list va; Vector dirs; VECTOR_Init(&dirs, 0, NULL, NULL); va_start(va, dir1); while (arg) { if (!VECTOR_Add(&dirs, arg)) { VECTOR_Destroy(&dirs); return NULL; } arg = va_arg(va, Str); } va_end(va); jvms = JVM_Find2((Str*)VECTOR_GetElements(&dirs), VECTOR_Size(&dirs)); VECTOR_Destroy(&dirs); return jvms; } }
/** * "Start element" callback for XML_Handle. Creates new entry in the element * stack. If an error has occured, simply increments skipDepth */ STATIC void XML_HandleStartElem(void * ctx, Str tag, const XMLAttr * a) { XMLContext * context = (XMLContext*)ctx; if (context->error) { context->skipDepth++; } else { XMLTag * t = NULL; int depth = VECTOR_Size(&context->stack); if (!depth) { /* this is a root element */ if (!context->rootTagName || !StrCmp(tag, context->rootTagName)) { /* we don't expect more than one root tag */ ASSERT(!context->rootTag); if (!context->rootTag) { t = context->rootHandler(context->rootContext, tag, a); } } else { Warning(TEXT("WARNING: invalid root tag <%s>, expected <%s>\n"), tag, context->rootTagName); } } else { XMLTagCtx * parent; parent = (XMLTagCtx*)VECTOR_Get(&context->stack, depth-1); ASSERT(parent && parent->tag && parent->context == context); /* * if tag handler is NULL, it means that the handler for the * parent tag didn't expect any inner tags; we treat this as * an error */ if (parent->tag->handleTag) { t = parent->tag->handleTag(parent->tag, tag, a); } } if (t) { /* add new tag to the stack */ XMLTagCtx * tagContext = MEM_New(XMLTagCtx); XMLTag * p = NULL; if (depth > 0) { p = ((XMLTagCtx*)VECTOR_Get(&context->stack,depth-1))->tag; } if (tagContext) { memset(tagContext, 0, sizeof(*tagContext)); tagContext->context = context; tagContext->tag = t; tagContext->parent = p; if (VECTOR_Add(&context->stack, tagContext)) { return; } MEM_Free(tagContext); } XML_FreeTag(t, p); } /* handle error */ context->error = True; context->skipDepth++; } }
/** * Returns the number of discovered JVMs. The return value is always > 0 */ int JVM_GetCount(const JVMSet * jvms) { return VECTOR_Size(&jvms->found); }
/** * Discovers all available JVMs. If no JVMs are discovered, returns NULL. * In addition to the standard directories, also looks in the additional * directories specified by the dirs array. Note that this directory list * replaces the default list ("jre","../jre") used by JVM_Find, it does not * adds new directories to the list. */ JVMSet * JVM_Find2(const Str dirs[], int n) { JVMSet * jvms = MEM_New(JVMSet); if (jvms) { memset(jvms, 0, sizeof(*jvms)); if (VECTOR_Init(&jvms->found, 0, JVM_VectorEquals, JVM_VectorFree)) { /* Look for JVMs in the Windows registry */ JVM_Discover(jvms); /* Look for JVMs in the additional directories */ if (n > 0) { int i; StrBuf sb,sb2; Char* baseDir = NULL; STRBUF_Init(&sb); STRBUF_Init(&sb2); TRACE("JNILIB: checking special directories\n"); for (i=0; i<n; i++) { Str javaHome = NULL; JvmPathType pathType = JVM_GetPathType(dirs[i]); if (pathType == JvmPathRelative) { LPTSTR filePath; TRACE1("JNILIB: relative path: %s\n",dirs[i]); if (baseDir) { STRBUF_Copy(&sb, baseDir); } else { int separator; JVM_GetModuleFileName(NULL,&sb); STRBUF_Replace(&sb, '/', '\\'); separator = STRBUF_LastIndexOf(&sb,'\\'); STRBUF_SetLength(&sb,separator+1); baseDir = STRBUF_Dup(&sb); if (!baseDir) continue; TRACE1("JNILIB: base dir: %s\n",baseDir); } STRBUF_Append(&sb, dirs[i]); STRBUF_Replace(&sb, '/', '\\'); STRBUF_Alloc(&sb2, STRBUF_Length(&sb)); sb2.len = GetFullPathName(STRBUF_Text(&sb), sb2.alloc, sb2.s, &filePath); ASSERT(sb2.len && sb2.s[0]); javaHome = STRBUF_Text(&sb2); } else if (pathType == JvmPathAbsolute) { TRACE1("JNILIB: absolute path: %s\n",dirs[i]); javaHome = dirs[i]; } else if (pathType == JvmPathSystem) { /* directory on the system drive */ TRACE1("JNILIB: system path: %s\n",dirs[i]); STRBUF_Alloc(&sb,GetSystemDirectory(NULL,0)+1); STRBUF_SetLength(&sb,GetSystemDirectory(sb.s,sb.alloc)); STRBUF_Clear(&sb2); STRBUF_AppendChar(&sb2,STRBUF_CharAt(&sb,0)); STRBUF_AppendChar(&sb2,':'); STRBUF_Append(&sb2, dirs[i]); javaHome = STRBUF_Text(&sb2); } else { TRACE1("JNILIB: invalid path: %s\n",dirs[i]); continue; } if (javaHome) { TRACE1("JNILIB: Java home: %s\n",javaHome); if (FILE_IsDir(javaHome)) { JVM* jvm = JVM_CreateDirContext(javaHome); if (jvm) { jvm->flags |= JVM_FLAG_SPECIAL; if (JVM_Add(jvms, jvm) && !jvms->specialVM) { jvms->specialVM = jvm; } } } else { TRACE1("JNILIB: no such directory: %s\n",javaHome); } } } MEM_Free(baseDir); STRBUF_Destroy(&sb); STRBUF_Destroy(&sb2); } /* Did we find anything? */ if (!VECTOR_IsEmpty(&jvms->found)) { JVM_Sort(jvms, JVM_DefaultSort); TRACE1("JNILIB: found %d JVM(s)\n",VECTOR_Size(&jvms->found)); return jvms; } TRACE("JNILIB: found no JVMs\n, sorry"); VECTOR_Destroy(&jvms->found); } MEM_Free(jvms); } return NULL; }
/** * JVM discovery. Returns number of discovered JVMs */ STATIC int JVM_Discover(JVMSet * jvms) { HKEY hRoot = NULL; ULONG err = RegOpenKeyEx(HKLM, JRE_REG_KEY, 0, KEY_READ, &hRoot); char curVer[32]; char ver[COUNT(curVer)]; if (err == NO_ERROR) { ULONG nIndex = 0; /* determine the current version */ ULONG t = REG_SZ; ULONG n = COUNT(ver); TRACE("JNILIB: checking current version of JRE...\n"); err = RegQueryValueEx(hRoot,CURRENT_VERSION,0,&t,(LPBYTE)curVer,&n); if (err == NO_ERROR) { JVM * jvm; curVer[COUNT(curVer)-1] = 0; /* just in case */ TRACE1("JNILIB: current Java version: %s\n", curVer); jvm = JVM_CreateRegContext(hRoot, curVer, False); if (jvm) { jvm->flags |= JVM_FLAG_DEFAULT; if (JVM_Add(jvms, jvm)) { jvms->defaultVM = jvm; } } } TRACE("JNILIB: trying to find other versions of JRE...\n"); while (RegEnumKey(hRoot, nIndex, ver, COUNT(ver)) == NO_ERROR) { if (StrCmp(ver, curVer)) { JVM_Add(jvms, JVM_CreateRegContext(hRoot, ver, False)); } nIndex++; } RegCloseKey(hRoot); } err = RegOpenKeyEx(HKLM, JVM_REG_KEY, 0, KEY_READ, &hRoot); if (err == NO_ERROR) { ULONG nIndex = 0; /* determine the current version */ curVer[0] = 0; if (!jvms->defaultVM) { ULONG t = REG_SZ; ULONG n = COUNT(ver); TRACE("JNILIB: checking current version of JVM...\n"); err = RegQueryValueEx(hRoot,CURRENT_VERSION,0,&t,(LPBYTE)curVer,&n); if (err == NO_ERROR) { JVM * jvm; curVer[COUNT(curVer)-1] = 0; /* just in case */ TRACE1("JNILIB: current Java version: %s\n", curVer); jvm = JVM_CreateRegContext(hRoot, curVer, True); if (jvm) { jvm->flags |= JVM_FLAG_DEFAULT; if (JVM_Add(jvms, jvm)) { jvms->defaultVM = jvm; } } } } TRACE("JNILIB: trying to find other versions of JVM...\n"); while (RegEnumKey(hRoot, nIndex, ver, COUNT(ver)) == NO_ERROR) { if (StrCmp(ver, curVer)) { JVM_Add(jvms, JVM_CreateRegContext(hRoot, ver, True)); } nIndex++; } RegCloseKey(hRoot); } return VECTOR_Size(&jvms->found); }