/** * Creates MidpSession for the specified XRPC client id. Invoked on the XRPC * thread under synchronization. */ STATIC MidpSession* GWENG_MidpCreateSession(EcmtGateway* gw, int xrpcSid) { MidpSession* ses = MEM_New(MidpSession); if (ses) { LUID luid; /* Just in case if AllocateLocallyUniqueId fails... */ luid.LowPart = (DWORD)ses; AllocateLocallyUniqueId(&luid); memset(ses, 0, sizeof(*ses)); ses->key.xrpcSid = xrpcSid; ses->key.xrpcSession = XRPC_GetCurrentSession(gw->xrpc); ses->sid = luid.LowPart; ASSERT(!HASH_Contains(&gw->ecmtSessionMap,(HashKey)ses->sid)); ASSERT(!HASH_Contains(&gw->midpSessionMap,&ses->key)); if (HASH_Init(&ses->connMap, 1, NULL, NULL, hashFreeValueProc)) { /* Create context for the control connection (number zero) */ MidpConnection* conn = MEM_New(MidpConnection); if (conn) { memset(conn, 0, sizeof(*conn)); if (HASH_Put(&ses->connMap, (HashKey)0, conn)) { if (HASH_Put(&gw->ecmtSessionMap,(HashKey)ses->sid,ses)) { if (HASH_Put(&gw->midpSessionMap, &ses->key, ses)) { if (MUTEX_Init(&ses->xrpcMutex)) { ses->xrpcWorkThread = WKQ_Create(); if (ses->xrpcWorkThread) { ses->xrpcWorkItem = WKI_Create( ses->xrpcWorkThread, GWENG_AsyncXRpc, ses); if (ses->xrpcWorkItem) { QUEUE_Init(&ses->xrpcQueue); TRACE3("GW: new session %08x for " "%08x.%08x\n", ses->sid, ses->key.xrpcSession, ses->key.xrpcSid); return ses; } WKQ_Delete(ses->xrpcWorkThread); } MUTEX_Destroy(&ses->xrpcMutex); } HASH_Remove(&gw->midpSessionMap, &ses->key); } HASH_Remove(&gw->ecmtSessionMap, (HashKey)ses->sid); } } else { MEM_Free(conn); } } HASH_Destroy(&ses->connMap); } MEM_Free(ses); } return NULL; }
/** * Returns a wait context from the pool, or allocates a new one */ STATIC Waiter * WKQ_GetWaiter(WorkQueueModule * module) { Waiter * waiter = NULL; ASSERT(module->initcount > 0); if (module->waitpool) { MUTEX_Lock(&module->mutex); if (module->waitpool) { waiter = module->waitpool; module->waitpool = waiter->next; waiter->next = NULL; module->nwait--; ASSERT(module->nwait >= 0); ASSERT(module->nwait || !module->waitpool); } MUTEX_Unlock(&module->mutex); } if (!waiter) { waiter = MEM_New(Waiter); if (waiter) { if (!EVENT_Init(&waiter->event)) { MEM_Free(waiter); waiter = NULL; } } } if (waiter) { EVENT_Reset(&waiter->event); } return waiter; }
/** * Submits asynchronous XRPC call. Doesn't wait until the call completes. * This resolves the deadlock between Ecmt Gateway and emulator.exe */ STATIC void GWENG_SubmitAsyncCall(MidpSession* midp, XRpcString method, XRpcContainer* params) { if (params) { AsyncXRpcEntry* a = MEM_New(AsyncXRpcEntry); if (a) { memset(a, 0, sizeof(*a)); a->method = method; a->params = params; MUTEX_Lock(&midp->xrpcMutex); QUEUE_InsertTail(&midp->xrpcQueue, &a->entry); MUTEX_Unlock(&midp->xrpcMutex); if (!WKI_Submit(midp->xrpcWorkItem)) { /* * The work item is busy processing pending calls. It * could be that GWENG_AsyncXRpc callback has already * exited the loop but hasn't returned yet. In that case, * this asynchronous call would remain in the queue until * we submit the next one. That's not good. Try to "kick" * it with another work item. */ WKQ_InvokeLater(midp->xrpcWorkThread, GWENG_AsyncXRpc, midp); } } else { XRPC_FreeContainer(params); } } }
/** * Initializes the input zlib context */ STATIC Bool ZipInitIn(Zip * zf) { /* allocate buffer */ zf->inbuf = (I8u*)MEM_Alloc(zf->bufsize); if (zf->inbuf) { /* allocate zlib context */ zf->in = MEM_New(z_stream); if (zf->in) { int bits = ((zf->zflags & ZIP_ZHDR) ? (-MAX_WBITS) : MAX_WBITS); /* tell zlib to use our memory allocation functions */ memset(zf->in, 0, sizeof(*zf->in)); zf->in->zalloc = ZipMemAlloc; zf->in->zfree = ZipMemFree; zf->in->next_in = zf->inbuf; if (inflateInit2(zf->in, bits) == Z_OK) { /* skip .gz header */ if (!(zf->zflags & ZIP_GZIP) || ZipSkipHeader(zf)) { return True; } inflateEnd(zf->in); } MEM_Free(zf->in); zf->in = NULL; } MEM_Free(zf->inbuf); zf->inbuf = NULL; } zf->zflags |= ZIP_IN_ERR; return False; }
/** NOTE: both IP address and port are in host byte order */ STATIC File * SocketOpen2(IPaddr addr, Port port) { Socket sock = INVALID_SOCKET; if (SOCKET_GetTcp(0,&sock)) { if (SOCKET_Connect(sock, addr, port)) { SocketFile * s = MEM_New(SocketFile); if (s) { Bool ok; StrBuf32 nameBuf; STRBUF_InitBufXXX(&nameBuf); STRBUF_Format(&nameBuf.sb, TEXT(IPADDR_FORMAT)TEXT_(":%hu"), HOST_IPADDR_FORMAT_ARG(addr),port); memset(s, 0, sizeof(*s)); ok = FILE_Init(&s->file, nameBuf.sb.s, False, &SocketIO); STRBUF_Destroy(&nameBuf.sb); if (ok) { s->sock = sock; s->eof = False; return &s->file; } } shutdown(sock, SHUT_RDWR); } closesocket(sock); } return NULL; }
/** * "connect" method handler */ STATIC XRpcElement* GWENG_MidpConnect(void* ctx, const XRpcContainer* param) { /* decode parameters */ const XRpcIntElement* sidParam = XRPC_GetIntElementByName(param, ECMTGW_SEI_CONNECT_SID_PARAM); const XRpcIntElement* cidParam = XRPC_GetIntElementByName(param, ECMTGW_SEI_CONNECT_CID_PARAM); const XRpcShortElement* portParam = XRPC_GetShortElementByName(param, ECMTGW_SEI_CONNECT_PORT_PARAM); if (sidParam && cidParam && portParam) { MidpSession* midp; EcmtGateway* gw = ctx; I32u cid = XRPC_GetInt(cidParam); Port port = XRPC_GetShort(portParam); MidpSessionKey key; key.xrpcSid = XRPC_GetInt(sidParam); key.xrpcSession = XRPC_GetCurrentSession(gw->xrpc); TRACE4("GW: MidpConnect(%08x.%08x.%u, port %hu)\n", key.xrpcSession, key.xrpcSid, cid, port); MUTEX_Lock(&gw->mutex); midp = HASH_Get(&gw->midpSessionMap,&key); if (midp) { MidpConnection* conn = MEM_New(MidpConnection); if (conn) { memset(conn, 0, sizeof(*conn)); conn->connId = cid; if (HASH_Put(&midp->connMap, (HashKey)cid, conn)) { char pkt[ECMT_MIDP_DEBUG_CONNECT_SIZE]; GWENG_MidpFillHeader(pkt,midp->sid,ECMT_MIDP_DEBUG_OPCODE_CONNECT); *((I32u*)(pkt+ECMT_MIDP_DEBUG_CONNECT_CID_OFFSET)) = htonl(cid); *((I16u*)(pkt+ECMT_MIDP_DEBUG_CONNECT_PORT_OFFSET)) = htons(port); GWENG_QueueAdd(gw->handsetQueue, KECMT_MIDP_DEBUG_PLUGIN_UID, pkt, ECMT_MIDP_DEBUG_CONNECT_SIZE); MUTEX_Unlock(&gw->mutex); return NULL; } MEM_Free(conn); } GWENG_MidpResetConn(gw, midp, cid, False, True); } else { TRACE3("GW: unexpected MIDP connect (%08x.%08x.%u)\n", key.xrpcSession, key.xrpcSid, cid); } MUTEX_Unlock(&gw->mutex); } return NULL; }
/** * Allocates a new BitSet */ BitSet * BITSET_Create() { BitSet * bs = MEM_New(BitSet); if (bs) { BITSET_Init(bs); return bs; } return NULL; }
/** * Initializes the output zlib context */ STATIC Bool ZipInitOut(Zip * zf) { /* allocate buffer */ zf->outbuf = (I8u*)MEM_Alloc(zf->bufsize); if (zf->outbuf) { /* allocate zlib context */ zf->out = MEM_New(z_stream); if (zf->out) { int zerr; int bits = ((zf->zflags & ZIP_ZHDR) ? (-MAX_WBITS) : MAX_WBITS); /* tell zlib to use our memory allocation functions */ memset(zf->out, 0, sizeof(*zf->out)); zf->out->zalloc = ZipMemAlloc; zf->out->zfree = ZipMemFree; /* windowBits is passed < 0 to suppress zlib header */ zerr = deflateInit2(zf->out, Z_BEST_COMPRESSION, Z_DEFLATED, bits, 8, Z_DEFAULT_STRATEGY); if (zerr == Z_OK) { if (zf->zflags & ZIP_GZIP) { /* write a very simple .gz header */ I8u hdr[10]; memset(hdr, 0, sizeof(hdr)); hdr[0] = (I8u)GzMagic[0]; hdr[1] = (I8u)GzMagic[1]; hdr[2] = Z_DEFLATED; hdr[9] = OS_CODE; if (FILE_Write(zf->f,hdr,sizeof(hdr)) == sizeof(hdr)) { FILE_Flush(zf->f); zf->out->next_out = zf->outbuf; zf->out->avail_out = zf->bufsize; return True; } } else { /* not writing the header */ zf->out->next_out = zf->outbuf; zf->out->avail_out = zf->bufsize; return True; } deflateEnd(zf->out); } MEM_Free(zf->out); zf->out = NULL; } MEM_Free(zf->outbuf); zf->outbuf = NULL; } zf->zflags |= ZIP_OUT_ERR; return False; }
/** * Allocates a new lock and initializes it */ RWLock * RWLOCK_Create() { RWLock * lock = MEM_New(RWLock); if (lock) { if (RWLOCK_Init(lock)) { return lock; } MEM_Free(lock); } return NULL; }
/** * Allocates a new event and initializes it */ Event * EVENT_Create() { Event * e = MEM_New(Event); if (e) { if (EVENT_Init(e)) { return e; } MEM_Free(e); } return NULL; }
/** * Allocate random number generator context. * Returns NULL is memory allocation fails. * The seed is initialized with the value returned by time() */ Random * RANDOM_CreateRNG(const RNG * rng) { Random * r = MEM_New(Random); if (r) { if (!RANDOM_Init(r, rng)) { MEM_Free(r); r = NULL; } } return r; }
/** * Creates new critical section */ CritSect * CS_Create() { CritSect * cs = MEM_New(CritSect); if (cs) { if (CS_Init(cs)) { return cs; } MEM_Free(cs); } return NULL; }
/** * Creates the iterator containing one element. Does not support the remove * operation. */ Iterator * ITR_Singleton(IElementC element) { SingletonIterator * si = MEM_New(SingletonIterator); if (si) { ITR_Init(&si->itr, &singletonIterator); si->element = (IElement)element; si->hasNext = True; return &si->itr; } else { return NULL; } }
STATIC void * RNG_Lehmer_Init(Random * rnd) { RNG_Lehmer_Data * r; UNREF(rnd); r = MEM_New(RNG_Lehmer_Data); if (r) { r->multiplier = __INT64_C(0x5DEECE66D); r->addend = __INT64_C(0xB); r->mask = (__INT64_C(1) << 48) - 1; r->seed = RANDOM_GenSeed(); } return r; }
/** * This is an exported function that associates a "socket file" with an * open socket. If this call fails, the caller is responsible for closing * the socket. If this cal succeeds, then the socket will be closed by * FILE_Close() */ File * FILE_AttachToSocket(Socket sock) { SocketFile * sf = MEM_New(SocketFile); if (sf) { memset(sf, 0, sizeof(*sf)); sf->sock = sock; sf->eof = False; if (FILE_Init(&sf->file, TEXT("socket"), True, &SocketIO)) { return &sf->file; } MEM_Free(sf); } return NULL; }
/** * Creates the COM port transport */ EcmtConnection* GWENG_CreateQueueConnection(EcmtGateway* gw, EcmtQueue* q) { EcmtQueueConnection* qc = MEM_New(EcmtQueueConnection); if (qc) { memset(qc, 0, sizeof(*qc)); qc->queue = q; qc->header = True; qc->connection.io = &gwIoQueue; qc->connection.ref = 1; qc->connection.gw = gw; BUFFER_Init(&qc->buf); return &qc->connection; } return NULL; }
/** * Creates the read-only iterator which doesn't support remove operation */ Iterator * QUEUE_ConstIterator(const Queue * q) { if (QUEUE_IsEmpty(q)) { return ITR_Empty(); } else { QueueIterator * qi = MEM_New(QueueIterator); if (qi) { ITR_Init(&qi->itr, &queueConstIterator); qi->entry = NULL; qi->next = q->head.next; return &qi->itr; } else { return NULL; } } }
/** * Creates the iterator */ Iterator * QUEUE_Iterator(Queue * q) { if (QUEUE_IsEmpty(q)) { return ITR_Empty(); } else { QueueIterator * qi = MEM_New(QueueIterator); if (qi) { ITR_Init(&qi->itr, &queueIterator); qi->entry = NULL; qi->next = QUEUE_First(q); return &qi->itr; } else { return NULL; } } }
/** * Creates JVM context given the JRE home dir. We assume that the parameter * points to existing directory. Note that in this case we don't know the * version of JRE. We could figure it out by reading the manifest from rt.jar * but that might take considerable amount of time. A typical size of rt.jar * is over 25MB. Instead, we assume that if the caller has given us a path * to its own JRE installation, then this is the preferred version of JRE. */ STATIC JVM * JVM_CreateDirContext(Str home) { JVM * jvm = MEM_New(JVM); if (jvm) { memset(jvm, 0, sizeof(*jvm)); jvm->versionString = STRING_Dup("UNKNOWN"); jvm->javaHome = STRING_Dup(home); if (jvm->versionString && jvm->javaHome) { char s[MAX_PATH]; /* Normalize the Java home path */ Char* p; int len = StrLen(jvm->javaHome); for (p=StrChr(jvm->javaHome,'/'); p; p=strchr(p,'/')) *p = '\\'; while (len > 0 && jvm->javaHome[len-1] == '\\') { jvm->javaHome[--len] = 0; } /* find jvm.dll */ snprintf(s,COUNT(s),"%s\\%s",jvm->javaHome,JVM_DLL_1); s[COUNT(s)-1] = 0; if (FILE_IsFile(s)) { jvm->javaLib = STRING_Dup(s); if (jvm->javaLib) { TRACE1("JNILIB: Java runtime lib: %s\n",s); return jvm; } } else { TRACE1("JNILIB: no such file: %s\n",s); snprintf(s,COUNT(s),"%s\\%s",jvm->javaHome,JVM_DLL_2); s[COUNT(s)-1] = 0; if (FILE_IsFile(s)) { jvm->javaLib = STRING_Dup(s); if (jvm->javaLib) { TRACE1("JNILIB: Java runtime lib: %s\n",s); return jvm; } } else { TRACE1("JNILIB: no such file: %s\n",s); } } } JVM_Free(jvm); } return NULL; }
/** * Creates the iterator that allows to filter the value returned by the * iterator and substitute it with something else. NULL callback means * no filtering, i.e. the default behavior provided by the target iterator. */ Iterator * ITR_Filter(Iterator * target, ItrFilterNext fnext, ItrFilterRemove fremove, void * ctx) { ASSERT(target); if (target) { FilterIterator * fi = MEM_New(FilterIterator); if (fi) { ITR_Init(&fi->itr, &filterIterator); fi->target = target; fi->next = fnext; fi->remove = fremove; fi->ctx = ctx; return &fi->itr; } } return NULL; }
/** * Create a new thread, returning True on success */ Bool THREAD_Create(ThrID* id, ThrProc proc, void * arg) { ThrData * thr = NULL; ASSERT(THREAD_IsInited()); if (id) *id = NULL; if (!THREAD_IsInited()) return False; /* allocate thread data */ thr = MEM_New(ThrData); if (thr) { memset(thr, 0, sizeof(*thr)); if (EVENT_Init(&thr->exitEvent)) { InterlockedIncrement(&WIN32_ThreadCount); thr->signature = ThrData_Signature; thr->refCount = 2; thr->proc = proc; thr->arg = arg; /* create Win32 thread */ thr->handle = CreateThread(NULL, 0, WIN32_ThreadProc, thr, CREATE_SUSPENDED, &thr->thrid); ASSERT(thr->handle); if (thr->handle) { if (ResumeThread(thr->handle) != (DWORD)-1) { if (id) *id = thr; return True; } else { WIN32_FAILURE(ResumeThread); VERIFY(CloseHandle(thr->handle)); } } else { WIN32_FAILURE(CreateThread); } EVENT_Destroy(&thr->exitEvent); InterlockedDecrement(&WIN32_ThreadCount); } MEM_Free(thr); } return False; }
/** * Gets a RWLockWaiter structure from the cache or allocates a new one. * It's the responsibility of the caller to initialize the event * pointer and insert the waiter into the right queue. It's done * by RWLOCK_GetExclusiveWaiter and RWLOCK_GetSharedWaiter functions. * Must be called under synchronization */ STATIC RWLockWaiter * RWLOCK_GetWaiter(RWLock * lock) { RWLockWaiter * w = NULL; QEntry * e = QUEUE_RemoveTail(&lock->waiterCache); if (e) { w = QCAST(e,RWLockWaiter,entry); w->index = RWLOCK_GetNextWaiterIndex(lock); return w; } else { w = MEM_New(RWLockWaiter); if (w) { memset(w,0,sizeof(*w)); w->index = RWLOCK_GetNextWaiterIndex(lock); return w; } } return NULL; }
/** * Creates a clone of the bitset */ BitSet * BITSET_Clone(const BitSet * bs) { BitSet * clon = MEM_New(BitSet); if (clon) { *clon = *bs; if (clon->alloc) { size_t size = sizeof(BitUnit) * clon->alloc; clon->storage.units = (BitUnit*)MEM_Alloc(size); if (clon->storage.units) { memcpy(clon->storage.units, bs->storage.units, size); return clon; } } else { return clon; } MEM_Free(clon); } return NULL; }
/** * Enumerates the contents of the directory. */ Iterator * FILE_ListDir(Str dir) { Win32DirIterator * w = MEM_New(Win32DirIterator); if (w) { size_t len; DirIterator * di = &w->common; memset(w, 0, sizeof(*w)); DIR_ItrInit(di, &dirIterator); if (!dir || !dir[0]) dir = TEXT("."); len = StrLen(dir); if (STRBUF_Alloc(&di->dirName, len + 4)) { VERIFY(STRBUF_Copy(&di->dirName, dir)); VERIFY(STRBUF_Append(&di->dirName, TEXT("\\*.*"))); w->handle = FindFirstFile(di->dirName.s, &w->data); STRBUF_SetLength(&di->dirName, len); if (w->handle != INVALID_HANDLE_VALUE) { if (StrCmp(w->data.cFileName,TEXT(".")) && StrCmp(w->data.cFileName,TEXT(".."))) { di->hasNext = True; } else { while (FindNextFile(w->handle, &w->data)) { if (StrCmp(w->data.cFileName,TEXT(".")) && StrCmp(w->data.cFileName,TEXT(".."))) { di->hasNext = True; break; } } } /* preallocate space for the file name */ if (!di->hasNext || STRBUF_Alloc(&di->fileName, StrLen(w->data.cFileName))) { return &di->itr; } FindClose(w->handle); } } DIR_ItrDestroy(&w->common); MEM_Free(w); } return NULL; }
/** * Returns work item from the pool, allocates a new one if needed. */ STATIC WorkItem * WKQ_GetWorkItem(WorkQueueModule * mod, WorkQueue * q, WorkProc cb, WorkProc2 cb2, void * p1, void * p2) { WorkItem * w = NULL; ASSERT(mod->initcount > 0); /* can't use QUEUE_IsEmpty without synchronization */ if (!mod->itempool.size) { MUTEX_Lock(&mod->mutex); if (!QUEUE_IsEmpty(&mod->itempool)) { w = QCAST(QUEUE_RemoveHead(&mod->itempool),WorkItem,itemsQ); w->flags = 0; } MUTEX_Unlock(&mod->mutex); } if (!w) { w = MEM_New(WorkItem); if (w) { memset(w, 0, sizeof(*w)); } } if (w) { if (MUTEX_Lock(&q->mutex)) { w->proc = cb; w->proc2 = cb2; w->param = p1; w->param2 = p2; QUEUE_InsertTail(&q->items,&w->itemsQ); MUTEX_Unlock(&q->mutex); return w; } MEM_Free(w); } return NULL; }
/** * Creates a new Zip IO context. * Compresses output data and decompresses input data. */ File * FILE_Zip(File * f, int flags) { ASSERT(f); ASSERT(!(flags & (~0x000f))); if (f) { Zip * zf = MEM_New(Zip); if (zf) { memset(zf, 0, sizeof(*zf)); if (FILE_Init(&zf->file, TEXT("zip"), True, &ZipIO)) { zf->f = f; zf->bufsize = Z_BUFSIZE; if (flags & FILE_ZIP_IN) zf->zflags |= ZIP_IN; if (flags & FILE_ZIP_OUT) zf->zflags |= ZIP_OUT; if (flags & FILE_ZIP_ZHDR) zf->zflags |= ZIP_ZHDR; if (flags & FILE_ZIP_GZIP) zf->zflags |= ZIP_GZIP; return &zf->file; } MEM_Free(zf); } } return NULL; }
/** * Creates JVM context given the JRE or JDK registry key. */ STATIC JVM * JVM_CreateRegContext(HKEY hJavaKey, Str szVersion, Bool isJdk) { int n; JavaVersion version; if (JVM_ParseVersion2(szVersion,&version,&n)) { JVM * jvm = MEM_New(JVM); if (jvm) { memset(jvm, 0, sizeof(*jvm)); if (isJdk) jvm->flags |= JVM_FLAG_JDK; jvm->version = version; jvm->versionString = STRING_Dup(szVersion); jvm->nVersionDigits = n; if (jvm->versionString) { if (JVM_Check(hJavaKey, jvm)) { return jvm; } } JVM_Free(jvm); } } else { TRACE1("JNILIB: unparsable Java version: %s\n",szVersion); } return NULL; }
/** * "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++; } }
/** * 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; }