/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024, 2026 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package platform.dependent.mswindows.services;
import avt.io.*;
import platform.dependent.mswindows.kernel.*;
import platform.independent.filesystem.*;
import platform.independent.osservices.*;
import platform.independent.util.*;
public final class MSWindowsServices(platform.dependent.PlatformServices)
{
private static int startThreadResult;
private static CriticalSection startThreadOperation;
private static Process currentProcess;
private static OrderedTable fileSystemRootTable;
private static CriticalSection fileSystemRootOperation;
private static OutOfResourcesError errorOutOfResources;
private static final long TAGGED_STACK_DATA_AREA_SIZE;
private static final long TAGGED_STACK_CONTEXT_AREA_SIZE;
public static void finalization() { finalize(); }
public static boolean initialization() {
int size = class.instanceSize;
long ptr = Kernel.virtualAlloc(0, size + (-size & (MemoryRegion.PAGE_SIZE - 1)), Kernel.MEM_COMMIT, Kernel.PAGE_READWRITE);
return ptr != 0 && initialize(ptr, class);
}
private static void initErrors() {
errorOutOfResources = new OutOfResourcesError(platform.independent.osservices.package.getResourceString("!machine-error.out-of-resources"));
}
private static void initServices() {
startThreadOperation = new CriticalSection();
fileSystemRootTable = new OrderedTable();
fileSystemRootOperation = new CriticalSection();
currentProcess = new CurrentProcess();
String workingDirectory = currentProcess.workingDirectory;
if(workingDirectory.length >= 4 && workingDirectory[0] == '/' && workingDirectory[2] == ':' && workingDirectory[3] == '/')
{
char volumeLetter = workingDirectory[1];
if(volumeLetter >= 'A' && volumeLetter <= 'Z' || volumeLetter >= 'a' && volumeLetter <= 'z')
{
volumeLetter &= 0x005f;
String rootPath = new String(new char[] { '/', volumeLetter, ':' });
fileSystemRootTable[rootPath] = new FileSystemDescriptor(rootPath, workingDirectory.substring(3));
}
}
}
private static void protectImportMemoryRegion() {
long2 regionBounds = getImportMemoryRegionPointers();
long regionBegin = regionBounds[0];
long regionEnd = regionBounds[1];
Kernel.virtualProtect(regionBegin, regionEnd - regionBegin + (-regionEnd & (MemoryRegion.PAGE_SIZE - 1)), Kernel.PAGE_READONLY);
}
private static int getDaysCount(int year, int month) {
switch(month + 1)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: return 31;
case 4:
case 6:
case 9:
case 11: return 30;
case 2: return ++year % (year % 100 == 0 ? 400 : 4) == 0 ? 29 : 28;
default: return 0;
}
}
private static native long getThreadEntryPoint();
private static native long2 getImportMemoryRegionPointers();
private int fldProcessorNumberOfCores;
private long fldMinimumApplicationAddress;
private long fldMaximumApplicationAddress;
private String fldOperatingSystemVersion;
public () { }
/* время */
public int currentOffsetInMillis() {
TimeZoneInfo tzinfo = new TimeZoneInfo();
Kernel.getTimeZoneInfo(tzinfo.getPointer());
return -60000 * tzinfo.bias;
}
public long currentTimeInMillis() {
SystemTime time = new SystemTime();
Kernel.getSystemTime(time.getPointer());
int yer;
int year = yer = time.year - 1 & 0xffff;
int month = time.month - 1;
int day = time.dayOfMonth - 1;
int hour = time.hour;
int minute = time.minute;
int second = time.second;
int millisecond = time.millisecond;
int days = 146097 * (year / 400);
year %= 400;
days += 36524 * (year / 100);
year %= 100;
days += 1461 * (year / 4) + 365 * (year % 4) + day;
for(int mnt = 0; mnt < month; mnt++) days += getDaysCount(yer, mnt);
return days * 86400000L + hour * 3600000L + minute * 60000L + second * 1000L + millisecond;
}
/* память */
public void deallocateRegion(long2 region, int flags) {
long address = region[0];
long size = region[1];
int freeFlags = Kernel.MEM_DECOMMIT;
if((flags & MemoryRegion.RESERVED) == 0)
{
size = 0;
freeFlags = Kernel.MEM_RELEASE;
}
Kernel.virtualFree(address, size, freeFlags);
}
public void setRegionProtectionBits(long2 region, int pbits) {
int protect;
switch(pbits & (MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE))
{
case MemoryRegion.READABLE:
{
protect = Kernel.PAGE_READONLY;
break;
}
case MemoryRegion.WRITEABLE:
case MemoryRegion.READABLE | MemoryRegion.WRITEABLE:
{
protect = Kernel.PAGE_READWRITE;
break;
}
case MemoryRegion.EXECUTABLE:
{
protect = Kernel.PAGE_EXECUTE;
break;
}
case MemoryRegion.EXECUTABLE | MemoryRegion.READABLE:
{
protect = Kernel.PAGE_EXECUTE_READ;
break;
}
case MemoryRegion.EXECUTABLE | MemoryRegion.WRITEABLE:
case MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE:
{
protect = Kernel.PAGE_EXECUTE_READWRITE;
break;
}
default:
{
protect = Kernel.PAGE_NOACCESS;
}
}
if(Kernel.virtualProtect(region[0], region[1], protect)[0] == 0)
{
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "region" }));
}
}
public int getRegionProtectionBits(long2 region) {
MemoryBasicInfo mbinfo = new MemoryBasicInfo();
if(Kernel.virtualQuery(region[0], mbinfo.getPointer(), MemoryBasicInfo.class.structSize) == 0)
{
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "region" }));
}
switch(mbinfo.protect)
{
case Kernel.PAGE_READONLY : return MemoryRegion.READABLE;
case Kernel.PAGE_READWRITE : return MemoryRegion.READABLE | MemoryRegion.WRITEABLE;
case Kernel.PAGE_WRITECOPY : return MemoryRegion.READABLE | MemoryRegion.WRITEABLE | MemoryRegion.SHARED;
case Kernel.PAGE_EXECUTE : return MemoryRegion.EXECUTABLE;
case Kernel.PAGE_EXECUTE_READ : return MemoryRegion.EXECUTABLE | MemoryRegion.READABLE;
case Kernel.PAGE_EXECUTE_READWRITE: return MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE;
case Kernel.PAGE_EXECUTE_WRITECOPY: return MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE | MemoryRegion.SHARED;
default : return 0;
}
}
public long2 allocateRegion(long2 region, int flags) {
final long MEMORY_START_ADDRESS = 0xffff800000000000L;
final long MEMORY_LIMIT_ADDRESS = 0x0000800000000000L;
long address = region[0];
long size = region[1];
if(size < 0 || size > MEMORY_LIMIT_ADDRESS - MEMORY_START_ADDRESS || address != 0 && (address + size > MEMORY_LIMIT_ADDRESS || address < MEMORY_START_ADDRESS))
{
if(errorOutOfResources == null) return 0;
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "region" }));
}
address &= -MemoryRegion.PAGE_SIZE;
if(size == 0) size = 1;
size += -size & (MemoryRegion.PAGE_SIZE - 1);
int allocationFlags = Kernel.MEM_COMMIT;
if((flags & MemoryRegion.RESERVED) != 0)
{
allocationFlags = Kernel.MEM_RESERVE;
if((flags & (MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE)) != 0) allocationFlags |= Kernel.MEM_COMMIT;
}
if((flags & MemoryRegion.DOWN) != 0)
{
allocationFlags |= Kernel.MEM_TOP_DOWN;
}
int allocationProtect = Kernel.PAGE_NOACCESS;
switch(flags & (MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE))
{
case MemoryRegion.READABLE:
{
allocationProtect = Kernel.PAGE_READONLY;
break;
}
case MemoryRegion.WRITEABLE:
case MemoryRegion.READABLE | MemoryRegion.WRITEABLE:
{
allocationProtect = Kernel.PAGE_READWRITE;
break;
}
case MemoryRegion.EXECUTABLE:
{
allocationProtect = Kernel.PAGE_EXECUTE;
break;
}
case MemoryRegion.EXECUTABLE | MemoryRegion.READABLE:
{
allocationProtect = Kernel.PAGE_EXECUTE_READ;
break;
}
case MemoryRegion.EXECUTABLE | MemoryRegion.WRITEABLE:
case MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE:
{
allocationProtect = Kernel.PAGE_EXECUTE_READWRITE;
break;
}
}
if((address = Kernel.virtualAlloc(address, size, allocationFlags, allocationProtect)) == 0) switch(Kernel.getLastError())
{
default:
{
if(errorOutOfResources == null) return 0;
throw new IllegalArgumentException(avt.lang.package.getResourceString("illegal-argument.passed"));
}
case Kernel.ERROR_NOT_ENOUGH_MEMORY:
{
if(errorOutOfResources == null) return 0;
throw errorOutOfResources;
}
case Kernel.NO_ERROR:
}
return new long2 { address, size };
}
public long2[] enumerateRegions() {
MemoryBasicInfo mbinfo = new MemoryBasicInfo();
long mbiPtr = mbinfo.getPointer();
long mbiSize = MemoryBasicInfo.class.structSize;
long address = fldMinimumApplicationAddress;
long limit = fldMaximumApplicationAddress + 1;
int length = 0;
long2[] result = new long2[0x3f];
while(address < limit && Kernel.virtualQuery(address, mbiPtr, mbiSize) != 0)
{
long size = mbinfo.regionSize;
if(mbinfo.state != Kernel.MEM_FREE)
{
if(length == result.length) Array.copy(result, 0, result = new long2[length << 1 | 1], 0, length);
result[length++] = new long2 { address, size };
}
address += size;
}
if(length != result.length) Array.copy(result, 0, result = new long2[length], 0, length);
return result;
}
/* событие */
public void destroyEvent(long eventDs) { Kernel.closeHandle(eventDs); }
public void setSignalledEvent(long eventDs) { Kernel.setEvent(eventDs); }
public void clearSignalledEvent(long eventDs) { Kernel.resetEvent(eventDs); }
public void waitSignalledEvent(long eventDs, long timeInMillis, int timeInNanos) {
final long timeMaximum = 0xfffffffeL;
if(timeInMillis < Long.MAX_VALUE && timeInNanos >= 500000 || timeInMillis == 0 && timeInNanos > 0) timeInMillis++;
Kernel.waitForSingleObject(eventDs, timeInMillis <= 0 ? Kernel.INFINITE : timeInMillis >= timeMaximum ? (int) timeMaximum : (int) timeInMillis);
}
public long createEvent(boolean manualReset, boolean initialState, char[] name) { return Kernel.createEvent(0, manualReset, initialState, name.getPointer()); }
/* поток исполнения */
public void yieldThread() { Kernel.switchToThread(); }
public void setThreadPriority(long2 threadId, int priority) {
int usedId = (int) threadId[1];
long handle = Kernel.openThread(Kernel.THREAD_SET_LIMITED_INFORMATION, false, usedId);
if(handle == Kernel.NULL) return;
try
{
switch(priority)
{
case Thread.MIN_PRIORITY:
{
priority = Kernel.THREAD_PRIORITY_IDLE;
break;
}
case Thread.LOW_PRIORITY - 1:
{
priority = Kernel.THREAD_PRIORITY_LOWEST;
break;
}
case Thread.LOW_PRIORITY:
{
priority = Kernel.THREAD_PRIORITY_BELOW_NORMAL;
break;
}
case Thread.NORM_PRIORITY - 1:
case Thread.NORM_PRIORITY:
case Thread.NORM_PRIORITY + 1:
{
priority = Kernel.THREAD_PRIORITY_NORMAL;
break;
}
case Thread.HIGH_PRIORITY:
{
priority = Kernel.THREAD_PRIORITY_ABOVE_NORMAL;
break;
}
case Thread.HIGH_PRIORITY + 1:
{
priority = Kernel.THREAD_PRIORITY_HIGHEST;
break;
}
default:
{
priority = Kernel.THREAD_PRIORITY_TIME_CRITICAL;
}
}
Kernel.setThreadPriority(handle, priority);
} finally
{
Kernel.closeHandle(handle);
}
}
public void setThreadDescription(long2 threadId, byte[] src, int offset, int length) {
int usedId = (int) threadId[1];
long handle = Kernel.openThread(Kernel.THREAD_SET_LIMITED_INFORMATION, false, usedId);
if(handle == Kernel.NULL) return;
try
{
Kernel.setThreadDescription(handle, src.getPointer() + offset);
} finally
{
Kernel.closeHandle(handle);
}
}
public boolean isAliveThread(long threadMainId) {
int usedId = (int) threadMainId;
long handle = Kernel.openThread(Kernel.THREAD_QUERY_LIMITED_INFORMATION, false, usedId);
if(handle == Kernel.NULL) return false;
boolean result;
try
{
int2 exitCode = Kernel.getExitCodeThread(handle);
result = exitCode[0] != 0 && exitCode[1] == Kernel.STILL_ACTIVE;
} finally
{
Kernel.closeHandle(handle);
}
return result;
}
public int getThreadPriority(long2 threadId) {
int usedId = (int) threadId[1];
long handle = Kernel.openThread(Kernel.THREAD_QUERY_LIMITED_INFORMATION, false, usedId);
if(handle == Kernel.NULL) return 0;
int result = 0;
try
{
switch(Kernel.getThreadPriority(handle))
{
case Kernel.THREAD_PRIORITY_IDLE:
{
result = Thread.MIN_PRIORITY;
break;
}
case Kernel.THREAD_PRIORITY_LOWEST:
{
result = Thread.LOW_PRIORITY - 1;
break;
}
case Kernel.THREAD_PRIORITY_BELOW_NORMAL:
{
result = Thread.LOW_PRIORITY;
break;
}
case Kernel.THREAD_PRIORITY_NORMAL:
{
result = Thread.NORM_PRIORITY;
break;
}
case Kernel.THREAD_PRIORITY_ABOVE_NORMAL:
{
result = Thread.HIGH_PRIORITY;
break;
}
case Kernel.THREAD_PRIORITY_HIGHEST:
{
result = Thread.HIGH_PRIORITY + 1;
break;
}
case Kernel.THREAD_PRIORITY_TIME_CRITICAL:
{
result = Thread.MAX_PRIORITY;
break;
}
}
} finally
{
Kernel.closeHandle(handle);
}
return result;
}
public int getThreadDescription(long2 threadId, byte[] dst, int offset) {
int usedId = (int) threadId[1];
long handle = Kernel.openThread(Kernel.THREAD_QUERY_LIMITED_INFORMATION, false, usedId);
if(handle == Kernel.NULL) return 0;
int result;
try
{
result = Kernel.getThreadDescription(handle, dst.getPointer() + offset);
} finally
{
Kernel.closeHandle(handle);
}
return result;
}
public int getActiveThreadsQuantity() {
ThreadEntry32 threadInfoObj = new ThreadEntry32() { dwSize = ThreadEntry32.class.structSize };
long threadInfoPtr = threadInfoObj.getPointer();
int thisProcessId = Kernel.getCurrentProcessId();
int result = 0;
long handle = Kernel.createToolHelp32Snapshot(Kernel.TH32CS_SNAPTHREAD, 0);
try
{
if(Kernel.thread32First(handle, threadInfoPtr)) do
{
if(threadInfoObj.th32OwnerProcessID == thisProcessId) result++;
} while(Kernel.thread32Next(handle, threadInfoPtr));
} finally
{
Kernel.closeHandle(handle);
}
return result;
}
public long startThread(Runnable ref) {
if(ref == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "ref" }));
}
int result;
startThreadOperation.lock();
try
{
startThreadResult = 0;
long2 handleAndId = Kernel.createThread(0, 0x1000, getThreadEntryPoint(), ref, 0);
if(handleAndId[0] == Kernel.NULL)
{
throw errorOutOfResources;
}
do
{
Kernel.switchToThread();
if(startThreadResult < 0)
{
throw errorOutOfResources;
}
} while(startThreadResult == 0);
result = (int) handleAndId[1];
} finally
{
startThreadOperation.unlock();
}
return result;
}
public long2 getCurrentThreadId() {
int id = Kernel.getCurrentThreadId();
return new int2 { id, id };
}
public long[] getActiveThreadsMainIds() {
ThreadEntry32 threadInfoObj = new ThreadEntry32() { dwSize = ThreadEntry32.class.structSize };
long threadInfoPtr = threadInfoObj.getPointer();
int thisProcessId = Kernel.getCurrentProcessId();
int length = 0;
long[] result = new long[0x0f];
long handle = Kernel.createToolHelp32Snapshot(Kernel.TH32CS_SNAPTHREAD, 0);
try
{
if(Kernel.thread32First(handle, threadInfoPtr)) do
{
if(threadInfoObj.th32OwnerProcessID == thisProcessId)
{
if(length == result.length) Array.copy(result, 0, result = new long[length << 1 | 1], 0, length);
result[length++] = threadInfoObj.th32ThreadID;
}
} while(Kernel.thread32Next(handle, threadInfoPtr));
} finally
{
Kernel.closeHandle(handle);
}
if(length != result.length) Array.copy(result, 0, result = new long[length], 0, length);
return result;
}
public platform.dependent.Mutex newMutex() { return new CriticalSection(); }
public platform.dependent.Monitor newMonitor() { return new Monitor(); }
/* процесс */
public void exit(int exitCode) { Kernel.exitProcess(exitCode); }
public void closeProcessDescriptor(long2 procDs) {
Kernel.closeHandle(procDs[0]);
Kernel.closeHandle(procDs[1]);
}
public void joinProcess(long2 procDs, long timeInMillis, int timeInNanos) {
final long timeMaximum = 0xfffffffeL;
if(timeInMillis < Long.MAX_VALUE && timeInNanos >= 500000 || timeInMillis == 0 && timeInNanos > 0) timeInMillis++;
Kernel.waitForSingleObject(procDs[0], timeInMillis <= 0 ? Kernel.INFINITE : timeInMillis >= timeMaximum ? (int) timeMaximum : (int) timeInMillis);
}
public boolean isProcessTerminated(long2 procDs) { return Kernel.waitForSingleObject(procDs[0], 0) == Kernel.WAIT_OBJECT_0; }
public boolean isPlatformOutputStream(ByteWriter stream) { return stream instanceof HandleOutputStream; }
public boolean isPlatformInputStream(ByteReader stream) { return stream instanceof HandleInputStream; }
public boolean isCurrentProcessHasInstance() {
ProcessEntry32 processInfoObj = new ProcessEntry32() { dwSize = ProcessEntry32.class.structSize };
long processInfoPtr = processInfoObj.getPointer();
int thisProcessId = Kernel.getCurrentProcessId();
char[] thisModulePathChars = new char[Kernel.MAX_PATH + 1];
char[] anotModulePathChars = new char[Kernel.MAX_PATH + 1];
int thisModulePathLength = Kernel.getModuleFileName(0, thisModulePathChars.getPointer(), Kernel.MAX_PATH + 1);
int anotModulePathLength = 0;
long anotModulePathPtr = anotModulePathChars.getPointer();
long snapshotHandle = Kernel.createToolHelp32Snapshot(Kernel.TH32CS_SNAPPROCESS, 0);
try
{
if(Kernel.process32First(snapshotHandle, processInfoPtr)) do
{
int anotProcessId = processInfoObj.th32ProcessId;
if(thisProcessId == anotProcessId) continue;
long processHandle = Kernel.openProcess(Kernel.PROCESS_QUERY_INFORMATION | Kernel.PROCESS_QUERY_LIMITED_INFORMATION | Kernel.PROCESS_VM_READ, false, anotProcessId);
if(processHandle == 0) continue;
try
{
anotModulePathChars[0] = '\0';
anotModulePathLength = Kernel.getModuleFileNameEx(processHandle, 0, anotModulePathPtr, Kernel.MAX_PATH + 1);
} finally
{
Kernel.closeHandle(processHandle);
}
if(thisModulePathLength == anotModulePathLength && Array.offsetOfNonEqual(thisModulePathChars, 0, anotModulePathChars, 0, thisModulePathLength) == Comparable.INDEFINITE)
{
return true;
}
} while(Kernel.process32Next(snapshotHandle, processInfoPtr));
} finally
{
Kernel.closeHandle(snapshotHandle);
}
return false;
}
public int getProcessExitCode(long2 procDs) {
int2 result = Kernel.getExitCodeProcess(procDs[0]);
return result[0] == 0 ? 0 : result[1];
}
public long getCurrentProcessId() { return Kernel.getCurrentProcessId(); }
public long2 startProcess(platform.dependent.ProcessParameters ref) throws DirectoryNotFoundException, FileNotFoundException, IOException {
int length = 0;
StringBuilder string = new StringBuilder();
/* приоритет */
int priorityClass = Kernel.NORMAL_PRIORITY_CLASS;
switch(ref.priority)
{
case Process.MIN_PRIORITY:
{
priorityClass = Kernel.IDLE_PRIORITY_CLASS;
break;
}
case Process.LOW_PRIORITY - 1:
case Process.LOW_PRIORITY:
{
priorityClass = Kernel.BELOW_NORMAL_PRIORITY_CLASS;
break;
}
case Process.NORM_PRIORITY - 1:
case Process.NORM_PRIORITY:
case Process.NORM_PRIORITY + 1:
{
priorityClass = Kernel.NORMAL_PRIORITY_CLASS;
break;
}
case Process.HIGH_PRIORITY:
case Process.HIGH_PRIORITY + 1:
{
priorityClass = Kernel.ABOVE_NORMAL_PRIORITY_CLASS;
break;
}
case Process.MAX_PRIORITY:
{
priorityClass = Kernel.HIGH_PRIORITY_CLASS;
break;
}
}
/* рабочая папка */
length = string.append(toInternalPath(ref.workingDirectory)).length;
char[] workingDirectory = new char[length + 1];
string.getChars(0, length, workingDirectory, 0);
/* командная строка */
string.clear();
String moduleFileName;
for(String[] arguments = ref.arguments, int alength = arguments.length, int aindex = 0; aindex < alength; aindex++)
{
String argument = arguments[aindex];
if(aindex <= 0)
{
moduleFileName = argument;
} else
{
string.append(' ');
}
if(argument.length > 0 && argument.indexOf(' ') < 0)
{
string.append(argument);
continue;
}
string.append('\"').append(argument).append('\"');
}
length = string.length;
char[] commandLine = new char[length + 1];
string.getChars(0, length, commandLine, 0);
/* переменные среды */
string.clear();
for(Object[] environment = ref.environment, int vlength = environment.length, int vindex = 0; vindex < vlength; vindex++)
{
string.append(environment[vindex]).append('\0');
}
length = string.append('\0').length;
char[] environment = new char[length + 1];
string.getChars(0, length, environment, 0);
/* стандартные потоки ввода-вывода */
long stdInHandle = Kernel.INVALID_HANDLE_VALUE;
HandleInputStream stdInStream = (HandleInputStream) ref.standardInput;
if(stdInStream != null) Kernel.setHandleInfo(stdInHandle = stdInStream.handle, Kernel.HANDLE_FLAG_INHERIT, Kernel.HANDLE_FLAG_INHERIT);
long stdOutHandle = Kernel.INVALID_HANDLE_VALUE;
HandleOutputStream stdOutStream = (HandleOutputStream) ref.standardOutput;
if(stdOutStream != null) Kernel.setHandleInfo(stdOutHandle = stdOutStream.handle, Kernel.HANDLE_FLAG_INHERIT, Kernel.HANDLE_FLAG_INHERIT);
long stdErrHandle = Kernel.INVALID_HANDLE_VALUE;
HandleOutputStream stdErrStream = (HandleOutputStream) ref.standardError;
if(stdErrStream != null) Kernel.setHandleInfo(stdErrHandle = stdErrStream.handle, Kernel.HANDLE_FLAG_INHERIT, Kernel.HANDLE_FLAG_INHERIT);
/* создание процесса */
StartupInfo startupInfo = new StartupInfo() {
dwSize = StartupInfo.class.structSize,
dwFlags = Kernel.STARTF_USESTDHANDLES,
hStdInput = stdInHandle,
hStdOutput = stdOutHandle,
hStdError = stdErrHandle
};
ProcessInfo processInfo = new ProcessInfo();
if(!Kernel.createProcess(
0,
commandLine.getPointer(),
0,
0,
true,
Kernel.CREATE_UNICODE_ENVIRONMENT | priorityClass,
environment.getPointer(),
workingDirectory.getPointer(),
startupInfo.getPointer(),
processInfo.getPointer()
)) switch(Kernel.getLastError())
{
case Kernel.ERROR_FILE_NOT_FOUND:
case Kernel.ERROR_PATH_NOT_FOUND:
{
throw new FileNotFoundException(platform.independent.filesystem.package.getResourceString("not-found.file")) {
fileName = moduleFileName
};
}
case Kernel.ERROR_DIRECTORY:
{
throw new DirectoryNotFoundException(platform.independent.filesystem.package.getResourceString("not-found.directory")) {
directoryName = new String(workingDirectory, 0, workingDirectory.length - 1)
};
}
default:
{
throw errorOutOfResources;
}
}
return new long2 { processInfo.hProcess, processInfo.hThread };
}
public Process getCurrentProcess() { return currentProcess; }
public platform.dependent.EnvironmentTable newEnvironmentTable() { return new EnvironmentTable(); }
public ByteStream newPipe() {
long2 pipeDs = Kernel.createPipe(0, 0x100000);
if(pipeDs == 0)
{
throw errorOutOfResources;
}
return new PipeStream(pipeDs[0], pipeDs[1]);
}
public String getConsoleInputCharsetName() { return "CP-" + Int.toString(Kernel.getConsoleInputCP()); }
public String getConsoleOutputCharsetName() { return "CP-" + Int.toString(Kernel.getConsoleOutputCP()); }
/* файловая система */
public boolean isObjectPathCaseSensitive() { return false; }
public boolean isInternalPathFull(String internalPath) {
int length = internalPath.length;
if(length >= 2 && internalPath[1] == ':' && (length <= 2 || internalPath[2] == '\\'))
{
char volumeLetter = internalPath[0];
return volumeLetter >= 'A' && volumeLetter <= 'Z' || volumeLetter >= 'a' && volumeLetter <= 'z';
}
return false;
}
public FileSystemRoot[] enumerateRoots() throws IOException {
char[] internalRootPath = new char[] { '\0', ':', '\\', '\0' };
long internalRootPathPtr = internalRootPath.getPointer();
int rootsLength = 0;
FileSystemRoot[] rootsArray = new FileSystemRoot['Z' - 'A' + 1];
fileSystemRootOperation.lock();
try
{
for(char volumeLetter = 'A'; volumeLetter <= 'Z'; volumeLetter++)
{
internalRootPath[0] = volumeLetter;
if(Kernel.getDriveType(internalRootPathPtr) > Kernel.DRIVE_NO_ROOT_DIR)
{
String rootPath = new String(new char[] { '/', volumeLetter, ':' });
FileSystemRoot volumeDescriptor = (FileSystemRoot) fileSystemRootTable[rootPath];
if(volumeDescriptor == null)
{
fileSystemRootTable[rootPath] = volumeDescriptor = new FileSystemDescriptor(rootPath, "/");
}
rootsArray[rootsLength++] = volumeDescriptor;
}
}
} finally
{
fileSystemRootOperation.unlock();
}
rootsArray.length = rootsLength;
return rootsArray;
}
public FileSystemRoot getRoot(String objectPath) throws FileSystemNotFoundException, IOException {
int length = objectPath.length;
char volumeLetter;
if(
length < 3 ||
objectPath[0] != '/' ||
((volumeLetter = objectPath[1]) < 'A' || volumeLetter > 'Z') && (volumeLetter < 'a' || volumeLetter > 'z') ||
objectPath[2] != ':' ||
length > 3 && objectPath[3] != '/'
)
{
throw new IllegalObjectNameException(String.format(platform.independent.filesystem.package.getResourceString("illegal-argument.object-name"), new Object[] { "objectPath" }));
}
volumeLetter &= 0x005f;
FileSystemRoot volumeDescriptor;
fileSystemRootOperation.lock();
try
{
String rootPath = objectPath.substring(0, 3);
volumeDescriptor = (FileSystemRoot) fileSystemRootTable[rootPath];
if(volumeDescriptor == null)
{
char[] internalRootPath = new char[] { volumeLetter, ':', '\\', '\0' };
if(Kernel.getDriveType(internalRootPath.getPointer()) <= Kernel.DRIVE_NO_ROOT_DIR)
{
throw new FileSystemNotFoundException(platform.independent.osservices.package.getResourceString("not-found.root-path")) { path = new String(internalRootPath, 0, 3) };
}
fileSystemRootTable[rootPath] = volumeDescriptor = new FileSystemDescriptor(rootPath, "/");
}
} finally
{
fileSystemRootOperation.unlock();
}
return volumeDescriptor;
}
public String getUserConfigDir() throws IOException {
String internalPath;
label0:
{
with(currentProcess.environment) if((internalPath = operator []("AppData")) == null || internalPath.length <= 0)
{
if((internalPath = operator []("UserProfile")) == null)
{
throw new IOException(avt.io.package.getResourceString("io"));
}
if(!internalPath.endsWith("\\")) internalPath = internalPath + '\\';
internalPath = internalPath + "AppData\\Roaming\\";
break label0;
}
if(!internalPath.endsWith("\\")) internalPath = internalPath + '\\';
}
String objectPath = toObjectPath(internalPath);
with(getRoot(objectPath), fileSystem) for(String subdirPath = objectPath.substring(path.length), int pos = 0; (pos = subdirPath.indexOf('/', pos + 1)) >= 0; )
{
String checkPath = subdirPath.substring(0, pos);
if(!isObjectExists(checkPath)) createDirectory(checkPath);
}
return objectPath;
}
public String getUserCacheDir() throws IOException { return getUserLocalDir(); }
public String getUserLocalDir() throws IOException {
String internalPath;
label0:
{
with(currentProcess.environment) if((internalPath = operator []("LocalAppData")) == null || internalPath.length <= 0)
{
if((internalPath = operator []("UserProfile")) == null)
{
throw new IOException(avt.io.package.getResourceString("io"));
}
if(!internalPath.endsWith("\\")) internalPath = internalPath + '\\';
internalPath = internalPath + "AppData\\Local\\";
break label0;
}
if(!internalPath.endsWith("\\")) internalPath = internalPath + '\\';
}
String objectPath = toObjectPath(internalPath);
with(getRoot(objectPath), fileSystem) for(String subdirPath = objectPath.substring(path.length), int pos = 0; (pos = subdirPath.indexOf('/', pos + 1)) >= 0; )
{
String checkPath = subdirPath.substring(0, pos);
if(!isObjectExists(checkPath)) createDirectory(checkPath);
}
return objectPath;
}
public String toInternalPath(String objectPath) {
if(objectPath.startsWith("/")) objectPath = objectPath.substring(1);
return objectPath.replaceAll('/', '\\');
}
public String toObjectPath(String internalPath) {
if(!internalPath.startsWith("\\")) internalPath = '/' + internalPath;
return internalPath.replaceAll('\\', '/');
}
/* свойства платформы */
public int processorNumberOfCores { read = fldProcessorNumberOfCores }
public String operatingSystemName { read = "Microsoft Windows" }
public String operatingSystemVersion { read = fldOperatingSystemVersion }
public String lineSeparator { read = "\u000d\u000a" }
/* инициализация и финализация */
protected void afterConstruction() {
protectImportMemoryRegion();
initErrors();
try
{
SystemInfo sysinfo = new SystemInfo();
Kernel.getSystemInfo(sysinfo.getPointer());
KUSER_SHARED_DATA kusdata = (KUSER_SHARED_DATA) KUSER_SHARED_DATA.class.newStructAt(0x7ffe0000L);
fldProcessorNumberOfCores = sysinfo.dwNumberOfProcessors;
fldMinimumApplicationAddress = sysinfo.lpMinimumApplicationAddress;
fldMaximumApplicationAddress = sysinfo.lpMaximumApplicationAddress;
fldOperatingSystemVersion = (new StringBuilder()).append(kusdata.ntMajorVersion).append('.').append(kusdata.ntMinorVersion).append('.').append(kusdata.ntBuildNumber).toString();
sysinfo = null;
kusdata = null;
} catch(Exception exception) { }
initServices();
super.afterConstruction();
}
/* защищённые члены из Runtime */
protected boolean isCanonicalPointer(long ptr) {
long minAddress = fldMinimumApplicationAddress;
long maxAddress = fldMaximumApplicationAddress;
return (minAddress | maxAddress) != 0 ? ptr >= minAddress && ptr <= maxAddress : super.isCanonicalPointer(ptr);
}
}