jstring wchar_to_java(JNIEnv* env, const wchar_t* chars, size_t len, jobject result) { if (sizeof(wchar_t) != 2) { mark_failed_with_message(env, "unexpected size of wchar_t", result); return NULL; } return env->NewString((jchar*)chars, len); }
JNIEXPORT void JNICALL Java_net_rubygrapefruit_platform_internal_jni_WindowsFileFunctions_stat(JNIEnv *env, jclass target, jstring path, jobject dest, jobject result) { jclass destClass = env->GetObjectClass(dest); jmethodID mid = env->GetMethodID(destClass, "details", "(IJJ)V"); if (mid == NULL) { mark_failed_with_message(env, "could not find method", result); return; } WIN32_FILE_ATTRIBUTE_DATA attr; wchar_t* pathStr = java_to_wchar(env, path, result); BOOL ok = GetFileAttributesExW(pathStr, GetFileExInfoStandard, &attr); free(pathStr); if (!ok) { DWORD error = GetLastError(); if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND || error == ERROR_NOT_READY) { // Treat device with no media as missing env->CallVoidMethod(dest, mid, (jint)FILE_TYPE_MISSING, (jlong)0, (jlong)0); return; } mark_failed_with_errno(env, "could not file attributes", result); return; } jlong lastModified = lastModifiedNanos(&attr.ftLastWriteTime); if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { env->CallVoidMethod(dest, mid, (jint)FILE_TYPE_DIRECTORY, (jlong)0, lastModified); } else { jlong size = ((jlong)attr.nFileSizeHigh << 32) | attr.nFileSizeLow; env->CallVoidMethod(dest, mid, (jint)FILE_TYPE_FILE, size, lastModified); } }
JNIEXPORT void JNICALL Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_initConsole(JNIEnv *env, jclass target, jint output, jobject result) { CONSOLE_SCREEN_BUFFER_INFO console_info; HANDLE handle = getHandle(env, output, result); if (handle == NULL) { mark_failed_with_message(env, "not a terminal", result); return; } if (!GetConsoleScreenBufferInfo(handle, &console_info)) { if (GetLastError() == ERROR_INVALID_HANDLE) { mark_failed_with_message(env, "not a console", result); } else { mark_failed_with_errno(env, "could not get console buffer", result); } return; } current_console = handle; original_attributes = console_info.wAttributes; current_attributes = original_attributes; Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_normal(env, target, result); }
JNIEXPORT void JNICALL Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_getConsoleSize(JNIEnv *env, jclass target, jint output, jobject dimension, jobject result) { CONSOLE_SCREEN_BUFFER_INFO console_info; HANDLE handle = getHandle(env, output, result); if (handle == NULL) { mark_failed_with_message(env, "not a console", result); return; } if (!GetConsoleScreenBufferInfo(handle, &console_info)) { mark_failed_with_errno(env, "could not get console buffer", result); return; } jclass dimensionClass = env->GetObjectClass(dimension); jfieldID widthField = env->GetFieldID(dimensionClass, "cols", "I"); env->SetIntField(dimension, widthField, console_info.srWindow.Right - console_info.srWindow.Left + 1); jfieldID heightField = env->GetFieldID(dimensionClass, "rows", "I"); env->SetIntField(dimension, heightField, console_info.srWindow.Bottom - console_info.srWindow.Top + 1); }
JNIEXPORT void JNICALL Java_net_rubygrapefruit_platform_internal_jni_WindowsFileFunctions_readdir(JNIEnv *env, jclass target, jstring path, jobject contents, jobject result) { jclass contentsClass = env->GetObjectClass(contents); jmethodID mid = env->GetMethodID(contentsClass, "addFile", "(Ljava/lang/String;IJJ)V"); if (mid == NULL) { mark_failed_with_message(env, "could not find method", result); return; } WIN32_FIND_DATAW entry; wchar_t* pathStr = java_to_wchar(env, path, result); HANDLE dirHandle = FindFirstFileW(pathStr, &entry); free(pathStr); if (dirHandle == INVALID_HANDLE_VALUE) { mark_failed_with_errno(env, "could not open directory", result); return; } do { if (wcscmp(L".", entry.cFileName) == 0 || wcscmp(L"..", entry.cFileName) == 0) { continue; } jstring childName = wchar_to_java(env, entry.cFileName, wcslen(entry.cFileName), result); jint type = (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_TYPE_DIRECTORY : FILE_TYPE_FILE; jlong lastModified = lastModifiedNanos(&entry.ftLastWriteTime); jlong size = ((jlong)entry.nFileSizeHigh << 32) | entry.nFileSizeLow; env->CallVoidMethod(contents, mid, childName, type, size, lastModified); } while (FindNextFileW(dirHandle, &entry) != 0); DWORD error = GetLastError(); if (error != ERROR_NO_MORE_FILES ) { mark_failed_with_errno(env, "could not read next directory entry", result); } FindClose(dirHandle); }
/* * File system functions */ JNIEXPORT void JNICALL Java_net_rubygrapefruit_platform_internal_jni_PosixFileSystemFunctions_listFileSystems(JNIEnv *env, jclass target, jobject info, jobject result) { wchar_t* volumeName = (wchar_t*)malloc(sizeof(wchar_t) * (MAX_PATH+1)); jclass info_class = env->GetObjectClass(info); jmethodID method = env->GetMethodID(info_class, "add", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V"); HANDLE handle = FindFirstVolumeW(volumeName, MAX_PATH+1); if (handle == INVALID_HANDLE_VALUE) { free(volumeName); mark_failed_with_errno(env, "could not find first volume", result); return; } wchar_t* deviceName = (wchar_t*)malloc(sizeof(wchar_t) * (MAX_PATH+1)); wchar_t* pathNames = (wchar_t*)malloc(sizeof(wchar_t) * (MAX_PATH+1)); wchar_t* fsName = (wchar_t*)malloc(sizeof(wchar_t) * (MAX_PATH+1)); while(true) { // Chop off the trailing '\' size_t len = wcslen(volumeName); if (len < 5) { mark_failed_with_message(env, "volume name is too short", result); break; } volumeName[len-1] = L'\0'; if (QueryDosDeviceW(&volumeName[4], deviceName, MAX_PATH+1) == 0) { mark_failed_with_errno(env, "could not query dos device", result); break; } volumeName[len-1] = L'\\'; DWORD used; if (GetVolumePathNamesForVolumeNameW(volumeName, pathNames, MAX_PATH+1, &used) == 0) { // TODO - try again if the buffer is too small mark_failed_with_errno(env, "could not query volume paths", result); break; } wchar_t* cur = pathNames; if (cur[0] != L'\0') { if(GetVolumeInformationW(cur, NULL, 0, NULL, NULL, NULL, fsName, MAX_PATH+1) == 0) { if (GetLastError() != ERROR_NOT_READY) { mark_failed_with_errno(env, "could not query volume information", result); break; } wcscpy(fsName, L"unknown"); } for (;cur[0] != L'\0'; cur += wcslen(cur) + 1) { env->CallVoidMethod(info, method, env->NewString((jchar*)deviceName, wcslen(deviceName)), env->NewString((jchar*)fsName, wcslen(fsName)), env->NewString((jchar*)cur, wcslen(cur)), JNI_FALSE); } } if (FindNextVolumeW(handle, volumeName, MAX_PATH) == 0) { if (GetLastError() != ERROR_NO_MORE_FILES) { mark_failed_with_errno(env, "could find next volume", result); } break; } } free(volumeName); free(deviceName); free(pathNames); free(fsName); FindVolumeClose(handle); }