/* * Class: net_decasdev_dokan_Dokan * Method: isNameInExpression * Signature: (Ljava/lang/String;Ljava/lang/String;Z)Z */ JNIEXPORT jboolean JNICALL Java_net_decasdev_dokan_Dokan_isNameInExpression ( JNIEnv* env, jclass, jstring jexpression, jstring jname, jboolean jignoreCase ) { try { const jchar* pExp = env->GetStringChars( jexpression, NULL ); if ( pExp == NULL ) throw "Failed at GetStringChars for expression"; const jchar* pName = env->GetStringChars( jname, NULL ); if ( pName == NULL ) throw "Failed at GetStringChars for name"; jboolean result = DokanIsNameInExpression( ( LPCWSTR )pExp, ( LPCWSTR )pName, jignoreCase ); env->ReleaseStringChars( jexpression, pExp ); env->ReleaseStringChars( jname, pName ); return result; } catch ( const char* msg ) { env->ThrowNew( env->FindClass( "java/lang/IllegalArgumentException" ), msg ); return FALSE; } }
// check whether Name matches Expression // Expression can contain "?"(any one character) and "*" (any string) // when IgnoreCase is TRUE, do case insenstive matching // // http://msdn.microsoft.com/en-us/library/ff546850(v=VS.85).aspx // * (asterisk) Matches zero or more characters. // ? (question mark) Matches a single character. // DOS_DOT Matches either a period or zero characters beyond the name string. // DOS_QM Matches any single character or, upon encountering a period or end // of name string, advances the expression to the end of the set of // contiguous DOS_QMs. // DOS_STAR Matches zero or more characters until encountering and matching // the final . in the name. BOOL DOKANAPI DokanIsNameInExpression(LPCWSTR Expression, // matching pattern LPCWSTR Name, // file name BOOL IgnoreCase) { ULONG ei = 0; ULONG ni = 0; while (Expression[ei] != '\0') { if (Expression[ei] == L'*') { ei++; if (Expression[ei] == '\0') return TRUE; while (Name[ni] != '\0') { if (DokanIsNameInExpression(&Expression[ei], &Name[ni], IgnoreCase)) return TRUE; ni++; } } else if (Expression[ei] == DOS_STAR) { ULONG p = ni; ULONG lastDot = 0; ei++; while (Name[p] != '\0') { if (Name[p] == L'.') lastDot = p; p++; } BOOL endReached = FALSE; while (!endReached) { endReached = (Name[ni] == '\0' || ni == lastDot); if (!endReached) { if (DokanIsNameInExpression(&Expression[ei], &Name[ni], IgnoreCase)) return TRUE; ni++; } } } else if (Expression[ei] == DOS_QM) { ei++; if (Name[ni] != L'.') { ni++; } else { ULONG p = ni + 1; while (Name[p] != '\0') { if (Name[p] == L'.') break; p++; } if (Name[p] == L'.') ni++; } } else if (Expression[ei] == DOS_DOT) { ei++; if (Name[ni] == L'.') ni++; } else { if (Expression[ei] == L'?') { ei++; ni++; } else if (IgnoreCase && towupper(Expression[ei]) == towupper(Name[ni])) { ei++; ni++; } else if (!IgnoreCase && Expression[ei] == Name[ni]) { ei++; ni++; } else { return FALSE; } } } if (ei == wcslen(Expression) && ni == wcslen(Name)) return TRUE; return FALSE; }
// add entry which matches the pattern specifed in EventContext // to the buffer specifed in EventInfo // LONG MatchFiles(PEVENT_CONTEXT EventContext, PEVENT_INFORMATION EventInfo, PLIST_ENTRY FindDataList, BOOLEAN PatternCheck, PDOKAN_INSTANCE DokanInstance) { PLIST_ENTRY thisEntry, listHead, nextEntry; ULONG lengthRemaining = EventInfo->BufferLength; PVOID currentBuffer = EventInfo->Buffer; PVOID lastBuffer = currentBuffer; ULONG index = 0; PWCHAR pattern = NULL; // search patten is specified if (PatternCheck && EventContext->Operation.Directory.SearchPatternLength != 0) { pattern = (PWCHAR)( (SIZE_T)&EventContext->Operation.Directory.SearchPatternBase[0] + (SIZE_T)EventContext->Operation.Directory.SearchPatternOffset); } listHead = FindDataList; for (thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = nextEntry) { PDOKAN_FIND_DATA find; nextEntry = thisEntry->Flink; find = CONTAINING_RECORD(thisEntry, DOKAN_FIND_DATA, ListEntry); DbgPrintW(L"FileMatch? : %s (%s,%d,%d)\n", find->FindData.cFileName, (pattern ? pattern : L"null"), EventContext->Operation.Directory.FileIndex, index); // pattern is not specified or pattern match is ignore cases if (!pattern || DokanIsNameInExpression(pattern, find->FindData.cFileName, TRUE)) { if (EventContext->Operation.Directory.FileIndex <= index) { // index+1 is very important, should use next entry index ULONG entrySize = DokanFillDirectoryInformation( EventContext->Operation.Directory.FileInformationClass, currentBuffer, &lengthRemaining, &find->FindData, index + 1, DokanInstance); // buffer is full if (entrySize == 0) break; // pointer of the current last entry lastBuffer = currentBuffer; // end if needs to return single entry if (EventContext->Flags & SL_RETURN_SINGLE_ENTRY) { DbgPrint(" =>return single entry\n"); index++; break; } DbgPrint(" =>return\n"); // the offset of next entry ((PFILE_BOTH_DIR_INFORMATION)currentBuffer)->NextEntryOffset = entrySize; // next buffer position currentBuffer = (PCHAR)currentBuffer + entrySize; } index++; } } // Since next of the last entry doesn't exist, clear next offset ((PFILE_BOTH_DIR_INFORMATION)lastBuffer)->NextEntryOffset = 0; // acctualy used length of buffer EventInfo->BufferLength = EventContext->Operation.Directory.BufferLength - lengthRemaining; if (index <= EventContext->Operation.Directory.FileIndex) { if (thisEntry != listHead) return -2; // BUFFER_OVERFLOW return -1; // NO_MORE_FILES } return index; }