diff --git a/.github/workflows/IKVM.yml b/.github/workflows/IKVM.yml index cd3600d873..fe523539b7 100644 --- a/.github/workflows/IKVM.yml +++ b/.github/workflows/IKVM.yml @@ -688,6 +688,12 @@ jobs: - test runs-on: ubuntu-latest steps: + - name: Free Disk Space (Linux) + uses: jlumbroso/free-disk-space@main + with: + dotnet: false + swap-storage: false + large-packages: false - name: Checkout Source uses: actions/checkout@v4 with: diff --git a/Directory.Build.props b/Directory.Build.props index 0b58f39e46..f6e8178d98 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,9 +7,9 @@ win-x64;win-x86;win-arm64;linux-x64;linux-arm;linux-arm64;linux-musl-x64;linux-musl-arm;linux-musl-arm64;osx-x64;osx-arm64 $(SupportedImageRuntimes) - + <_SupportedRuntimes>;$(SupportedRuntimes); <_EnabledRuntimes>;$(EnabledRuntimes); @@ -101,13 +101,13 @@ - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/IKVM.deps.targets b/IKVM.deps.targets index 54110ff19d..bd5f5123e3 100644 --- a/IKVM.deps.targets +++ b/IKVM.deps.targets @@ -17,7 +17,7 @@ - + diff --git a/IKVM.libs.targets b/IKVM.libs.targets index 6b9f179c94..c6bd06eb18 100644 --- a/IKVM.libs.targets +++ b/IKVM.libs.targets @@ -1,11 +1,11 @@ - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)src\libikvm\libikvm.clangproj" /> + - + - <__SupportedRuntimes>%(_ReferencedClangProjects.SupportedRuntimes) + <__SupportedRuntimes>%(DotNetClangProjectReference.SupportedRuntimes) <__SupportedRuntimes Condition=" '$(__SupportedRuntimes)' == '' ">$(_SupportedRuntimes) @@ -13,7 +13,7 @@ <_ReferencedClangProjectReference Remove="@(_ReferencedClangProjectReference)" /> - <_ReferencedClangProjectReference Include="@(_ReferencedClangProjects)"> + <_ReferencedClangProjectReference Include="@(DotNetClangProjectReference)"> %(__SupportedRuntimes.Identity) @@ -25,7 +25,7 @@ $(GetClangProjectReferencesDependsOn); - GetClangProjectReferencesByRuntime; + GetDotNetClangProjectReferencesByRuntime; diff --git a/IKVM.refs.targets b/IKVM.refs.targets index 76be36776a..4feb8a3acf 100644 --- a/IKVM.refs.targets +++ b/IKVM.refs.targets @@ -1,20 +1,187 @@ + + $(TargetsForTfmSpecificContentInPackage);GetIkvmLibsTfmSpecificContent;GetIkvmJavaTfmSpecificContent + $(TargetsForTfmSpecificDebugSymbolsInPackage);GetIkvmLibsTfmSpecificDebugSymbols;GetIkvmJavaTfmSpecificDebugSymbols + + true all + IkvmLibsItem - + true all + IkvmLibsItem - + + + + true + False + all + IkvmJavaItem + ref + + + false + False all + IkvmJavaItem + win + + + false + False + all + IkvmJavaItem + linux + + + false + False + all + IkvmJavaItem + osx + + + + ref\$(TargetFramework)\%(Filename)%(Extension) + + + runtimes\win\lib\$(TargetFramework)\%(Filename)%(Extension) + + + runtimes\win\lib\$(TargetFramework)\%(Filename).dll.config + + + runtimes\linux\lib\$(TargetFramework)\%(Filename)%(Extension) + + + runtimes\linux\lib\$(TargetFramework)\%(Filename).dll.config + + + runtimes\osx\lib\$(TargetFramework)\%(Filename)%(Extension) + + + runtimes\osx\lib\$(TargetFramework)\%(Filename).dll.config + + + lib\$(TargetFramework)\%(Filename)%(Extension) + + + lib\$(TargetFramework)\%(Filename).dll.config + + + + + + + + $(TargetFramework) + ref\$(TargetFramework)\%(Filename).pdb + + + $(TargetFramework) + runtimes\win\lib\$(TargetFramework)\%(Filename).pdb + + + $(TargetFramework) + runtimes\linux\lib\$(TargetFramework)\%(Filename).pdb + + + $(TargetFramework) + runtimes\osx\lib\$(TargetFramework)\%(Filename).pdb + + + $(TargetFramework) + lib\$(TargetFramework)\%(Filename).pdb + + + + + + + + PreserveNewest + refs\%(Filename)%(Extension) + + + PreserveNewest + runtimes\%(IkvmJavaItem.IkvmJavaRuntimeIdentifier)\lib\$(TargetFramework)\%(Filename)%(Extension) + %(Filename)%(Extension) + %(Filename)%(Extension) + + + PreserveNewest + runtimes\%(IkvmJavaItem.IkvmJavaRuntimeIdentifier)\lib\$(TargetFramework)\%(Filename).pdb + %(Filename).pdb + %(Filename).pdb + + + PreserveNewest + runtimes\%(IkvmJavaItem.IkvmJavaRuntimeIdentifier)\lib\$(TargetFramework)\%(Filename).dll.config + %(Filename).dll.config + %(Filename).dll.config + + + + + + + + ref\$(TargetFramework)\%(Filename)%(Extension) + + + runtimes\%(IkvmJavaItem.IkvmJavaRuntimeIdentifier)\lib\$(TargetFramework)\%(Filename)%(Extension) + + + runtimes\%(IkvmJavaItem.IkvmJavaRuntimeIdentifier)\lib\$(TargetFramework)\%(Filename).dll.config + + + lib\$(TargetFramework)\%(Filename)%(Extension) + + + lib\$(TargetFramework)\%(Filename).dll.config + + + + + + + + $(TargetFramework) + ref\$(TargetFramework)\%(Filename).pdb + + + $(TargetFramework) + runtimes\%(IkvmJavaItem.IkvmJavaRuntimeIdentifier)\lib\$(TargetFramework)\%(Filename).pdb + + + $(TargetFramework) + lib\$(TargetFramework)\%(Filename).pdb + + + + + + + + IKVM.Java + $(PackageVersion) + project + runtimes\%(IkvmJavaItem.IkvmJavaRuntimeIdentifier)\lib\$(TargetFramework)\IKVM.Java.dll + %(IkvmJavaItem.IkvmJavaRuntimeIdentifier) + + + + diff --git a/IKVM.sln b/IKVM.sln index cfec4f3b14..78db923940 100644 --- a/IKVM.sln +++ b/IKVM.sln @@ -281,10 +281,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IKVM.Image.runtime.win-x86" EndProject Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libawt", "src\libawt\libawt.clangproj", "{93B43F23-23B1-4968-951E-DC9A447D6F0E}" EndProject -Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libw2k_lsa_auth", "src\libw2k_lsa_auth\libw2k_lsa_auth.clangproj", "{78A745D7-706A-4B33-9D21-0EB7B5144C42}" -EndProject -Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libosxkrb5", "src\libosxkrb5\libosxkrb5.clangproj", "{F2969046-1672-4685-AE8D-53AED942DAE9}" -EndProject Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libosx", "src\libosx\libosx.clangproj", "{55F3F094-CE8E-4734-B14E-7DD5DFE7E4F3}" EndProject Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libmanagement", "src\libmanagement\libmanagement.clangproj", "{9CE0434D-A6B9-4708-850C-CA83E26851B2}" @@ -311,6 +307,16 @@ Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libjsoundds", "src\libjsoun EndProject Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libosxapp", "src\libosxapp\libosxapp.clangproj", "{0E068B20-9C99-45C5-8D94-A1FF9EDD6739}" EndProject +Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libsctp", "src\libsctp\libsctp.clangproj", "{D6D8258D-456A-4C72-ABA1-1CABC37D471F}" +EndProject +Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libj2pkcs11", "src\libj2pkcs11\libj2pkcs11.clangproj", "{8AFAE23F-DE5F-4B71-B9C3-C5B0E7705B96}" +EndProject +Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libjaas", "src\libjaas\libjaas.clangproj", "{2D69F3E3-D750-479B-975A-D8DE7FA3F7EE}" +EndProject +Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libjnf", "src\libjnf\libjnf.clangproj", "{606E173D-798D-4463-8EFD-0AD750831DD3}" +EndProject +Project("{6DE1C62B-E8D7-451A-8734-87EAEB46E35B}") = "libkrb5", "src\libkrb5\libkrb5.clangproj", "{78A745D7-706A-4B33-9D21-0EB7B5144C42}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -765,14 +771,6 @@ Global {93B43F23-23B1-4968-951E-DC9A447D6F0E}.Debug|Any CPU.Build.0 = Debug|Any CPU {93B43F23-23B1-4968-951E-DC9A447D6F0E}.Release|Any CPU.ActiveCfg = Release|Any CPU {93B43F23-23B1-4968-951E-DC9A447D6F0E}.Release|Any CPU.Build.0 = Release|Any CPU - {78A745D7-706A-4B33-9D21-0EB7B5144C42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {78A745D7-706A-4B33-9D21-0EB7B5144C42}.Debug|Any CPU.Build.0 = Debug|Any CPU - {78A745D7-706A-4B33-9D21-0EB7B5144C42}.Release|Any CPU.ActiveCfg = Release|Any CPU - {78A745D7-706A-4B33-9D21-0EB7B5144C42}.Release|Any CPU.Build.0 = Release|Any CPU - {F2969046-1672-4685-AE8D-53AED942DAE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F2969046-1672-4685-AE8D-53AED942DAE9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F2969046-1672-4685-AE8D-53AED942DAE9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F2969046-1672-4685-AE8D-53AED942DAE9}.Release|Any CPU.Build.0 = Release|Any CPU {55F3F094-CE8E-4734-B14E-7DD5DFE7E4F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {55F3F094-CE8E-4734-B14E-7DD5DFE7E4F3}.Debug|Any CPU.Build.0 = Debug|Any CPU {55F3F094-CE8E-4734-B14E-7DD5DFE7E4F3}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -825,6 +823,26 @@ Global {0E068B20-9C99-45C5-8D94-A1FF9EDD6739}.Debug|Any CPU.Build.0 = Debug|Any CPU {0E068B20-9C99-45C5-8D94-A1FF9EDD6739}.Release|Any CPU.ActiveCfg = Release|Any CPU {0E068B20-9C99-45C5-8D94-A1FF9EDD6739}.Release|Any CPU.Build.0 = Release|Any CPU + {D6D8258D-456A-4C72-ABA1-1CABC37D471F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6D8258D-456A-4C72-ABA1-1CABC37D471F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6D8258D-456A-4C72-ABA1-1CABC37D471F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6D8258D-456A-4C72-ABA1-1CABC37D471F}.Release|Any CPU.Build.0 = Release|Any CPU + {8AFAE23F-DE5F-4B71-B9C3-C5B0E7705B96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8AFAE23F-DE5F-4B71-B9C3-C5B0E7705B96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8AFAE23F-DE5F-4B71-B9C3-C5B0E7705B96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8AFAE23F-DE5F-4B71-B9C3-C5B0E7705B96}.Release|Any CPU.Build.0 = Release|Any CPU + {2D69F3E3-D750-479B-975A-D8DE7FA3F7EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D69F3E3-D750-479B-975A-D8DE7FA3F7EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D69F3E3-D750-479B-975A-D8DE7FA3F7EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D69F3E3-D750-479B-975A-D8DE7FA3F7EE}.Release|Any CPU.Build.0 = Release|Any CPU + {606E173D-798D-4463-8EFD-0AD750831DD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {606E173D-798D-4463-8EFD-0AD750831DD3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {606E173D-798D-4463-8EFD-0AD750831DD3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {606E173D-798D-4463-8EFD-0AD750831DD3}.Release|Any CPU.Build.0 = Release|Any CPU + {78A745D7-706A-4B33-9D21-0EB7B5144C42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {78A745D7-706A-4B33-9D21-0EB7B5144C42}.Debug|Any CPU.Build.0 = Debug|Any CPU + {78A745D7-706A-4B33-9D21-0EB7B5144C42}.Release|Any CPU.ActiveCfg = Release|Any CPU + {78A745D7-706A-4B33-9D21-0EB7B5144C42}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/doc/0.index.md b/doc/0.index.md index 110c43aff9..4fbfb54374 100644 --- a/doc/0.index.md +++ b/doc/0.index.md @@ -1,3 +1,12 @@ # Overview -Beginning of the IKVM documentation. Under Legacy there exists some old (very out of date) documentation previously maintained on SourceForge. This documentation cannot be trusted, but it is the best we have currently. +Beginning of the IKVM documentation. Under Legacy there exists some old (very out of date) documentation previously maintained on SourceForge. This documentation cannot be trusted but it is the best we have currently. + +# Topics +- [Usage](1.usage.md) +- [Initialization](2.init.md) + +# Tools + +- [ikvmc](tools/ikvm.md) +- [ikvmstub](tools/ikvmstub.md) diff --git a/doc/1.usage.md b/doc/1.usage.md new file mode 100644 index 0000000000..2a22cea41a --- /dev/null +++ b/doc/1.usage.md @@ -0,0 +1,90 @@ +# Usage + +## Installation + +IKVM can be added to a .NET SDK-style project by installing the IKVM nuget package provided on nuget.org. This can be done by either running `dotnet add package IKVM` or by manually editing your project file and inserting a `ProjectReference`. + +```xml + + + +``` + +Upon referencing the IKVM package the Java Base Class library should be immediately available to .NET code. + +```C# +using java.lang; +using java.util; + +public static void Main(string[] args) +{ + var set = new TreeSet(); +} + +``` + +Java classes are made available as .NET classes mapping the Java package name to the .NET namespace name. Java primitive types are exposed to .NET primitive types. + +## IkvmReference + +The `IkvmReference` functionality is an extension to the MSBuild system for SDK-style .NET projects that allows easy referencing of Java resources such as classes and JARs from .NET projects. The simplest case is just adding a JAR file to your .NET project: + +```xml + + + +``` + +When used `IkvmReference` will attempt to convert this JAR fie into a .NET assembly and provide Intellisense and build support. After IKVM has had a chance to convert the JAR file you should be able to simply access classes from the file using standard C# code. Java packages appear as normal namespaces. + +```C# +using myjavapackage; + +public static void Main(string[] args) +{ + MyJavaClass.javaMethod(); +} + +``` + +`IkvmReference` inherits the same capabilities as the [`Reference`](https://learn.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-items?view=vs-2022#reference) element. In fact the `IkvmReference` simply produces `Reference` entries in the background after converting the Java code to .NET code. In addition to this `IkvmReference` provides a number of metadata options to customize that conversion process. + +### `Include` +Include can be one of: +- path to a JAR file +- path to a directory +- an otherwise unimportant name (if `Compile` is used instead) + +### `AssemblyName`, `AssemblyVersion` and `AssemblyFileVersion` +IKVM attempts to infer the assembly name from the original Java code with the following steps: +- AssemblyName or AssemblyVersion being explicitely defined. +- Following the rules defined by the [`Automatic-Module-Name`](https://github.com/ikvmnet/ikvm#automatic-module-name-specification) specification. This is a specification that originated with JDK9. + +### KeyFile +Specifies the filename containing the cryptographic key. When this option is used, the compiler inserts the public key from the specified file into the assembly manifest and then signs the final assembly with the private key. + +### DelaySign +This option causes the compiler to reserve space in the output file so that a digital signature can be added later. Use DelaySign if you only want to place the public key in the assembly. The DelaySign option has no effect unless used with KeyFile. + +### Compile +A semi-colon separated list of Java class path items to compile into the assembly. By default this value is the Identity of the item, if the identity of the item is an existing JAR file or directory (not yet supported). MSBuild globs are supported to reference multiple JAR or .class files. + +### References +Optional semi-colon separated list of other `IkvmReference` identity values to specify as a reference to the current one. For example, if `foo.jar` depends on `bar.jar`, include both as `IkvmReference` items, but specify the identity of `bar.jar` on the References metadata of `foo.jar`. This is required if you intend to include two different JAR files to produce two different assemblies and the code of these items depends upon each other. + +```xml + + + + +``` + +In the above case we want to compile two different Java items into two different output assemblies. However, classes within `bar.jar` depend on classes within `foo.jar`. When `References` is present the build process can use this information to find classes from one in the other. The ultimate result is two output assemblies that that reference each other. One has to be built before the other, and so this information is required. + +For more information see [Compilation](2.compilation.md). + +### ClassLoader +A fully qualified classs name of the custom `ClassLoader` implementation to use as a delegation parent. Examples include `ikvm.runtime.AppDomainAssemblyClassLoader` and `ikvm.runtime.ClassPathAssemblyClassLoader`. + +For more information see [ClassLoaders](4.classloading.md). + diff --git a/doc/2.compilation.md b/doc/2.compilation.md new file mode 100644 index 0000000000..7643b4043f --- /dev/null +++ b/doc/2.compilation.md @@ -0,0 +1,7 @@ +# Compilation + +IKVM includes two methods by which to compile Java byte code into .NET code. Dynamic and static. Dynamic compilation happens at runtime when Java code loads Java classes files. For instance, using a `URLClassLoader` to load a JAR file at runtime. While static compilation happens before you run your .NET application. The base Java classes included with IKVM itself are an example of static compilation. + +## Dynamic Compilation + +## Static Compilation diff --git a/doc/3.classloading.md b/doc/3.classloading.md new file mode 100644 index 0000000000..d3c257f695 --- /dev/null +++ b/doc/3.classloading.md @@ -0,0 +1,14 @@ +# Class Loading + +Class loading is a complicated subject in Java, and IKVM makes it more so. In Java each class is expected to have an associated class loader by which it can resolve additional classes or resources at runtime. And each class loader has a clear hierarchy of parent class loaders by which it can dispatch requests. This is quite unlike .NET which has a more tangled runtime dependency model. + +Within the IKVM dynamic model, the traditional Java class loader design is respected. Thus you can create instances of `URLClassLoader` and others, parent them to each other, and expect it to work. Existing Java code should work without changes when loaded dynamically. + +Static compilation is a different matter. When static compiling your Java code to a .NET assembly all that remains at runtime is the .NET assembly. There is no Class Loader that caused that code to launch. It's just assemblies present in the `AppDomain` or `AssemblyLoadContext`. However, Java code needs to still be able to examine .NET types at runtime and find a `java.lang.ClassLoader` associated with the `java.lang.Class` types you are accessing. To accomplish this we introduce `ikvm.runtime.AssemblyClassLoader`. + +`ikvm.runtime.AssemblyClassLoader` serves as the fake class loader type assigned as the class loader of .NET types visible to Java. Each .NET assembly is given a unique `AssemblyClassLoader` instance. These class loaders however do not have a parent. Instead, they implement class and resource lookups using a delegation model, forwarding the request to the other assemblies referenced by the starting assembly. This takes the .NET assembly reference information and ensures that if one assembly depends on another assembly the seconds resources are accessible to the first. + +The short story of this is that when Java code is compiled statically into .NET assemblies, it no longer falls into the same class loader hierarchy as Java code loaded dynamically. At runtime, for this statically compiled code, there are no class paths and no class path order to be concerned about, etc. As long as the assemblies properly reference their dependencies they have access to resources of those dependencies. + +Class paths and class path order however remain important during static compilation itself. + diff --git a/doc/3.init.md b/doc/3.init.md new file mode 100644 index 0000000000..1a2af7908b --- /dev/null +++ b/doc/3.init.md @@ -0,0 +1,21 @@ +# Initialization + +IKVM contains the bulk of the open source OpenJDK project, especially it's base class library. This set of classes requires some upfront initialization. In a normal Java distribution this is initiated by the VM itself. However, since IKVM can be loaded as a .NET assembly, making the Java base class library immediately available to users, IKVM needs to initialize the base class library before any user access to the classes occurs. + +In addition to this IKVM distributes multiple versions of the OpenJDK base class library compiled for the three major operating systems: Windows, Linux and MacOS. Before access to the base class library happens the correct .NET assembly has to be loaded. + +## .NET + +Loading of the base class library assembly on .NET is relatively simple. The IKVM NuGet package distributes multiple assemblies within the `runtimes/{rid}/lib/{tfm}` directory. The .NET SDK is capable of configuring your .NET application which references IKVM to either load the correct assembly at runtime in the case of Framework-dependent builds or to only include the required assembly in the case of Framework-independent builds). This is done by writing the correct entries into your `.deps.json` file. + +In addition to that we distribute a reference assembly in the NuGet package which the compiler uses to build your code irrespective of the final assembly or assemblies that are distributed. + +Initialization of the base class library happens when the `IKVM.Runtime` assembly is loaded. Since the base class library depends upon `IKVM.Runtime`, `IKVM.Runtime` has a chance to initiate initialization before user code calls or accesses the classes in the base class library. + +## .NET Framework + +The situation for .NET Framework is different. Framework supports no mechanism similar to `.deps.json` nor does it include any other method by which to alter how the runtime locates assemblies BEFORE an attempt by user code is made to load that assembly on the basis of the running operating system. This isn't usually a big deal as Framework-independent builds aren't something that users often do: Windows is usually assumed to be the target OS. However, Mono does exist. + +IKVM cannot solve this issue alone without intervention from Mono. There is no way to cleanly ensure one variant of an assembly is loaded when that assembly's loading can be driven by other unknown assemblies that depend upon it. So, until then, we leave the issue unresolved. + +When building or publishing for .NET Framework without a RID, the Windows version of `IKVM.Java.dll` is made as output. The Linux and OS X variants are included within `runtimes/{rid}/lib/{tfm}` but Mono has no way to know this. However, you can still do a RID-specific build for .NET Framework. When doing so, the proper variant is included instead. diff --git a/doc/tools/ikvmc.md b/doc/tools/ikvmc.md new file mode 100644 index 0000000000..c50152434f --- /dev/null +++ b/doc/tools/ikvmc.md @@ -0,0 +1,5 @@ +# ikvmc Tool + +> The `ikvmc` tool is considered an advanced option and it is recommended that new projects use the `IkvmReference` for the .NET SDK for most use cases. + +See: [ikvmc](legacy/tools/ikvmc.md) diff --git a/doc/tools/ikvmstub.md b/doc/tools/ikvmstub.md new file mode 100644 index 0000000000..0c17fd3640 --- /dev/null +++ b/doc/tools/ikvmstub.md @@ -0,0 +1,5 @@ +# ikvmstub Tool + +The `ikvmstub` tool generates Java stubs from .NET assemblies. + +See: [ikvmc](legacy/tools/ikvmstub.md) diff --git a/global.json b/global.json index 6df460d8b5..11579458ef 100644 --- a/global.json +++ b/global.json @@ -4,7 +4,7 @@ "rollForward": "latestFeature" }, "msbuild-sdks": { - "Microsoft.Build.NoTargets": "3.7.0", - "IKVM.Clang.Sdk": "0.2.13" + "Microsoft.Build.NoTargets": "3.7.56", + "IKVM.Clang.Sdk": "0.2.17" } } diff --git a/openjdk b/openjdk index e58c8a60e3..05400db82e 160000 --- a/openjdk +++ b/openjdk @@ -1 +1 @@ -Subproject commit e58c8a60e38ef345be29ff8277dcac903044797a +Subproject commit 05400db82ed4aa88c36e569d34e3bf01622901c3 diff --git a/openjdk.props b/openjdk.props index 81a4929efb..076664ded0 100644 --- a/openjdk.props +++ b/openjdk.props @@ -1,26 +1,15 @@ - %(Identity) - - - - - - - - - - @@ -45,8 +34,6 @@ - - @@ -73,716 +60,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - @@ -794,8 +102,6 @@ - - @@ -821,131 +127,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -953,10 +135,237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1113,355 +522,74 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + @@ -1469,184 +597,90 @@ - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -1670,7 +704,7 @@ - + diff --git a/src/IKVM.ByteCode.Tests/IKVM.ByteCode.Tests.csproj b/src/IKVM.ByteCode.Tests/IKVM.ByteCode.Tests.csproj index 4974c71ffd..6f12b8bca4 100644 --- a/src/IKVM.ByteCode.Tests/IKVM.ByteCode.Tests.csproj +++ b/src/IKVM.ByteCode.Tests/IKVM.ByteCode.Tests.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/src/IKVM.ConsoleApp/IKVM.ConsoleApp.csproj b/src/IKVM.ConsoleApp/IKVM.ConsoleApp.csproj index 37c5897649..f94cf094a1 100644 --- a/src/IKVM.ConsoleApp/IKVM.ConsoleApp.csproj +++ b/src/IKVM.ConsoleApp/IKVM.ConsoleApp.csproj @@ -1,7 +1,11 @@ - + + + + + Exe - net6.0;net481; + ;net481;net6.0;net8.0 11 x64 @@ -9,11 +13,12 @@ - - - + + + + diff --git a/src/IKVM.ConsoleApp/Program.cs b/src/IKVM.ConsoleApp/Program.cs index 087f8ae107..9d9df4f177 100644 --- a/src/IKVM.ConsoleApp/Program.cs +++ b/src/IKVM.ConsoleApp/Program.cs @@ -1,30 +1,17 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; + +using java.lang; namespace IKVM.ConsoleApp { + public static class Program { public static void Main(string[] args) { - Foo(); - } - - public static void Foo() - { - new Bar(); - } - - class Bar - { - - public Bar() - { - for (int i = 0; i < 19383; i++) - System.Console.WriteLine(java.net.InetAddress.getLocalHost().getHostName()); - } - + Thread.sleep(5000); + var s = new java.io.File("/mnt/c/dev/ikvm").getCanonicalPath(); } } diff --git a/src/IKVM.Image-bin/IKVM.Image-bin.csproj b/src/IKVM.Image-bin/IKVM.Image-bin.csproj index 07e7ceabcb..b62e7271b8 100644 --- a/src/IKVM.Image-bin/IKVM.Image-bin.csproj +++ b/src/IKVM.Image-bin/IKVM.Image-bin.csproj @@ -8,29 +8,32 @@ - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libjvm\libjvm.clangproj " /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libfdlibm\libfdlibm.clangproj " /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libverify\libverify.clangproj" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libiava\libiava.clangproj" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libnet\libnet.clangproj" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libnio\libnio.clangproj" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libunpack\libunpack.clangproj" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libsunec\libsunec.clangproj" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libsunmscapi\libsunmscapi.clangproj" SupportedRuntimes="win-x64;win-x86;win-arm64" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libawt\libawt.clangproj" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libmanagement\libmanagement.clangproj" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libw2k_lsa_auth\libw2k_lsa_auth.clangproj" SupportedRuntimes="win-x64;win-x86;win-arm64" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libosxapp\libosxapp.clangproj" SupportedRuntimes="osx-x64;osx-arm64" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libosx\libosx.clangproj" SupportedRuntimes="osx-x64;osx-arm64" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libosxkrb5\libosxkrb5.clangproj" SupportedRuntimes="osx-x64;osx-arm64" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libjsound\libjsound.clangproj" SupportedRuntimes="win-x64;win-x86;win-arm64;linux-arm;linux-arm64;linux-x64;linux-musl-arm;linux-musl-arm64;linux-musl-x64" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libjsoundds\libjsoundds.clangproj" SupportedRuntimes="win-x64;win-x86;win-arm64" /> - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libjsoundalsa\libjsoundalsa.clangproj" SupportedRuntimes="linux-arm;linux-arm64;linux-x64;linux-musl-arm;linux-musl-arm64;linux-musl-x64" /> + + + + + + + + + + + + + + + + + + + + + - + - <__SupportedRuntimes>%(_ReferencedClangProjects.SupportedRuntimes) + <__SupportedRuntimes>%(DotNetClangProjectReference.SupportedRuntimes) <__SupportedRuntimes Condition=" '$(__SupportedRuntimes)' == '' ">$(_SupportedRuntimes) @@ -38,7 +41,7 @@ <_ReferencedClangProjectReference Remove="@(_ReferencedClangProjectReference)" /> - <_ReferencedClangProjectReference Include="@(_ReferencedClangProjects)"> + <_ReferencedClangProjectReference Include="@(DotNetClangProjectReference)"> %(__SupportedRuntimes.Identity) @@ -50,7 +53,7 @@ $(GetClangProjectReferencesDependsOn); - GetClangProjectReferencesByRuntime; + GetDotNetClangProjectReferencesByRuntime; diff --git a/src/IKVM.Image.JDK-bin/IKVM.Image.JDK-bin.csproj b/src/IKVM.Image.JDK-bin/IKVM.Image.JDK-bin.csproj index 8a23bf79ab..3d0cbd503f 100644 --- a/src/IKVM.Image.JDK-bin/IKVM.Image.JDK-bin.csproj +++ b/src/IKVM.Image.JDK-bin/IKVM.Image.JDK-bin.csproj @@ -4,6 +4,7 @@ net472;net6.0;net8.0 $(_SupportedImageRuntimes) false + true diff --git a/src/IKVM.Image.JRE-bin/IKVM.Image.JRE-bin.csproj b/src/IKVM.Image.JRE-bin/IKVM.Image.JRE-bin.csproj index 344069e86a..9cfc373074 100644 --- a/src/IKVM.Image.JRE-bin/IKVM.Image.JRE-bin.csproj +++ b/src/IKVM.Image.JRE-bin/IKVM.Image.JRE-bin.csproj @@ -4,6 +4,7 @@ net472;net6.0;net8.0 $(_SupportedImageRuntimes) false + true diff --git a/src/IKVM.JTReg.TestAdapter.Core/IKVM.JTReg.TestAdapter.Core.csproj b/src/IKVM.JTReg.TestAdapter.Core/IKVM.JTReg.TestAdapter.Core.csproj index bea02ce504..806f93805d 100644 --- a/src/IKVM.JTReg.TestAdapter.Core/IKVM.JTReg.TestAdapter.Core.csproj +++ b/src/IKVM.JTReg.TestAdapter.Core/IKVM.JTReg.TestAdapter.Core.csproj @@ -2,6 +2,7 @@ + @@ -34,9 +35,10 @@ + + + - - diff --git a/src/IKVM.JTReg.TestAdapter.Core/IkvmTraceServer.cs b/src/IKVM.JTReg.TestAdapter.Core/IkvmTraceServer.cs index 5c92c029dc..71229dcae8 100644 --- a/src/IKVM.JTReg.TestAdapter.Core/IkvmTraceServer.cs +++ b/src/IKVM.JTReg.TestAdapter.Core/IkvmTraceServer.cs @@ -3,8 +3,8 @@ using System.IO.Pipelines; using System.Net; using System.Net.Sockets; -using System.Runtime.InteropServices; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; namespace IKVM.JTReg.TestAdapter.Core @@ -33,10 +33,11 @@ public IkvmTraceServer(IJTRegExecutionContext context) /// /// Starts listening for signals. /// - public void Start() + public void Start(CancellationToken cancellationToken = default) { lock (syncRoot) { + cancellationToken.Register(() => Stop()); listener = new TcpListener(new IPEndPoint(IPAddress.Loopback, 0)); listener.Start(); listener.BeginAcceptSocket(OnAcceptSocket, null); diff --git a/src/IKVM.JTReg.TestAdapter.Core/JTRegTestManager.cs b/src/IKVM.JTReg.TestAdapter.Core/JTRegTestManager.cs index a7fb702acb..7ac6a145dd 100644 --- a/src/IKVM.JTReg.TestAdapter.Core/JTRegTestManager.cs +++ b/src/IKVM.JTReg.TestAdapter.Core/JTRegTestManager.cs @@ -18,7 +18,9 @@ namespace IKVM.JTReg.TestAdapter.Core public class JTRegTestManager { - public const string URI = "executor://ikvmjtregtestadapter/v1"; + public static readonly JTRegTestManager Instance = new(); + + public const string URI = "executor://jtregtestadapter/v1"; internal static readonly string JTREG_LIB = Path.Combine(Path.GetDirectoryName(typeof(JTRegTestManager).Assembly.Location), "jtreg"); @@ -217,6 +219,9 @@ internal void DiscoverTestsImpl(string source, string[] testDirs, IJTRegDiscover { foreach (var testCase in (IEnumerable)Util.GetTestCases(source, testManager, testSuite, context.Options.PartitionCount)) { + if (cancellationToken.IsCancellationRequested) + return; + context.SendTestCase(testCase); testCount++; } @@ -255,7 +260,7 @@ public void RunTests(string source, List tests, IJTRegExecutionCo if (context.CanAttachDebuggerToProcess && Debugger.IsAttached) { debug = new IkvmTraceServer(context); - debug.Start(); + debug.Start(cancellationToken); } source = Path.GetFullPath(source); diff --git a/src/IKVM.JTReg.TestAdapter.Core/JTRegTestManagerProxy.cs b/src/IKVM.JTReg.TestAdapter.Core/JTRegTestManagerProxy.cs deleted file mode 100644 index ee007eb077..0000000000 --- a/src/IKVM.JTReg.TestAdapter.Core/JTRegTestManagerProxy.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace IKVM.JTReg.TestAdapter.Core -{ - - /// - /// Proxy to a instance that can be marshalled by reference. - /// - public class JTRegTestManagerProxy : -#if NETFRAMEWORK - MarshalByRefObject -#else - object -#endif - { - - readonly JTRegTestManager real = new JTRegTestManager(); - - /// - /// Initiates a discovery of the tests of the given source. - /// - /// - /// - /// - public void DiscoverTests(string source, IJTRegDiscoveryContext context, CancellationTokenProxy cancellationTokenProxy) - { - var ctp = new CancellationTokenCancellationProxy(); - - try - { - cancellationTokenProxy.Register(ctp); - real.DiscoverTests(source, context, ctp.Token); - } - finally - { - cancellationTokenProxy.Unregister(ctp); - } - } - - /// - /// Initiates a run of the given sources, optionally with the specified tests. - /// - /// - /// - /// - public void RunTests(string source, IJTRegExecutionContext context, CancellationTokenProxy cancellationTokenProxy) - { - RunTests(source, null, context, cancellationTokenProxy); - } - - /// - /// Initiates a run of the given source, optionally with the specified tests. - /// - /// - /// - /// - /// - public void RunTests(string source, List tests, IJTRegExecutionContext context, CancellationTokenProxy cancellationTokenProxy) - { - if (source is null) - throw new ArgumentNullException(nameof(source)); - if (context is null) - throw new ArgumentNullException(nameof(context)); - if (cancellationTokenProxy is null) - throw new ArgumentNullException(nameof(cancellationTokenProxy)); - - var ctp = new CancellationTokenCancellationProxy(); - - try - { - cancellationTokenProxy.Register(ctp); - real.RunTests(source, tests, context, ctp.Token); - } - finally - { - cancellationTokenProxy.Unregister(ctp); - } - } - -#if NETFRAMEWORK - - public override object InitializeLifetimeService() - { - return null; - } - -#endif - - } - -} diff --git a/src/IKVM.JTReg.TestAdapter.Tests/IKVM.JTReg.TestAdapter.Tests.csproj b/src/IKVM.JTReg.TestAdapter.Tests/IKVM.JTReg.TestAdapter.Tests.csproj index c7135f9b55..27319cfb2e 100644 --- a/src/IKVM.JTReg.TestAdapter.Tests/IKVM.JTReg.TestAdapter.Tests.csproj +++ b/src/IKVM.JTReg.TestAdapter.Tests/IKVM.JTReg.TestAdapter.Tests.csproj @@ -2,6 +2,7 @@ + @@ -13,13 +14,12 @@ - - + - + @@ -35,9 +35,16 @@ + + + + + + + + - - + diff --git a/src/IKVM.JTReg.TestAdapter.Tests/JTRegTestAdapterTests.cs b/src/IKVM.JTReg.TestAdapter.Tests/JTRegTestAdapterTests.cs index 9285f08ece..fa1f2c9e88 100644 --- a/src/IKVM.JTReg.TestAdapter.Tests/JTRegTestAdapterTests.cs +++ b/src/IKVM.JTReg.TestAdapter.Tests/JTRegTestAdapterTests.cs @@ -1,65 +1,63 @@ -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Threading; +//using System.Collections.Concurrent; +//using System.Collections.Generic; +//using System.IO; +//using System.Threading; -using FluentAssertions; +//using FluentAssertions; -using IKVM.JTReg.TestAdapter.Core; +//using IKVM.JTReg.TestAdapter.Core; -using javax.xml.bind; +//using Microsoft.VisualStudio.TestTools.UnitTesting; -using Microsoft.VisualStudio.TestTools.UnitTesting; +//using Moq; -using Moq; +//namespace IKVM.JTReg.TestAdapter.Tests +//{ -namespace IKVM.JTReg.TestAdapter.Tests -{ +// [TestClass] +// public class JTRegTestAdapterTests +// { - [TestClass] - public class JTRegTestAdapterTests - { +// public TestContext TestContext { get; set; } - public TestContext TestContext { get; set; } +// [TestMethod] +// public void CanDiscoverTests() +// { +// var testCases = new List(); +// var messages = new ConcurrentBag<(JTRegTestMessageLevel, string)>(); - [TestMethod] - public void CanDiscoverTests() - { - var testCases = new List(); - var messages = new ConcurrentBag<(JTRegTestMessageLevel, string)>(); +// var discoveryContext = new Mock(); +// discoveryContext.Setup(x => x.Options).Returns(new JTRegTestOptions()); +// discoveryContext.Setup(x => x.SendMessage(It.IsAny(), It.IsAny())).Callback((JTRegTestMessageLevel l, string m) => messages.Add((l, m))); +// discoveryContext.Setup(x => x.SendTestCase(It.IsAny())).Callback((JTRegTestCase x) => testCases.Add(x)); - var discoveryContext = new Mock(); - discoveryContext.Setup(x => x.Options).Returns(new JTRegTestOptions()); - discoveryContext.Setup(x => x.SendMessage(It.IsAny(), It.IsAny())).Callback((JTRegTestMessageLevel l, string m) => messages.Add((l, m))); - discoveryContext.Setup(x => x.SendTestCase(It.IsAny())).Callback((JTRegTestCase x) => testCases.Add(x)); +// var testManager = new JTRegTestManager(); +// var baseDir = Path.GetDirectoryName(typeof(JTRegTestAdapterTests).Assembly.Location); +// var testDir = Path.Combine(baseDir, "root"); +// testManager.DiscoverTestsImpl(Path.Combine(baseDir, "fake"), new[] { testDir }, discoveryContext.Object, CancellationToken.None); +// testCases.Should().HaveCountGreaterThanOrEqualTo(1); +// } - var testManager = new JTRegTestManager(); - var baseDir = Path.GetDirectoryName(typeof(JTRegTestAdapterTests).Assembly.Location); - var testDir = Path.Combine(baseDir, "root"); - testManager.DiscoverTestsImpl(Path.Combine(baseDir, "fake"), new[] { testDir }, discoveryContext.Object, CancellationToken.None); - testCases.Should().HaveCountGreaterThanOrEqualTo(1); - } +// [TestMethod] +// public void CanExecuteTests() +// { +// var testResults = new ConcurrentBag(); +// var messages = new ConcurrentBag<(JTRegTestMessageLevel, string)>(); - [TestMethod] - public void CanExecuteTests() - { - var testResults = new ConcurrentBag(); - var messages = new ConcurrentBag<(JTRegTestMessageLevel, string)>(); +// var executionContext = new Mock(); +// executionContext.Setup(x => x.Options).Returns(new JTRegTestOptions()); +// executionContext.Setup(x => x.SendMessage(It.IsAny(), It.IsAny())).Callback((JTRegTestMessageLevel l, string m) => messages.Add((l, m))); +// executionContext.Setup(x => x.TestRunDirectory).Returns(TestContext.TestRunDirectory); +// executionContext.Setup(x => x.FilterTestCase(It.IsAny())).Returns(true); +// executionContext.Setup(x => x.RecordResult(It.IsAny())).Callback((JTRegTestResult x) => testResults.Add(x)); - var executionContext = new Mock(); - executionContext.Setup(x => x.Options).Returns(new JTRegTestOptions()); - executionContext.Setup(x => x.SendMessage(It.IsAny(), It.IsAny())).Callback((JTRegTestMessageLevel l, string m) => messages.Add((l, m))); - executionContext.Setup(x => x.TestRunDirectory).Returns(TestContext.TestRunDirectory); - executionContext.Setup(x => x.FilterTestCase(It.IsAny())).Returns(true); - executionContext.Setup(x => x.RecordResult(It.IsAny())).Callback((JTRegTestResult x) => testResults.Add(x)); +// var testManager = new JTRegTestManager(); +// var baseDir = Path.GetDirectoryName(typeof(JTRegTestAdapterTests).Assembly.Location); +// var testDir = Path.Combine(baseDir, "root"); +// testManager.RunTestsImpl(Path.Combine(baseDir, "fake"), new[] { testDir }, null, executionContext.Object, null, CancellationToken.None); +// testResults.Should().HaveCountGreaterThanOrEqualTo(1); +// } - var testManager = new JTRegTestManager(); - var baseDir = Path.GetDirectoryName(typeof(JTRegTestAdapterTests).Assembly.Location); - var testDir = Path.Combine(baseDir, "root"); - testManager.RunTestsImpl(Path.Combine(baseDir, "fake"), new[] { testDir }, null, executionContext.Object, null, CancellationToken.None); - testResults.Should().HaveCountGreaterThanOrEqualTo(1); - } +// } - } - -} +//} diff --git a/src/IKVM.JTReg.TestAdapter.Tests/Properties/AssemblyInfo.cs b/src/IKVM.JTReg.TestAdapter.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..93690a2bbf --- /dev/null +++ b/src/IKVM.JTReg.TestAdapter.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using IKVM.JTReg.TestAdapter; + +[assembly: JTRegTestSuite("root")] diff --git a/src/IKVM.JTReg.TestAdapter/CompilerServices/ModuleInitializerAttribute.cs b/src/IKVM.JTReg.TestAdapter/CompilerServices/ModuleInitializerAttribute.cs new file mode 100644 index 0000000000..7245e78508 --- /dev/null +++ b/src/IKVM.JTReg.TestAdapter/CompilerServices/ModuleInitializerAttribute.cs @@ -0,0 +1,16 @@ +#if NETFRAMEWORK + +namespace System.Runtime.CompilerServices +{ + + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + sealed class ModuleInitializerAttribute : Attribute + { + + + + } + +} + +#endif diff --git a/src/IKVM.JTReg.TestAdapter/IKVM.JTReg.TestAdapter.csproj b/src/IKVM.JTReg.TestAdapter/IKVM.JTReg.TestAdapter.csproj index 6e196a8afc..8f33e17aba 100644 --- a/src/IKVM.JTReg.TestAdapter/IKVM.JTReg.TestAdapter.csproj +++ b/src/IKVM.JTReg.TestAdapter/IKVM.JTReg.TestAdapter.csproj @@ -1,11 +1,18 @@ - + + + + + net472;net6.0;net8.0 false - + + + + @@ -14,4 +21,8 @@ + + + + diff --git a/src/IKVM.JTReg.TestAdapter/JTRegExecutionContextProxy.cs b/src/IKVM.JTReg.TestAdapter/JTRegExecutionContextProxy.cs index 65429cab49..e95fba18b5 100644 --- a/src/IKVM.JTReg.TestAdapter/JTRegExecutionContextProxy.cs +++ b/src/IKVM.JTReg.TestAdapter/JTRegExecutionContextProxy.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using IKVM.JTReg.TestAdapter.Core; @@ -13,11 +12,7 @@ namespace IKVM.JTReg.TestAdapter /// /// Proxies the interface to the Visual Studio test adapter. /// - class JTRegExecutionContextProxy : -#if NETFRAMEWORK - MarshalByRefObject, -#endif - IJTRegExecutionContext + class JTRegExecutionContextProxy : IJTRegExecutionContext { static readonly Dictionary properties = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -101,15 +96,6 @@ public void SendMessage(JTRegTestMessageLevel level, string message) frameworkHandle.SendMessage(JTRegProxyUtil.Convert(level), message); } -#if NETFRAMEWORK - - public override object InitializeLifetimeService() - { - return null; - } - -#endif - } } \ No newline at end of file diff --git a/src/IKVM.JTReg.TestAdapter/JTRegInit.cs b/src/IKVM.JTReg.TestAdapter/JTRegInit.cs new file mode 100644 index 0000000000..ca91f1d55b --- /dev/null +++ b/src/IKVM.JTReg.TestAdapter/JTRegInit.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace IKVM.JTReg.TestAdapter +{ + + static class JTRegInit + { + + /// + /// Initializes the module. We install a assembly resolver that attempts to locate assemblies in the same directory as the adapter. + /// + [ModuleInitializer] + public static void Init() + { +#if NETFRAMEWORK + AppDomain.CurrentDomain.AssemblyResolve += (s, a) => + { + var l = typeof(JTRegInit).Assembly.Location; + if (string.IsNullOrWhiteSpace(l)) + return null; + + var n = new AssemblyName(a.Name); + var p = Path.Combine(Path.GetDirectoryName(l), n.Name + ".dll"); + if (File.Exists(p) == false) + return null; + + try + { + return Assembly.LoadFrom(p); + } + catch + { + // ignore failure to load + } + + return null; + }; +#endif + } + + } + +} diff --git a/src/IKVM.JTReg.TestAdapter/JTRegProxyUtil.cs b/src/IKVM.JTReg.TestAdapter/JTRegProxyUtil.cs index 86dacf8eb2..cf53650a83 100644 --- a/src/IKVM.JTReg.TestAdapter/JTRegProxyUtil.cs +++ b/src/IKVM.JTReg.TestAdapter/JTRegProxyUtil.cs @@ -89,7 +89,7 @@ public static TestResult Convert(JTRegTestResult rslt) foreach (var message in rslt.Messages) r.Messages.Add(new TestResultMessage(Convert(message.Category), message.Text)); - var s = new AttachmentSet(new Uri(JTRegTestManager.URI), "IkvmJtRegTestAdapter"); + var s = new AttachmentSet(new Uri(JTRegTestManager.URI), "JTRegTestAdapter"); r.Attachments.Add(s); foreach (var attachment in rslt.Attachments) s.Attachments.Add(UriDataAttachment.CreateFrom(attachment.Path, attachment.Name)); diff --git a/src/IKVM.JTReg.TestAdapter/JTRegTestDiscoverer.cs b/src/IKVM.JTReg.TestAdapter/JTRegTestDiscoverer.cs index 83893ea461..c4f9a52fdc 100644 --- a/src/IKVM.JTReg.TestAdapter/JTRegTestDiscoverer.cs +++ b/src/IKVM.JTReg.TestAdapter/JTRegTestDiscoverer.cs @@ -12,13 +12,36 @@ namespace IKVM.JTReg.TestAdapter { + /// + /// Implements the portion of the adapter. + /// [DefaultExecutorUri(JTRegTestManager.URI)] [FileExtension(".dll")] [FileExtension(".exe")] public class JTRegTestDiscoverer : ITestDiscoverer { + /// + /// Discovers the tests available from the provided sources. + /// + /// + /// + /// + /// public void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink) + { + DiscoverTests(sources, discoveryContext, logger, discoverySink, CancellationToken.None); + } + + /// + /// Discovers the tests available from the provided sources. + /// + /// + /// + /// + /// + /// + public void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink, CancellationToken cancellationToken) { foreach (var source in sources) { @@ -27,9 +50,7 @@ public void DiscoverTests(IEnumerable sources, IDiscoveryContext discove try { - // setup isolation host for source - var proxy = JTRegTestIsolationHost.Instance.CreateManager(); - proxy.DiscoverTests(source, new JTRegDiscoveryContextProxy(discoveryContext, logger, discoverySink), new CancellationTokenProxy(CancellationToken.None)); + JTRegTestManager.Instance.DiscoverTests(source, new JTRegDiscoveryContextProxy(discoveryContext, logger, discoverySink), cancellationToken); } catch (Exception e) { diff --git a/src/IKVM.JTReg.TestAdapter/JTRegTestExecutor.cs b/src/IKVM.JTReg.TestAdapter/JTRegTestExecutor.cs index 673d5e9775..bc574da48d 100644 --- a/src/IKVM.JTReg.TestAdapter/JTRegTestExecutor.cs +++ b/src/IKVM.JTReg.TestAdapter/JTRegTestExecutor.cs @@ -28,15 +28,23 @@ public class JTRegTestExecutor : ITestExecutor public void RunTests(IEnumerable tests, IRunContext runContext, IFrameworkHandle frameworkHandle) { cts = new CancellationTokenSource(); - var ctp = new CancellationTokenProxy(cts.Token); + RunTests(tests, runContext, frameworkHandle, cts.Token); + } + /// + /// Executes the given test cases. + /// + /// + /// + /// + public void RunTests(IEnumerable tests, IRunContext runContext, IFrameworkHandle frameworkHandle, CancellationToken cancellationToken) + { foreach (var group in tests.GroupBy(i => i.Source)) { - if (cts.Token.IsCancellationRequested) + if (cancellationToken.IsCancellationRequested) break; - var proxy = JTRegTestIsolationHost.Instance.CreateManager(); - proxy.RunTests(group.Key, JTRegProxyUtil.Convert(group).ToList(), new JTRegExecutionContextProxy(runContext, frameworkHandle), ctp); + JTRegTestManager.Instance.RunTests(group.Key, JTRegProxyUtil.Convert(group).ToList(), new JTRegExecutionContextProxy(runContext, frameworkHandle), cancellationToken); } } @@ -49,15 +57,23 @@ public void RunTests(IEnumerable tests, IRunContext runContext, IFrame public void RunTests(IEnumerable sources, IRunContext runContext, IFrameworkHandle frameworkHandle) { cts = new CancellationTokenSource(); - var ctp = new CancellationTokenProxy(cts.Token); + RunTests(sources, runContext, frameworkHandle, cts.Token); + } + /// + /// Executes the test cases in the given sources. + /// + /// + /// + /// + public void RunTests(IEnumerable sources, IRunContext runContext, IFrameworkHandle frameworkHandle, CancellationToken cancellationToken) + { foreach (var source in sources) { - if (cts.Token.IsCancellationRequested) + if (cancellationToken.IsCancellationRequested) break; - var proxy = JTRegTestIsolationHost.Instance.CreateManager(); - proxy.RunTests(source, new JTRegExecutionContextProxy(runContext, frameworkHandle), ctp); + JTRegTestManager.Instance.RunTests(source, null, new JTRegExecutionContextProxy(runContext, frameworkHandle), cancellationToken); } } @@ -68,6 +84,7 @@ public void Cancel() { cts?.Cancel(); } + } } diff --git a/src/IKVM.JTReg.TestAdapter/JTRegTestIsolationHost.cs b/src/IKVM.JTReg.TestAdapter/JTRegTestIsolationHost.cs deleted file mode 100644 index 0aa1a0c748..0000000000 --- a/src/IKVM.JTReg.TestAdapter/JTRegTestIsolationHost.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.IO; - -using IKVM.JTReg.TestAdapter.Core; - -namespace IKVM.JTReg.TestAdapter -{ - - /// - /// Manages the isolation requirements for the services of the JTReg test adapter. - /// - class JTRegTestIsolationHost : IDisposable - { - - public static readonly JTRegTestIsolationHost Instance = new(); - -#if NETFRAMEWORK - AppDomain appdomain; -#endif - - /// - /// Initializes the static instance. - /// - public JTRegTestIsolationHost() - { -#if NETFRAMEWORK - var path = typeof(JTRegTestIsolationHost).Assembly.Location; - var conf = Path.ChangeExtension(path, ".dll.config"); - - var setup = new AppDomainSetup(); - setup.ApplicationBase = Path.GetDirectoryName(path); - setup.ConfigurationFile = conf; - appdomain = AppDomain.CreateDomain("JTRegTestAdapter", null, setup); -#endif - } - - /// - /// Creates a new for the given isolation host. - /// - /// - public JTRegTestManagerProxy CreateManager() - { -#if NETFRAMEWORK - return (JTRegTestManagerProxy)appdomain.CreateInstanceAndUnwrap(typeof(JTRegTestManagerProxy).Assembly.FullName, typeof(JTRegTestManagerProxy).FullName); -#else - return new JTRegTestManagerProxy(); -#endif - } - - /// - /// Disposes of the isolation host. - /// - public void Dispose() - { -#if NETFRAMEWORK - if (appdomain != null) - { - try - { - AppDomain.Unload(appdomain); - } - catch - { - // ignore any exceptions during unload - } - - appdomain = null; - } -#endif - } - - } - -} diff --git a/src/IKVM.JTReg.TestAdapter/JTRegTestOptionsExtensions.cs b/src/IKVM.JTReg.TestAdapter/JTRegTestOptionsExtensions.cs index fcd11cb57c..c364b4ea37 100644 --- a/src/IKVM.JTReg.TestAdapter/JTRegTestOptionsExtensions.cs +++ b/src/IKVM.JTReg.TestAdapter/JTRegTestOptionsExtensions.cs @@ -8,6 +8,9 @@ namespace IKVM.JTReg.TestAdapter { + /// + /// Provides options from a RunSettings file. + /// public static class JTRegTestOptionsExtensions { diff --git a/src/IKVM.JTReg.TestAdapter/TestingPlatform/JTRegBridgedTestFramework.cs b/src/IKVM.JTReg.TestAdapter/TestingPlatform/JTRegBridgedTestFramework.cs new file mode 100644 index 0000000000..7a5f5f8d82 --- /dev/null +++ b/src/IKVM.JTReg.TestAdapter/TestingPlatform/JTRegBridgedTestFramework.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.Testing.Extensions.VSTestBridge; +using Microsoft.Testing.Extensions.VSTestBridge.Requests; +using Microsoft.Testing.Platform.Capabilities.TestFramework; +using Microsoft.Testing.Platform.Messages; + +namespace IKVM.JTReg.TestAdapter.TestingPlatform +{ + + sealed class JTRegBridgedTestFramework : SynchronizedSingleSessionVSTestBridgedTestFramework + { + + /// + /// Initializes a new instance. + /// + /// + /// + /// + /// + public JTRegBridgedTestFramework(JTRegExtension extension, Func> getTestAssemblies, IServiceProvider serviceProvider, ITestFrameworkCapabilities capabilities) : + base(extension, getTestAssemblies, serviceProvider, capabilities) + { + + } + + /// + protected override Task SynchronizedDiscoverTestsAsync(VSTestDiscoverTestExecutionRequest request, IMessageBus messageBus, CancellationToken cancellationToken) + { + if (Environment.GetEnvironmentVariable("JTREG_DEBUG_DISCOVERTESTS") == "1" && !Debugger.IsAttached) + Debugger.Launch(); + + new JTRegTestDiscoverer().DiscoverTests(request.AssemblyPaths, request.DiscoveryContext, request.MessageLogger, request.DiscoverySink); + return Task.CompletedTask; + } + + /// + protected override Task SynchronizedRunTestsAsync(VSTestRunTestExecutionRequest request, IMessageBus messageBus, CancellationToken cancellationToken) + { + if (Environment.GetEnvironmentVariable("JTREG_DEBUG_RUNTESTS") == "1" && !Debugger.IsAttached) + Debugger.Launch(); + + if (request.VSTestFilter.TestCases is { } testCases) + new JTRegTestExecutor().RunTests(testCases, request.RunContext, request.FrameworkHandle, cancellationToken); + else + new JTRegTestExecutor().RunTests(request.AssemblyPaths, request.RunContext, request.FrameworkHandle, cancellationToken); + + return Task.CompletedTask; + } + + } + +} diff --git a/src/IKVM.JTReg.TestAdapter/TestingPlatform/JTRegExtension.cs b/src/IKVM.JTReg.TestAdapter/TestingPlatform/JTRegExtension.cs new file mode 100644 index 0000000000..bbabddbbcc --- /dev/null +++ b/src/IKVM.JTReg.TestAdapter/TestingPlatform/JTRegExtension.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Threading.Tasks; + +using Microsoft.Testing.Platform.Extensions; + +namespace IKVM.JTReg.TestAdapter.TestingPlatform +{ + + sealed class JTRegExtension : IExtension + { + + static string GetExtensionUid() + { + foreach (var attr in Assembly.GetEntryAssembly()?.GetCustomAttributes()) + if (attr.Key == "JTReg.Extension.Uid") + return attr.Value; + + return nameof(JTRegExtension); + } + + public string Uid { get; } = GetExtensionUid(); + + public string DisplayName => "MSTest"; + + public string Version => "1.0.0"; + + public string Description => "JTReg for Microsoft Testing Platform"; + + public Task IsEnabledAsync() => Task.FromResult(true); + + } + +} diff --git a/src/IKVM.JTReg.TestAdapter/TestingPlatform/TestApplicationBuilderExtensions.cs b/src/IKVM.JTReg.TestAdapter/TestingPlatform/TestApplicationBuilderExtensions.cs new file mode 100644 index 0000000000..3c14997f9c --- /dev/null +++ b/src/IKVM.JTReg.TestAdapter/TestingPlatform/TestApplicationBuilderExtensions.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System; +using System.Reflection; + +using Microsoft.Testing.Extensions.VSTestBridge.Capabilities; +using Microsoft.Testing.Extensions.VSTestBridge.Helpers; +using Microsoft.Testing.Platform.Builder; +using Microsoft.Testing.Platform.Capabilities.TestFramework; + +namespace IKVM.JTReg.TestAdapter.TestingPlatform +{ + + public static class TestApplicationBuilderExtensions + { + + public static void AddJTReg(this ITestApplicationBuilder testApplicationBuilder, Func> getTestAssemblies) + { + var extension = new JTRegExtension(); + testApplicationBuilder.AddRunSettingsService(extension); + testApplicationBuilder.AddTestCaseFilterService(extension); + testApplicationBuilder.RegisterTestFramework(_ => new TestFrameworkCapabilities(new VSTestBridgeExtensionBaseCapabilities()), (capabilities, serviceProvider) => new JTRegBridgedTestFramework(extension, getTestAssemblies, serviceProvider, capabilities)); + } + + } + +} diff --git a/src/IKVM.JTReg.TestAdapter/TestingPlatform/TestingPlatformBuilderHook.cs b/src/IKVM.JTReg.TestAdapter/TestingPlatform/TestingPlatformBuilderHook.cs new file mode 100644 index 0000000000..7cdc48388a --- /dev/null +++ b/src/IKVM.JTReg.TestAdapter/TestingPlatform/TestingPlatformBuilderHook.cs @@ -0,0 +1,15 @@ +using System.Reflection; + +using Microsoft.Testing.Platform.Builder; + +namespace IKVM.JTReg.TestAdapter.TestingPlatform +{ + + public static class TestingPlatformBuilderHook + { + + public static void AddExtensions(ITestApplicationBuilder testApplicationBuilder, string[] arguments) => testApplicationBuilder.AddJTReg(() => new[] { Assembly.GetEntryAssembly() }); + + } + +} diff --git a/src/IKVM.Java.Extensions/IKVM.Java.Extensions.csproj b/src/IKVM.Java.Extensions/IKVM.Java.Extensions.csproj index b796886671..6fef017a0a 100644 --- a/src/IKVM.Java.Extensions/IKVM.Java.Extensions.csproj +++ b/src/IKVM.Java.Extensions/IKVM.Java.Extensions.csproj @@ -1,4 +1,7 @@ - + + + + net472;net6.0;net8.0 @@ -6,4 +9,8 @@ + + + + diff --git a/src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj b/src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj index 6c55c2296a..bf1e2e257d 100644 --- a/src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj +++ b/src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj @@ -1,14 +1,22 @@ - + + + + + net472;net6.0;net7.0;net8.0 - - + + - + + + + + diff --git a/src/IKVM.Java.Tests/IKVM.Java.Tests.csproj b/src/IKVM.Java.Tests/IKVM.Java.Tests.csproj index b5a9989c3c..93ce9b53e6 100644 --- a/src/IKVM.Java.Tests/IKVM.Java.Tests.csproj +++ b/src/IKVM.Java.Tests/IKVM.Java.Tests.csproj @@ -9,8 +9,10 @@ - - + + + + @@ -19,6 +21,7 @@ + diff --git a/src/IKVM.Java.runtime.linux/SocketOptionRegistry.java b/src/IKVM.Java.runtime.linux/SocketOptionRegistry.java new file mode 100644 index 0000000000..82274bd6d0 --- /dev/null +++ b/src/IKVM.Java.runtime.linux/SocketOptionRegistry.java @@ -0,0 +1,87 @@ +package sun.nio.ch; +import java.net.SocketOption; +import java.net.StandardSocketOptions; +import java.net.ProtocolFamily; +import java.net.StandardProtocolFamily; +import java.util.Map; +import java.util.HashMap; +class SocketOptionRegistry { + + private SocketOptionRegistry() { } + + private static class RegistryKey { + private final SocketOption name; + private final ProtocolFamily family; + RegistryKey(SocketOption name, ProtocolFamily family) { + this.name = name; + this.family = family; + } + public int hashCode() { + return name.hashCode() + family.hashCode(); + } + public boolean equals(Object ob) { + if (ob == null) return false; + if (!(ob instanceof RegistryKey)) return false; + RegistryKey other = (RegistryKey)ob; + if (this.name != other.name) return false; + if (this.family != other.family) return false; + return true; + } + } + + private static class LazyInitialization { + + static final Map options = options(); + + private static Map options() { + Map map = + new HashMap(); + map.put(new RegistryKey(StandardSocketOptions.SO_BROADCAST, + Net.UNSPEC), new OptionKey(1, 6)); + map.put(new RegistryKey(StandardSocketOptions.SO_KEEPALIVE, + Net.UNSPEC), new OptionKey(1, 9)); + map.put(new RegistryKey(StandardSocketOptions.SO_LINGER, + Net.UNSPEC), new OptionKey(1, 13)); + map.put(new RegistryKey(StandardSocketOptions.SO_SNDBUF, + Net.UNSPEC), new OptionKey(1, 7)); + map.put(new RegistryKey(StandardSocketOptions.SO_RCVBUF, + Net.UNSPEC), new OptionKey(1, 8)); + map.put(new RegistryKey(StandardSocketOptions.SO_REUSEADDR, + Net.UNSPEC), new OptionKey(1, 2)); + + map.put(new RegistryKey(StandardSocketOptions.TCP_NODELAY, + Net.UNSPEC), new OptionKey(6, 1)); + + + map.put(new RegistryKey(StandardSocketOptions.IP_TOS, + StandardProtocolFamily.INET), new OptionKey(0, 1)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, + StandardProtocolFamily.INET), new OptionKey(0, 32)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, + StandardProtocolFamily.INET), new OptionKey(0, 33)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, + StandardProtocolFamily.INET), new OptionKey(0, 34)); + + + + map.put(new RegistryKey(StandardSocketOptions.IP_TOS, + StandardProtocolFamily.INET6), new OptionKey(41, 67)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, + StandardProtocolFamily.INET6), new OptionKey(41, 17)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, + StandardProtocolFamily.INET6), new OptionKey(41, 18)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, + StandardProtocolFamily.INET6), new OptionKey(41, 19)); + + + map.put(new RegistryKey(ExtendedSocketOption.SO_OOBINLINE, + Net.UNSPEC), new OptionKey(1, 10)); + return map; + } + } + + public static OptionKey findOption(SocketOption name, ProtocolFamily family) { + RegistryKey key = new RegistryKey(name, family); + return LazyInitialization.options.get(key); + } +} diff --git a/src/IKVM.Java.runtime.linux/UnixConstants.java b/src/IKVM.Java.runtime.linux/UnixConstants.java new file mode 100644 index 0000000000..8cfa61fe63 --- /dev/null +++ b/src/IKVM.Java.runtime.linux/UnixConstants.java @@ -0,0 +1,104 @@ +package sun.nio.fs; +class UnixConstants { + private UnixConstants() { } + static final int O_RDONLY = 00; + static final int O_WRONLY = 01; + static final int O_RDWR = 02; + static final int O_APPEND = 02000; + static final int O_CREAT = 0100; + static final int O_EXCL = 0200; + static final int O_TRUNC = 01000; + static final int O_SYNC = 04010000; + + + + + + static final int O_DSYNC = 010000; + + + + static final int O_NOFOLLOW = 0400000; + static final int O_DIRECT = 00; + + + static final int S_IAMB = + (0400|0200|0100|(0400 >> 3)|(0200 >> 3)|(0100 >> 3)|((0400 >> 3) >> 3)|((0200 >> 3) >> 3)|((0100 >> 3) >> 3)); + static final int S_IRUSR = 0400; + static final int S_IWUSR = 0200; + static final int S_IXUSR = 0100; + static final int S_IRGRP = (0400 >> 3); + static final int S_IWGRP = (0200 >> 3); + static final int S_IXGRP = (0100 >> 3); + static final int S_IROTH = ((0400 >> 3) >> 3); + static final int S_IWOTH = ((0200 >> 3) >> 3); + static final int S_IXOTH = ((0100 >> 3) >> 3); + + static final int S_IFMT = 0170000; + static final int S_IFREG = 0100000; + static final int S_IFDIR = 0040000; + static final int S_IFLNK = 0120000; + static final int S_IFCHR = 0020000; + static final int S_IFBLK = 0060000; + static final int S_IFIFO = 0010000; + static final int R_OK = 4; + static final int W_OK = 2; + static final int X_OK = 1; + static final int F_OK = 0; + static final int ENOENT = 2; + static final int ENXIO = 6; + static final int EACCES = 13; + static final int EEXIST = 17; + static final int ENOTDIR = 20; + static final int EINVAL = 22; + static final int EXDEV = 18; + static final int EISDIR = 21; + static final int ENOTEMPTY = 39; + static final int ENOSPC = 28; + static final int EAGAIN = 11; + static final int EWOULDBLOCK = 11; + static final int ENOSYS = 38; + static final int ELOOP = 40; + static final int EROFS = 30; + + + + + + static final int ENODATA = 61; + + + + + + + static final int XATTR_NOT_FOUND = 61; + + + + + + static final int ERANGE = 34; + static final int EMFILE = 24; + + + + + + + + static final int AT_SYMLINK_NOFOLLOW = 0x100; + static final int AT_REMOVEDIR = 0x200; + static final int ATTR_CMN_CRTIME = 00; + static final int ATTR_CMN_MODTIME = 00; + static final int ATTR_CMN_ACCTIME = 00; + static final int FSOPT_NOFOLLOW = 00; + + + + + static final int POSIX_FADV_SEQUENTIAL = 2; + static final int POSIX_FADV_NOREUSE = 5; + static final int POSIX_FADV_WILLNEED = 3; + +} diff --git a/src/IKVM.Java.runtime.osx/SocketOptionRegistry.java b/src/IKVM.Java.runtime.osx/SocketOptionRegistry.java new file mode 100644 index 0000000000..acfb5efb43 --- /dev/null +++ b/src/IKVM.Java.runtime.osx/SocketOptionRegistry.java @@ -0,0 +1,87 @@ +package sun.nio.ch; +import java.net.SocketOption; +import java.net.StandardSocketOptions; +import java.net.ProtocolFamily; +import java.net.StandardProtocolFamily; +import java.util.Map; +import java.util.HashMap; +class SocketOptionRegistry { + + private SocketOptionRegistry() { } + + private static class RegistryKey { + private final SocketOption name; + private final ProtocolFamily family; + RegistryKey(SocketOption name, ProtocolFamily family) { + this.name = name; + this.family = family; + } + public int hashCode() { + return name.hashCode() + family.hashCode(); + } + public boolean equals(Object ob) { + if (ob == null) return false; + if (!(ob instanceof RegistryKey)) return false; + RegistryKey other = (RegistryKey)ob; + if (this.name != other.name) return false; + if (this.family != other.family) return false; + return true; + } + } + + private static class LazyInitialization { + + static final Map options = options(); + + private static Map options() { + Map map = + new HashMap(); + map.put(new RegistryKey(StandardSocketOptions.SO_BROADCAST, + Net.UNSPEC), new OptionKey(0xffff, 0x0020)); + map.put(new RegistryKey(StandardSocketOptions.SO_KEEPALIVE, + Net.UNSPEC), new OptionKey(0xffff, 0x0008)); + map.put(new RegistryKey(StandardSocketOptions.SO_LINGER, + Net.UNSPEC), new OptionKey(0xffff, 0x0080)); + map.put(new RegistryKey(StandardSocketOptions.SO_SNDBUF, + Net.UNSPEC), new OptionKey(0xffff, 0x1001)); + map.put(new RegistryKey(StandardSocketOptions.SO_RCVBUF, + Net.UNSPEC), new OptionKey(0xffff, 0x1002)); + map.put(new RegistryKey(StandardSocketOptions.SO_REUSEADDR, + Net.UNSPEC), new OptionKey(0xffff, 0x0004)); + + map.put(new RegistryKey(StandardSocketOptions.TCP_NODELAY, + Net.UNSPEC), new OptionKey(6, 0x01)); + + + map.put(new RegistryKey(StandardSocketOptions.IP_TOS, + StandardProtocolFamily.INET), new OptionKey(0, 3)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, + StandardProtocolFamily.INET), new OptionKey(0, 9)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, + StandardProtocolFamily.INET), new OptionKey(0, 10)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, + StandardProtocolFamily.INET), new OptionKey(0, 11)); + + + + map.put(new RegistryKey(StandardSocketOptions.IP_TOS, + StandardProtocolFamily.INET6), new OptionKey(41, 36)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, + StandardProtocolFamily.INET6), new OptionKey(41, 9)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, + StandardProtocolFamily.INET6), new OptionKey(41, 10)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, + StandardProtocolFamily.INET6), new OptionKey(41, 11)); + + + map.put(new RegistryKey(ExtendedSocketOption.SO_OOBINLINE, + Net.UNSPEC), new OptionKey(0xffff, 0x0100)); + return map; + } + } + + public static OptionKey findOption(SocketOption name, ProtocolFamily family) { + RegistryKey key = new RegistryKey(name, family); + return LazyInitialization.options.get(key); + } +} diff --git a/src/IKVM.Java.runtime.osx/UnixConstants.java b/src/IKVM.Java.runtime.osx/UnixConstants.java new file mode 100644 index 0000000000..c42f11c5a9 --- /dev/null +++ b/src/IKVM.Java.runtime.osx/UnixConstants.java @@ -0,0 +1,87 @@ +package sun.nio.fs; +class UnixConstants { + private UnixConstants() { } + static final int O_RDONLY = 0x0000; + static final int O_WRONLY = 0x0001; + static final int O_RDWR = 0x0002; + static final int O_APPEND = 0x00000008; + static final int O_CREAT = 0x00000200; + static final int O_EXCL = 0x00000800; + static final int O_TRUNC = 0x00000400; + static final int O_SYNC = 0x0080; + + + + + + static final int O_DSYNC = 0x400000; + + + + static final int O_NOFOLLOW = 0x00000100; + static final int O_DIRECT = 00; + + + static final int S_IAMB = + (0000400|0000200|0000100|0000040|0000020|0000010|0000004|0000002|0000001); + static final int S_IRUSR = 0000400; + static final int S_IWUSR = 0000200; + static final int S_IXUSR = 0000100; + static final int S_IRGRP = 0000040; + static final int S_IWGRP = 0000020; + static final int S_IXGRP = 0000010; + static final int S_IROTH = 0000004; + static final int S_IWOTH = 0000002; + static final int S_IXOTH = 0000001; + + static final int S_IFMT = 0170000; + static final int S_IFREG = 0100000; + static final int S_IFDIR = 0040000; + static final int S_IFLNK = 0120000; + static final int S_IFCHR = 0020000; + static final int S_IFBLK = 0060000; + static final int S_IFIFO = 0010000; + static final int R_OK = (1<<2); + static final int W_OK = (1<<1); + static final int X_OK = (1<<0); + static final int F_OK = 0; + static final int ENOENT = 2; + static final int ENXIO = 6; + static final int EACCES = 13; + static final int EEXIST = 17; + static final int ENOTDIR = 20; + static final int EINVAL = 22; + static final int EXDEV = 18; + static final int EISDIR = 21; + static final int ENOTEMPTY = 66; + static final int ENOSPC = 28; + static final int EAGAIN = 35; + static final int EWOULDBLOCK = 35; + static final int ENOSYS = 78; + static final int ELOOP = 62; + static final int EROFS = 30; + + + + + + static final int ENODATA = 96; + static final int XATTR_NOT_FOUND = 00; + + + static final int ERANGE = 34; + static final int EMFILE = 24; + + + + + + + + static final int AT_SYMLINK_NOFOLLOW = 0x0020; + static final int AT_REMOVEDIR = 0x0080; + static final int ATTR_CMN_CRTIME = 00; + static final int ATTR_CMN_MODTIME = 00; + static final int ATTR_CMN_ACCTIME = 00; + static final int FSOPT_NOFOLLOW = 00; +} diff --git a/src/IKVM.Java.runtime.win/SocketOptionRegistry.java b/src/IKVM.Java.runtime.win/SocketOptionRegistry.java new file mode 100644 index 0000000000..1da0e18314 --- /dev/null +++ b/src/IKVM.Java.runtime.win/SocketOptionRegistry.java @@ -0,0 +1,87 @@ +package sun.nio.ch; +import java.net.SocketOption; +import java.net.StandardSocketOptions; +import java.net.ProtocolFamily; +import java.net.StandardProtocolFamily; +import java.util.Map; +import java.util.HashMap; +class SocketOptionRegistry { + + private SocketOptionRegistry() { } + + private static class RegistryKey { + private final SocketOption name; + private final ProtocolFamily family; + RegistryKey(SocketOption name, ProtocolFamily family) { + this.name = name; + this.family = family; + } + public int hashCode() { + return name.hashCode() + family.hashCode(); + } + public boolean equals(Object ob) { + if (ob == null) return false; + if (!(ob instanceof RegistryKey)) return false; + RegistryKey other = (RegistryKey)ob; + if (this.name != other.name) return false; + if (this.family != other.family) return false; + return true; + } + } + + private static class LazyInitialization { + + static final Map options = options(); + + private static Map options() { + Map map = + new HashMap(); + map.put(new RegistryKey(StandardSocketOptions.SO_BROADCAST, + Net.UNSPEC), new OptionKey(0xffff, 0x0020)); + map.put(new RegistryKey(StandardSocketOptions.SO_KEEPALIVE, + Net.UNSPEC), new OptionKey(0xffff, 0x0008)); + map.put(new RegistryKey(StandardSocketOptions.SO_LINGER, + Net.UNSPEC), new OptionKey(0xffff, 0x0080)); + map.put(new RegistryKey(StandardSocketOptions.SO_SNDBUF, + Net.UNSPEC), new OptionKey(0xffff, 0x1001)); + map.put(new RegistryKey(StandardSocketOptions.SO_RCVBUF, + Net.UNSPEC), new OptionKey(0xffff, 0x1002)); + map.put(new RegistryKey(StandardSocketOptions.SO_REUSEADDR, + Net.UNSPEC), new OptionKey(0xffff, 0x0004)); + + map.put(new RegistryKey(StandardSocketOptions.TCP_NODELAY, + Net.UNSPEC), new OptionKey(6, 0x0001)); + + + map.put(new RegistryKey(StandardSocketOptions.IP_TOS, + StandardProtocolFamily.INET), new OptionKey(0, 3)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, + StandardProtocolFamily.INET), new OptionKey(0, 9)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, + StandardProtocolFamily.INET), new OptionKey(0, 10)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, + StandardProtocolFamily.INET), new OptionKey(0, 11)); + + + + map.put(new RegistryKey(StandardSocketOptions.IP_TOS, + StandardProtocolFamily.INET6), new OptionKey(41, 39)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, + StandardProtocolFamily.INET6), new OptionKey(41, 9)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, + StandardProtocolFamily.INET6), new OptionKey(41, 10)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, + StandardProtocolFamily.INET6), new OptionKey(41, 11)); + + + map.put(new RegistryKey(ExtendedSocketOption.SO_OOBINLINE, + Net.UNSPEC), new OptionKey(0xffff, 0x0100)); + return map; + } + } + + public static OptionKey findOption(SocketOption name, ProtocolFamily family) { + RegistryKey key = new RegistryKey(name, family); + return LazyInitialization.options.get(key); + } +} diff --git a/src/IKVM.Java/IKVM.Java.runtime.props b/src/IKVM.Java/IKVM.Java.runtime.props index b3d7e34b91..2b464097f0 100644 --- a/src/IKVM.Java/IKVM.Java.runtime.props +++ b/src/IKVM.Java/IKVM.Java.runtime.props @@ -10,6 +10,14 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + windows + solaris + windows + linux + macosx + @@ -55,16 +63,11 @@ - - - - - - - - - - + + + + + diff --git a/src/IKVM.Java/IKVM.Java.runtime.targets b/src/IKVM.Java/IKVM.Java.runtime.targets index a93f3635e4..7b7a9a8f35 100644 --- a/src/IKVM.Java/IKVM.Java.runtime.targets +++ b/src/IKVM.Java/IKVM.Java.runtime.targets @@ -13,6 +13,7 @@ + @@ -113,101 +114,9 @@ - - - $([System.IO.Path]::GetFullPath('$(JAVA_HOME)\jre\lib\rt.jar')) - - - - - - - - $([System.IO.Path]::GetFullPath('$(JAVA_HOME)\lib\tools.jar')) - - - - - - - $(IntermediateOutputPath)btclasses.javac.rsp - $(IntermediateOutputPath)btclasses\ - $(IntermediateOutputPath)BuildTools.stamp - - - - - - - - - - - - <_BuildToolsJavaCompilerClasspath Include="$(ToolsJarPath)" /> - - - - <_BuildToolsJavaCompilerClasspathArg>@(_BuildToolsJavaCompilerClasspath, '$([System.IO.Path]::PathSeparator)') - <_BuildToolsJavaCompilerClasspathArg>$(_BuildToolsJavaCompilerClasspathArg.Replace('\', '\\')) - - - - <_BuildToolsJavaCompilerArgs Include="-cp" /> - <_BuildToolsJavaCompilerArgs Include=""$([MSBuild]::Escape('$(_BuildToolsJavaCompilerClasspathArg)'))"" /> - <_BuildToolsJavaCompilerArgs Include="-source" /> - <_BuildToolsJavaCompilerArgs Include="1.8" /> - <_BuildToolsJavaCompilerArgs Include="-target" /> - <_BuildToolsJavaCompilerArgs Include="1.8" /> - <_BuildToolsJavaCompilerArgs Include="-nowarn" /> - <_BuildToolsJavaCompilerArgs Include="-d" /> - <_BuildToolsJavaCompilerArgs Include="$(BuildToolsOutputPath)" /> - <_BuildToolsJavaCompilerArgs Include="@(BuildOpenJDKToolsSource->'%(FullPath)')" /> - - - - - - - - - - - - - - - - <_BuildToolsStartTime>$([System.DateTime]::Now.Ticks) - - - - - - - - <_BuildToolsStaleFiles Include="$(BuildToolsOutputPath)**\*.class" Condition=" '%(ModifiedTime)' == '' Or $([System.DateTime]::Parse('%(ModifiedTime)').Ticks) < $(_BuildToolsStartTime) " /> - - - - - - - <_BuildToolsStaleFiles Remove="@(_BuildToolsStaleFiles)" /> - - - - - - - - - - ResolveToolsJar; - BuildToolsResponseFile; - BuildTools; + OpenJdkBuildTools; $(GenerateSourceDependsOn); @@ -237,7 +146,7 @@ - + @@ -274,7 +183,7 @@ - + @@ -282,7 +191,7 @@ - + @@ -306,7 +215,7 @@ - + @@ -341,8 +250,8 @@ - - + + @@ -350,7 +259,7 @@ - + @@ -384,8 +293,8 @@ - - + + @@ -420,7 +329,7 @@ - + @@ -433,8 +342,8 @@ - - + + @@ -669,7 +578,7 @@ public class WriteStandardCharsets : Task - + @@ -678,9 +587,9 @@ public class WriteStandardCharsets : Task - - - + + + @@ -705,7 +614,7 @@ public class WriteStandardCharsets : Task - + @@ -717,8 +626,8 @@ public class WriteStandardCharsets : Task - - + + @@ -745,7 +654,7 @@ public class WriteStandardCharsets : Task - + @@ -1109,28 +1018,36 @@ File.WriteAllLines(Path, File.ReadAllLines(Path).TakeWhile(i => i.Contains("#BIN - + + + + + + <_Src Remove="@(_Src)" /> <_Src Include="$(OpenJdkDir)jdk\src\share\classes\java\nio\%(_GenBufferCommand.Template).java.template" /> + <_Bin Remove="@(_Bin)" /> <_Bin Include="$(OpenJdkDir)jdk\src\share\classes\java\nio\%(_GenBufferCommand.Template)-bin.java.template" /> + <_Tmp Remove="@(_Tmp)" /> <_Tmp Include="$(GenSrc)java\nio\%(_GenBufferCommand.Identity).java.tmp" /> + <_Dst Remove="@(_Dst)" /> <_Dst Include="$(GenSrc)java\nio\%(_GenBufferCommand.Identity).java" /> - - + + - - - - - - + + + + + + @@ -1161,14 +1078,14 @@ File.WriteAllLines(Path, File.ReadAllLines(Path).TakeWhile(i => i.Contains("#BIN - + - - + + @@ -1178,6 +1095,75 @@ File.WriteAllLines(Path, File.ReadAllLines(Path).TakeWhile(i => i.Contains("#BIN + + + + + + + + + + + + + + + + + + + + $([System.String]::Copy('%(Filename)%(Extension)').Replace('.', '_').Replace('-', '_')) + AWTIcon32_$([System.String]::Copy('%(Filename)%(Extension)').Replace('.', '_').Replace('-', '_')) + + + $([System.String]::Copy('%(Filename)%(Extension)').Replace('.', '_').Replace('-', '_')) + AWTIcon64_$([System.String]::Copy('%(Filename)%(Extension)').Replace('.', '_').Replace('-', '_')) + + + + + + + + + + + + <_Src Remove="@(_Src)" /> + <_Src Include="%(AwtIcons.Identity)" /> + <_Tmp Remove="@(_Tmp)" /> + <_Tmp Include="$(GenSrc)sun\awt\%(AwtIcons.ClassName).java.tmp" /> + <_Dst Remove="@(_Dst)" /> + <_Dst Include="$(GenSrc)sun\awt\%(AwtIcons.ClassName).java" /> + + + + + + + + + + + + + + + + + + + + + + + GenerateIcons; + $(GenerateSourceDependsOn); + + + $(GenerateSourceDependsOn); @@ -1192,7 +1178,7 @@ File.WriteAllLines(Path, File.ReadAllLines(Path).TakeWhile(i => i.Contains("#BIN - + @@ -1208,7 +1194,7 @@ File.WriteAllLines(Path, File.ReadAllLines(Path).TakeWhile(i => i.Contains("#BIN - + diff --git a/src/IKVM.Java/SocketOptionRegistry.java b/src/IKVM.Java/SocketOptionRegistry.java new file mode 100644 index 0000000000..1da0e18314 --- /dev/null +++ b/src/IKVM.Java/SocketOptionRegistry.java @@ -0,0 +1,87 @@ +package sun.nio.ch; +import java.net.SocketOption; +import java.net.StandardSocketOptions; +import java.net.ProtocolFamily; +import java.net.StandardProtocolFamily; +import java.util.Map; +import java.util.HashMap; +class SocketOptionRegistry { + + private SocketOptionRegistry() { } + + private static class RegistryKey { + private final SocketOption name; + private final ProtocolFamily family; + RegistryKey(SocketOption name, ProtocolFamily family) { + this.name = name; + this.family = family; + } + public int hashCode() { + return name.hashCode() + family.hashCode(); + } + public boolean equals(Object ob) { + if (ob == null) return false; + if (!(ob instanceof RegistryKey)) return false; + RegistryKey other = (RegistryKey)ob; + if (this.name != other.name) return false; + if (this.family != other.family) return false; + return true; + } + } + + private static class LazyInitialization { + + static final Map options = options(); + + private static Map options() { + Map map = + new HashMap(); + map.put(new RegistryKey(StandardSocketOptions.SO_BROADCAST, + Net.UNSPEC), new OptionKey(0xffff, 0x0020)); + map.put(new RegistryKey(StandardSocketOptions.SO_KEEPALIVE, + Net.UNSPEC), new OptionKey(0xffff, 0x0008)); + map.put(new RegistryKey(StandardSocketOptions.SO_LINGER, + Net.UNSPEC), new OptionKey(0xffff, 0x0080)); + map.put(new RegistryKey(StandardSocketOptions.SO_SNDBUF, + Net.UNSPEC), new OptionKey(0xffff, 0x1001)); + map.put(new RegistryKey(StandardSocketOptions.SO_RCVBUF, + Net.UNSPEC), new OptionKey(0xffff, 0x1002)); + map.put(new RegistryKey(StandardSocketOptions.SO_REUSEADDR, + Net.UNSPEC), new OptionKey(0xffff, 0x0004)); + + map.put(new RegistryKey(StandardSocketOptions.TCP_NODELAY, + Net.UNSPEC), new OptionKey(6, 0x0001)); + + + map.put(new RegistryKey(StandardSocketOptions.IP_TOS, + StandardProtocolFamily.INET), new OptionKey(0, 3)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, + StandardProtocolFamily.INET), new OptionKey(0, 9)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, + StandardProtocolFamily.INET), new OptionKey(0, 10)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, + StandardProtocolFamily.INET), new OptionKey(0, 11)); + + + + map.put(new RegistryKey(StandardSocketOptions.IP_TOS, + StandardProtocolFamily.INET6), new OptionKey(41, 39)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, + StandardProtocolFamily.INET6), new OptionKey(41, 9)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, + StandardProtocolFamily.INET6), new OptionKey(41, 10)); + map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, + StandardProtocolFamily.INET6), new OptionKey(41, 11)); + + + map.put(new RegistryKey(ExtendedSocketOption.SO_OOBINLINE, + Net.UNSPEC), new OptionKey(0xffff, 0x0100)); + return map; + } + } + + public static OptionKey findOption(SocketOption name, ProtocolFamily family) { + RegistryKey key = new RegistryKey(name, family); + return LazyInitialization.options.get(key); + } +} diff --git a/src/IKVM.Java/local/com/sun/java/util/jar/pack/PackageReader.java b/src/IKVM.Java/local/com/sun/java/util/jar/pack/PackageReader.java deleted file mode 100644 index 27cdcd13e8..0000000000 --- a/src/IKVM.Java/local/com/sun/java/util/jar/pack/PackageReader.java +++ /dev/null @@ -1,2383 +0,0 @@ -/* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.java.util.jar.pack; - -import com.sun.java.util.jar.pack.ConstantPool.*; -import com.sun.java.util.jar.pack.Package.Class; -import com.sun.java.util.jar.pack.Package.File; -import com.sun.java.util.jar.pack.Package.InnerClass; -import java.io.ByteArrayOutputStream; -import java.io.EOFException; -import java.io.PrintStream; -import java.io.FilterInputStream; -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Map; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Set; -import static com.sun.java.util.jar.pack.Constants.*; - -/** - * Reader for a package file. - * - * @see PackageWriter - * @author John Rose - */ -class PackageReader extends BandStructure { - Package pkg; - byte[] bytes; - LimitedBuffer in; - Package.Version packageVersion; - - PackageReader(Package pkg, InputStream in) throws IOException { - this.pkg = pkg; - this.in = new LimitedBuffer(in); - } - - /** A buffered input stream which is careful not to - * read its underlying stream ahead of a given mark, - * called the 'readLimit'. This property declares - * the maximum number of characters that future reads - * can consume from the underlying stream. - */ - static - class LimitedBuffer extends BufferedInputStream { - long served; // total number of charburgers served - int servedPos; // ...as of this value of super.pos - long limit; // current declared limit - long buffered; - public boolean atLimit() { - boolean z = (getBytesServed() == limit); - assert(!z || limit == buffered); - return z; - } - public long getBytesServed() { - return served + (pos - servedPos); - } - public void setReadLimit(long newLimit) { - if (newLimit == -1) - limit = -1; - else - limit = getBytesServed() + newLimit; - } - public long getReadLimit() { - if (limit == -1) - return limit; - else - return limit - getBytesServed(); - } - public int read() throws IOException { - if (pos < count) { - // fast path - return buf[pos++] & 0xFF; - } - served += (pos - servedPos); - int ch = super.read(); - servedPos = pos; - if (ch >= 0) served += 1; - assert(served <= limit || limit == -1); - return ch; - } - public int read(byte b[], int off, int len) throws IOException { - served += (pos - servedPos); - int nr = super.read(b, off, len); - servedPos = pos; - if (nr >= 0) served += nr; - //assert(served <= limit || limit == -1); - return nr; - } - public long skip(long n) throws IOException { - throw new RuntimeException("no skipping"); - } - LimitedBuffer(InputStream originalIn) { - super(null, 1<<14); - servedPos = pos; - super.in = new FilterInputStream(originalIn) { - public int read() throws IOException { - if (buffered == limit) - return -1; - ++buffered; - return super.read(); - } - public int read(byte b[], int off, int len) throws IOException { - if (buffered == limit) - return -1; - if (limit != -1) { - long remaining = limit - buffered; - if (len > remaining) - len = (int)remaining; - } - int nr = super.read(b, off, len); - if (nr >= 0) buffered += nr; - return nr; - } - }; - } - } - - void read() throws IOException { - boolean ok = false; - try { - // pack200_archive: - // file_header - // *band_headers :BYTE1 - // cp_bands - // attr_definition_bands - // ic_bands - // class_bands - // bc_bands - // file_bands - readFileHeader(); - readBandHeaders(); - readConstantPool(); // cp_bands - readAttrDefs(); - readInnerClasses(); - Class[] classes = readClasses(); - readByteCodes(); - readFiles(); // file_bands - assert(archiveSize1 == 0 || in.atLimit()); - assert(archiveSize1 == 0 || - in.getBytesServed() == archiveSize0+archiveSize1); - all_bands.doneDisbursing(); - - // As a post-pass, build constant pools and inner classes. - for (int i = 0; i < classes.length; i++) { - reconstructClass(classes[i]); - } - - ok = true; - } catch (Exception ee) { - Utils.log.warning("Error on input: "+ee, ee); - if (verbose > 0) - Utils.log.info("Stream offsets:"+ - " served="+in.getBytesServed()+ - " buffered="+in.buffered+ - " limit="+in.limit); - //if (verbose > 0) ee.printStackTrace(); - if (ee instanceof IOException) throw (IOException)ee; - if (ee instanceof RuntimeException) throw (RuntimeException)ee; - throw new Error("error unpacking", ee); - } - } - - // Temporary count values, until band decoding gets rolling. - int[] tagCount = new int[CONSTANT_Limit]; - int numFiles; - int numAttrDefs; - int numInnerClasses; - int numClasses; - - void readFileHeader() throws IOException { - // file_header: - // archive_magic archive_header - readArchiveMagic(); - readArchiveHeader(); - } - - // Local routine used to parse fixed-format scalars - // in the file_header: - private int getMagicInt32() throws IOException { - int res = 0; - for (int i = 0; i < 4; i++) { - res <<= 8; - res |= (archive_magic.getByte() & 0xFF); - } - return res; - } - - final static int MAGIC_BYTES = 4; - - void readArchiveMagic() throws IOException { - // Read a minimum of bytes in the first gulp. - in.setReadLimit(MAGIC_BYTES + AH_LENGTH_MIN); - - // archive_magic: - // #archive_magic_word :BYTE1[4] - archive_magic.expectLength(MAGIC_BYTES); - archive_magic.readFrom(in); - - // read and check magic numbers: - int magic = getMagicInt32(); - if (pkg.magic != magic) { - throw new IOException("Unexpected package magic number: got " - + magic + "; expected " + pkg.magic); - } - archive_magic.doneDisbursing(); - } - - // Fixed 6211177, converted to throw IOException - void checkArchiveVersion() throws IOException { - Package.Version versionFound = null; - for (Package.Version v : new Package.Version[] { - JAVA8_PACKAGE_VERSION, - JAVA7_PACKAGE_VERSION, - JAVA6_PACKAGE_VERSION, - JAVA5_PACKAGE_VERSION - }) { - if (packageVersion.equals(v)) { - versionFound = v; - break; - } - } - if (versionFound == null) { - String expVer = JAVA8_PACKAGE_VERSION.toString() - + "OR" - + JAVA7_PACKAGE_VERSION.toString() - + " OR " - + JAVA6_PACKAGE_VERSION.toString() - + " OR " - + JAVA5_PACKAGE_VERSION.toString(); - throw new IOException("Unexpected package minor version: got " - + packageVersion.toString() + "; expected " + expVer); - } - } - - void readArchiveHeader() throws IOException { - // archive_header: - // #archive_minver :UNSIGNED5[1] - // #archive_majver :UNSIGNED5[1] - // #archive_options :UNSIGNED5[1] - // (archive_file_counts) ** (#have_file_headers) - // (archive_special_counts) ** (#have_special_formats) - // cp_counts - // class_counts - // - // archive_file_counts: - // #archive_size_hi :UNSIGNED5[1] - // #archive_size_lo :UNSIGNED5[1] - // #archive_next_count :UNSIGNED5[1] - // #archive_modtime :UNSIGNED5[1] - // #file_count :UNSIGNED5[1] - // - // class_counts: - // #ic_count :UNSIGNED5[1] - // #default_class_minver :UNSIGNED5[1] - // #default_class_majver :UNSIGNED5[1] - // #class_count :UNSIGNED5[1] - // - // archive_special_counts: - // #band_headers_size :UNSIGNED5[1] - // #attr_definition_count :UNSIGNED5[1] - // - archive_header_0.expectLength(AH_LENGTH_0); - archive_header_0.readFrom(in); - - int minver = archive_header_0.getInt(); - int majver = archive_header_0.getInt(); - packageVersion = Package.Version.of(majver, minver); - checkArchiveVersion(); - this.initHighestClassVersion(JAVA7_MAX_CLASS_VERSION); - - archiveOptions = archive_header_0.getInt(); - archive_header_0.doneDisbursing(); - - // detect archive optional fields in archive header - boolean haveSpecial = testBit(archiveOptions, AO_HAVE_SPECIAL_FORMATS); - boolean haveFiles = testBit(archiveOptions, AO_HAVE_FILE_HEADERS); - boolean haveNumbers = testBit(archiveOptions, AO_HAVE_CP_NUMBERS); - boolean haveCPExtra = testBit(archiveOptions, AO_HAVE_CP_EXTRAS); - initAttrIndexLimit(); - - // now we are ready to use the data: - archive_header_S.expectLength(haveFiles? AH_LENGTH_S: 0); - archive_header_S.readFrom(in); - if (haveFiles) { - long sizeHi = archive_header_S.getInt(); - long sizeLo = archive_header_S.getInt(); - archiveSize1 = (sizeHi << 32) + ((sizeLo << 32) >>> 32); - // Set the limit, now, up to the file_bits. - in.setReadLimit(archiveSize1); // for debug only - } else { - archiveSize1 = 0; - in.setReadLimit(-1); // remove limitation - } - archive_header_S.doneDisbursing(); - archiveSize0 = in.getBytesServed(); - - int remainingHeaders = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S; - if (haveFiles) remainingHeaders += AH_FILE_HEADER_LEN; - if (haveSpecial) remainingHeaders += AH_SPECIAL_FORMAT_LEN; - if (haveNumbers) remainingHeaders += AH_CP_NUMBER_LEN; - if (haveCPExtra) remainingHeaders += AH_CP_EXTRA_LEN; - archive_header_1.expectLength(remainingHeaders); - archive_header_1.readFrom(in); - - if (haveFiles) { - archiveNextCount = archive_header_1.getInt(); - pkg.default_modtime = archive_header_1.getInt(); - numFiles = archive_header_1.getInt(); - } else { - archiveNextCount = 0; - numFiles = 0; - } - - if (haveSpecial) { - band_headers.expectLength(archive_header_1.getInt()); - numAttrDefs = archive_header_1.getInt(); - } else { - band_headers.expectLength(0); - numAttrDefs = 0; - } - - readConstantPoolCounts(haveNumbers, haveCPExtra); - - numInnerClasses = archive_header_1.getInt(); - - minver = (short) archive_header_1.getInt(); - majver = (short) archive_header_1.getInt(); - pkg.defaultClassVersion = Package.Version.of(majver, minver); - numClasses = archive_header_1.getInt(); - - archive_header_1.doneDisbursing(); - - // set some derived archive bits - if (testBit(archiveOptions, AO_DEFLATE_HINT)) { - pkg.default_options |= FO_DEFLATE_HINT; - } - } - - void readBandHeaders() throws IOException { - band_headers.readFrom(in); - bandHeaderBytePos = 1; // Leave room to pushback the initial XB byte. - bandHeaderBytes = new byte[bandHeaderBytePos + band_headers.length()]; - for (int i = bandHeaderBytePos; i < bandHeaderBytes.length; i++) { - bandHeaderBytes[i] = (byte) band_headers.getByte(); - } - band_headers.doneDisbursing(); - } - - void readConstantPoolCounts(boolean haveNumbers, boolean haveCPExtra) throws IOException { - // size the constant pools: - for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) { - // cp_counts: - // #cp_Utf8_count :UNSIGNED5[1] - // (cp_number_counts) ** (#have_cp_numbers) - // #cp_String_count :UNSIGNED5[1] - // #cp_Class_count :UNSIGNED5[1] - // #cp_Signature_count :UNSIGNED5[1] - // #cp_Descr_count :UNSIGNED5[1] - // #cp_Field_count :UNSIGNED5[1] - // #cp_Method_count :UNSIGNED5[1] - // #cp_Imethod_count :UNSIGNED5[1] - // (cp_attr_counts) ** (#have_cp_attr_counts) - // - // cp_number_counts: - // #cp_Int_count :UNSIGNED5[1] - // #cp_Float_count :UNSIGNED5[1] - // #cp_Long_count :UNSIGNED5[1] - // #cp_Double_count :UNSIGNED5[1] - // - // cp_extra_counts: - // #cp_MethodHandle_count :UNSIGNED5[1] - // #cp_MethodType_count :UNSIGNED5[1] - // #cp_InvokeDynamic_count :UNSIGNED5[1] - // #cp_BootstrapMethod_count :UNSIGNED5[1] - // - byte tag = ConstantPool.TAGS_IN_ORDER[k]; - if (!haveNumbers) { - // These four counts are optional. - switch (tag) { - case CONSTANT_Integer: - case CONSTANT_Float: - case CONSTANT_Long: - case CONSTANT_Double: - continue; - } - } - if (!haveCPExtra) { - // These four counts are optional. - switch (tag) { - case CONSTANT_MethodHandle: - case CONSTANT_MethodType: - case CONSTANT_InvokeDynamic: - case CONSTANT_BootstrapMethod: - continue; - } - } - tagCount[tag] = archive_header_1.getInt(); - } - } - - protected Index getCPIndex(byte tag) { - return pkg.cp.getIndexByTag(tag); - } - Index initCPIndex(byte tag, Entry[] cpMap) { - if (verbose > 3) { - for (int i = 0; i < cpMap.length; i++) { - Utils.log.fine("cp.add "+cpMap[i]); - } - } - Index index = ConstantPool.makeIndex(ConstantPool.tagName(tag), cpMap); - if (verbose > 1) Utils.log.fine("Read "+index); - pkg.cp.initIndexByTag(tag, index); - return index; - } - - void checkLegacy(String bandname) { - if (packageVersion.lessThan(JAVA7_PACKAGE_VERSION)) { - throw new RuntimeException("unexpected band " + bandname); - } - } - void readConstantPool() throws IOException { - // cp_bands: - // cp_Utf8 - // *cp_Int :UDELTA5 - // *cp_Float :UDELTA5 - // cp_Long - // cp_Double - // *cp_String :UDELTA5 (cp_Utf8) - // *cp_Class :UDELTA5 (cp_Utf8) - // cp_Signature - // cp_Descr - // cp_Field - // cp_Method - // cp_Imethod - - if (verbose > 0) Utils.log.info("Reading CP"); - - for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) { - byte tag = ConstantPool.TAGS_IN_ORDER[k]; - int len = tagCount[tag]; - - Entry[] cpMap = new Entry[len]; - if (verbose > 0) - Utils.log.info("Reading "+cpMap.length+" "+ConstantPool.tagName(tag)+" entries..."); - - switch (tag) { - case CONSTANT_Utf8: - readUtf8Bands(cpMap); - break; - case CONSTANT_Integer: - cp_Int.expectLength(cpMap.length); - cp_Int.readFrom(in); - for (int i = 0; i < cpMap.length; i++) { - int x = cp_Int.getInt(); // coding handles signs OK - cpMap[i] = ConstantPool.getLiteralEntry(x); - } - cp_Int.doneDisbursing(); - break; - case CONSTANT_Float: - cp_Float.expectLength(cpMap.length); - cp_Float.readFrom(in); - for (int i = 0; i < cpMap.length; i++) { - int x = cp_Float.getInt(); - float fx = Float.intBitsToFloat(x); - cpMap[i] = ConstantPool.getLiteralEntry(fx); - } - cp_Float.doneDisbursing(); - break; - case CONSTANT_Long: - // cp_Long: - // *cp_Long_hi :UDELTA5 - // *cp_Long_lo :DELTA5 - cp_Long_hi.expectLength(cpMap.length); - cp_Long_hi.readFrom(in); - cp_Long_lo.expectLength(cpMap.length); - cp_Long_lo.readFrom(in); - for (int i = 0; i < cpMap.length; i++) { - long hi = cp_Long_hi.getInt(); - long lo = cp_Long_lo.getInt(); - long x = (hi << 32) + ((lo << 32) >>> 32); - cpMap[i] = ConstantPool.getLiteralEntry(x); - } - cp_Long_hi.doneDisbursing(); - cp_Long_lo.doneDisbursing(); - break; - case CONSTANT_Double: - // cp_Double: - // *cp_Double_hi :UDELTA5 - // *cp_Double_lo :DELTA5 - cp_Double_hi.expectLength(cpMap.length); - cp_Double_hi.readFrom(in); - cp_Double_lo.expectLength(cpMap.length); - cp_Double_lo.readFrom(in); - for (int i = 0; i < cpMap.length; i++) { - long hi = cp_Double_hi.getInt(); - long lo = cp_Double_lo.getInt(); - long x = (hi << 32) + ((lo << 32) >>> 32); - double dx = Double.longBitsToDouble(x); - cpMap[i] = ConstantPool.getLiteralEntry(dx); - } - cp_Double_hi.doneDisbursing(); - cp_Double_lo.doneDisbursing(); - break; - case CONSTANT_String: - cp_String.expectLength(cpMap.length); - cp_String.readFrom(in); - cp_String.setIndex(getCPIndex(CONSTANT_Utf8)); - for (int i = 0; i < cpMap.length; i++) { - cpMap[i] = ConstantPool.getLiteralEntry(cp_String.getRef().stringValue()); - } - cp_String.doneDisbursing(); - break; - case CONSTANT_Class: - cp_Class.expectLength(cpMap.length); - cp_Class.readFrom(in); - cp_Class.setIndex(getCPIndex(CONSTANT_Utf8)); - for (int i = 0; i < cpMap.length; i++) { - cpMap[i] = ConstantPool.getClassEntry(cp_Class.getRef().stringValue()); - } - cp_Class.doneDisbursing(); - break; - case CONSTANT_Signature: - readSignatureBands(cpMap); - break; - case CONSTANT_NameandType: - // cp_Descr: - // *cp_Descr_type :DELTA5 (cp_Signature) - // *cp_Descr_name :UDELTA5 (cp_Utf8) - cp_Descr_name.expectLength(cpMap.length); - cp_Descr_name.readFrom(in); - cp_Descr_name.setIndex(getCPIndex(CONSTANT_Utf8)); - cp_Descr_type.expectLength(cpMap.length); - cp_Descr_type.readFrom(in); - cp_Descr_type.setIndex(getCPIndex(CONSTANT_Signature)); - for (int i = 0; i < cpMap.length; i++) { - Entry ref = cp_Descr_name.getRef(); - Entry ref2 = cp_Descr_type.getRef(); - cpMap[i] = ConstantPool.getDescriptorEntry((Utf8Entry)ref, - (SignatureEntry)ref2); - } - cp_Descr_name.doneDisbursing(); - cp_Descr_type.doneDisbursing(); - break; - case CONSTANT_Fieldref: - readMemberRefs(tag, cpMap, cp_Field_class, cp_Field_desc); - break; - case CONSTANT_Methodref: - readMemberRefs(tag, cpMap, cp_Method_class, cp_Method_desc); - break; - case CONSTANT_InterfaceMethodref: - readMemberRefs(tag, cpMap, cp_Imethod_class, cp_Imethod_desc); - break; - case CONSTANT_MethodHandle: - if (cpMap.length > 0) { - checkLegacy(cp_MethodHandle_refkind.name()); - } - cp_MethodHandle_refkind.expectLength(cpMap.length); - cp_MethodHandle_refkind.readFrom(in); - cp_MethodHandle_member.expectLength(cpMap.length); - cp_MethodHandle_member.readFrom(in); - cp_MethodHandle_member.setIndex(getCPIndex(CONSTANT_AnyMember)); - for (int i = 0; i < cpMap.length; i++) { - byte refKind = (byte) cp_MethodHandle_refkind.getInt(); - MemberEntry memRef = (MemberEntry) cp_MethodHandle_member.getRef(); - cpMap[i] = ConstantPool.getMethodHandleEntry(refKind, memRef); - } - cp_MethodHandle_refkind.doneDisbursing(); - cp_MethodHandle_member.doneDisbursing(); - break; - case CONSTANT_MethodType: - if (cpMap.length > 0) { - checkLegacy(cp_MethodType.name()); - } - cp_MethodType.expectLength(cpMap.length); - cp_MethodType.readFrom(in); - cp_MethodType.setIndex(getCPIndex(CONSTANT_Signature)); - for (int i = 0; i < cpMap.length; i++) { - SignatureEntry typeRef = (SignatureEntry) cp_MethodType.getRef(); - cpMap[i] = ConstantPool.getMethodTypeEntry(typeRef); - } - cp_MethodType.doneDisbursing(); - break; - case CONSTANT_InvokeDynamic: - if (cpMap.length > 0) { - checkLegacy(cp_InvokeDynamic_spec.name()); - } - cp_InvokeDynamic_spec.expectLength(cpMap.length); - cp_InvokeDynamic_spec.readFrom(in); - cp_InvokeDynamic_spec.setIndex(getCPIndex(CONSTANT_BootstrapMethod)); - cp_InvokeDynamic_desc.expectLength(cpMap.length); - cp_InvokeDynamic_desc.readFrom(in); - cp_InvokeDynamic_desc.setIndex(getCPIndex(CONSTANT_NameandType)); - for (int i = 0; i < cpMap.length; i++) { - BootstrapMethodEntry bss = (BootstrapMethodEntry) cp_InvokeDynamic_spec.getRef(); - DescriptorEntry descr = (DescriptorEntry) cp_InvokeDynamic_desc.getRef(); - cpMap[i] = ConstantPool.getInvokeDynamicEntry(bss, descr); - } - cp_InvokeDynamic_spec.doneDisbursing(); - cp_InvokeDynamic_desc.doneDisbursing(); - break; - case CONSTANT_BootstrapMethod: - if (cpMap.length > 0) { - checkLegacy(cp_BootstrapMethod_ref.name()); - } - cp_BootstrapMethod_ref.expectLength(cpMap.length); - cp_BootstrapMethod_ref.readFrom(in); - cp_BootstrapMethod_ref.setIndex(getCPIndex(CONSTANT_MethodHandle)); - cp_BootstrapMethod_arg_count.expectLength(cpMap.length); - cp_BootstrapMethod_arg_count.readFrom(in); - int totalArgCount = cp_BootstrapMethod_arg_count.getIntTotal(); - cp_BootstrapMethod_arg.expectLength(totalArgCount); - cp_BootstrapMethod_arg.readFrom(in); - cp_BootstrapMethod_arg.setIndex(getCPIndex(CONSTANT_LoadableValue)); - for (int i = 0; i < cpMap.length; i++) { - MethodHandleEntry bsm = (MethodHandleEntry) cp_BootstrapMethod_ref.getRef(); - int argc = cp_BootstrapMethod_arg_count.getInt(); - Entry[] argRefs = new Entry[argc]; - for (int j = 0; j < argc; j++) { - argRefs[j] = cp_BootstrapMethod_arg.getRef(); - } - cpMap[i] = ConstantPool.getBootstrapMethodEntry(bsm, argRefs); - } - cp_BootstrapMethod_ref.doneDisbursing(); - cp_BootstrapMethod_arg_count.doneDisbursing(); - cp_BootstrapMethod_arg.doneDisbursing(); - break; - default: - throw new AssertionError("unexpected CP tag in package"); - } - - Index index = initCPIndex(tag, cpMap); - - if (optDumpBands) { - try (PrintStream ps = new PrintStream(getDumpStream(index, ".idx"))) { - printArrayTo(ps, index.cpMap, 0, index.cpMap.length); - } - } - } - - cp_bands.doneDisbursing(); - - if (optDumpBands || verbose > 1) { - for (byte tag = CONSTANT_GroupFirst; tag < CONSTANT_GroupLimit; tag++) { - Index index = pkg.cp.getIndexByTag(tag); - if (index == null || index.isEmpty()) continue; - Entry[] cpMap = index.cpMap; - if (verbose > 1) - Utils.log.info("Index group "+ConstantPool.tagName(tag)+" contains "+cpMap.length+" entries."); - if (optDumpBands) { - try (PrintStream ps = new PrintStream(getDumpStream(index.debugName, tag, ".gidx", index))) { - printArrayTo(ps, cpMap, 0, cpMap.length, true); - } - } - } - } - - setBandIndexes(); - } - - void readUtf8Bands(Entry[] cpMap) throws IOException { - // cp_Utf8: - // *cp_Utf8_prefix :DELTA5 - // *cp_Utf8_suffix :UNSIGNED5 - // *cp_Utf8_chars :CHAR3 - // *cp_Utf8_big_suffix :DELTA5 - // (*cp_Utf8_big_chars :DELTA5) - // ** length(cp_Utf8_big_suffix) - int len = cpMap.length; - if (len == 0) - return; // nothing to read - - // Bands have implicit leading zeroes, for the empty string: - final int SUFFIX_SKIP_1 = 1; - final int PREFIX_SKIP_2 = 2; - - // First band: Read lengths of shared prefixes. - cp_Utf8_prefix.expectLength(Math.max(0, len - PREFIX_SKIP_2)); - cp_Utf8_prefix.readFrom(in); - - // Second band: Read lengths of unshared suffixes: - cp_Utf8_suffix.expectLength(Math.max(0, len - SUFFIX_SKIP_1)); - cp_Utf8_suffix.readFrom(in); - - char[][] suffixChars = new char[len][]; - int bigSuffixCount = 0; - - // Third band: Read the char values in the unshared suffixes: - cp_Utf8_chars.expectLength(cp_Utf8_suffix.getIntTotal()); - cp_Utf8_chars.readFrom(in); - for (int i = 0; i < len; i++) { - int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt(); - if (suffix == 0 && i >= SUFFIX_SKIP_1) { - // chars are packed in cp_Utf8_big_chars - bigSuffixCount += 1; - continue; - } - suffixChars[i] = new char[suffix]; - for (int j = 0; j < suffix; j++) { - int ch = cp_Utf8_chars.getInt(); - assert(ch == (char)ch); - suffixChars[i][j] = (char)ch; - } - } - cp_Utf8_chars.doneDisbursing(); - - // Fourth band: Go back and size the specially packed strings. - int maxChars = 0; - cp_Utf8_big_suffix.expectLength(bigSuffixCount); - cp_Utf8_big_suffix.readFrom(in); - cp_Utf8_suffix.resetForSecondPass(); - for (int i = 0; i < len; i++) { - int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt(); - int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt(); - if (suffix == 0 && i >= SUFFIX_SKIP_1) { - assert(suffixChars[i] == null); - suffix = cp_Utf8_big_suffix.getInt(); - } else { - assert(suffixChars[i] != null); - } - if (maxChars < prefix + suffix) - maxChars = prefix + suffix; - } - char[] buf = new char[maxChars]; - - // Fifth band(s): Get the specially packed characters. - cp_Utf8_suffix.resetForSecondPass(); - cp_Utf8_big_suffix.resetForSecondPass(); - for (int i = 0; i < len; i++) { - if (i < SUFFIX_SKIP_1) continue; - int suffix = cp_Utf8_suffix.getInt(); - if (suffix != 0) continue; // already input - suffix = cp_Utf8_big_suffix.getInt(); - suffixChars[i] = new char[suffix]; - if (suffix == 0) { - // Do not bother to add an empty "(Utf8_big_0)" band. - continue; - } - IntBand packed = cp_Utf8_big_chars.newIntBand("(Utf8_big_"+i+")"); - packed.expectLength(suffix); - packed.readFrom(in); - for (int j = 0; j < suffix; j++) { - int ch = packed.getInt(); - assert(ch == (char)ch); - suffixChars[i][j] = (char)ch; - } - packed.doneDisbursing(); - } - cp_Utf8_big_chars.doneDisbursing(); - - // Finally, sew together all the prefixes and suffixes. - cp_Utf8_prefix.resetForSecondPass(); - cp_Utf8_suffix.resetForSecondPass(); - cp_Utf8_big_suffix.resetForSecondPass(); - for (int i = 0; i < len; i++) { - int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt(); - int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt(); - if (suffix == 0 && i >= SUFFIX_SKIP_1) - suffix = cp_Utf8_big_suffix.getInt(); - - // by induction, the buffer is already filled with the prefix - System.arraycopy(suffixChars[i], 0, buf, prefix, suffix); - - cpMap[i] = ConstantPool.getUtf8Entry(new String(buf, 0, prefix+suffix)); - } - - cp_Utf8_prefix.doneDisbursing(); - cp_Utf8_suffix.doneDisbursing(); - cp_Utf8_big_suffix.doneDisbursing(); - } - - Map utf8Signatures; - - void readSignatureBands(Entry[] cpMap) throws IOException { - // cp_Signature: - // *cp_Signature_form :DELTA5 (cp_Utf8) - // *cp_Signature_classes :UDELTA5 (cp_Class) - cp_Signature_form.expectLength(cpMap.length); - cp_Signature_form.readFrom(in); - cp_Signature_form.setIndex(getCPIndex(CONSTANT_Utf8)); - int[] numSigClasses = new int[cpMap.length]; - for (int i = 0; i < cpMap.length; i++) { - Utf8Entry formRef = (Utf8Entry) cp_Signature_form.getRef(); - numSigClasses[i] = ConstantPool.countClassParts(formRef); - } - cp_Signature_form.resetForSecondPass(); - cp_Signature_classes.expectLength(getIntTotal(numSigClasses)); - cp_Signature_classes.readFrom(in); - cp_Signature_classes.setIndex(getCPIndex(CONSTANT_Class)); - utf8Signatures = new HashMap<>(); - for (int i = 0; i < cpMap.length; i++) { - Utf8Entry formRef = (Utf8Entry) cp_Signature_form.getRef(); - ClassEntry[] classRefs = new ClassEntry[numSigClasses[i]]; - for (int j = 0; j < classRefs.length; j++) { - classRefs[j] = (ClassEntry) cp_Signature_classes.getRef(); - } - SignatureEntry se = ConstantPool.getSignatureEntry(formRef, classRefs); - cpMap[i] = se; - utf8Signatures.put(se.asUtf8Entry(), se); - } - cp_Signature_form.doneDisbursing(); - cp_Signature_classes.doneDisbursing(); - } - - void readMemberRefs(byte tag, Entry[] cpMap, CPRefBand cp_class, CPRefBand cp_desc) throws IOException { - // cp_Field: - // *cp_Field_class :DELTA5 (cp_Class) - // *cp_Field_desc :UDELTA5 (cp_Descr) - // cp_Method: - // *cp_Method_class :DELTA5 (cp_Class) - // *cp_Method_desc :UDELTA5 (cp_Descr) - // cp_Imethod: - // *cp_Imethod_class :DELTA5 (cp_Class) - // *cp_Imethod_desc :UDELTA5 (cp_Descr) - cp_class.expectLength(cpMap.length); - cp_class.readFrom(in); - cp_class.setIndex(getCPIndex(CONSTANT_Class)); - cp_desc.expectLength(cpMap.length); - cp_desc.readFrom(in); - cp_desc.setIndex(getCPIndex(CONSTANT_NameandType)); - for (int i = 0; i < cpMap.length; i++) { - ClassEntry mclass = (ClassEntry ) cp_class.getRef(); - DescriptorEntry mdescr = (DescriptorEntry) cp_desc.getRef(); - cpMap[i] = ConstantPool.getMemberEntry(tag, mclass, mdescr); - } - cp_class.doneDisbursing(); - cp_desc.doneDisbursing(); - } - - void readFiles() throws IOException { - // file_bands: - // *file_name :UNSIGNED5 (cp_Utf8) - // *file_size_hi :UNSIGNED5 - // *file_size_lo :UNSIGNED5 - // *file_modtime :DELTA5 - // *file_options :UNSIGNED5 - // *file_bits :BYTE1 - if (verbose > 0) - Utils.log.info(" ...building "+numFiles+" files..."); - file_name.expectLength(numFiles); - file_size_lo.expectLength(numFiles); - int options = archiveOptions; - boolean haveSizeHi = testBit(options, AO_HAVE_FILE_SIZE_HI); - boolean haveModtime = testBit(options, AO_HAVE_FILE_MODTIME); - boolean haveOptions = testBit(options, AO_HAVE_FILE_OPTIONS); - if (haveSizeHi) - file_size_hi.expectLength(numFiles); - if (haveModtime) - file_modtime.expectLength(numFiles); - if (haveOptions) - file_options.expectLength(numFiles); - - file_name.readFrom(in); - file_size_hi.readFrom(in); - file_size_lo.readFrom(in); - file_modtime.readFrom(in); - file_options.readFrom(in); - file_bits.setInputStreamFrom(in); - - Iterator nextClass = pkg.getClasses().iterator(); - - // Compute file lengths before reading any file bits. - long totalFileLength = 0; - long[] fileLengths = new long[numFiles]; - for (int i = 0; i < numFiles; i++) { - long size = ((long)file_size_lo.getInt() << 32) >>> 32; - if (haveSizeHi) - size += (long)file_size_hi.getInt() << 32; - fileLengths[i] = size; - totalFileLength += size; - } - assert(in.getReadLimit() == -1 || in.getReadLimit() == totalFileLength); - - byte[] buf = new byte[1<<16]; - for (int i = 0; i < numFiles; i++) { - // %%% Use a big temp file for file bits? - Utf8Entry name = (Utf8Entry) file_name.getRef(); - long size = fileLengths[i]; - File file = pkg.new File(name); - file.modtime = pkg.default_modtime; - file.options = pkg.default_options; - if (haveModtime) - file.modtime += file_modtime.getInt(); - if (haveOptions) - file.options |= file_options.getInt(); - if (verbose > 1) - Utils.log.fine("Reading "+size+" bytes of "+name.stringValue()); - long toRead = size; - while (toRead > 0) { - int nr = buf.length; - if (nr > toRead) nr = (int) toRead; - nr = file_bits.getInputStream().read(buf, 0, nr); - if (nr < 0) throw new EOFException(); - file.addBytes(buf, 0, nr); - toRead -= nr; - } - pkg.addFile(file); - if (file.isClassStub()) { - assert(file.getFileLength() == 0); - Class cls = nextClass.next(); - cls.initFile(file); - } - } - - // Do the rest of the classes. - while (nextClass.hasNext()) { - Class cls = nextClass.next(); - cls.initFile(null); // implicitly initialize to a trivial one - cls.file.modtime = pkg.default_modtime; - } - - file_name.doneDisbursing(); - file_size_hi.doneDisbursing(); - file_size_lo.doneDisbursing(); - file_modtime.doneDisbursing(); - file_options.doneDisbursing(); - file_bits.doneDisbursing(); - file_bands.doneDisbursing(); - - if (archiveSize1 != 0 && !in.atLimit()) { - throw new RuntimeException("Predicted archive_size "+ - archiveSize1+" != "+ - (in.getBytesServed()-archiveSize0)); - } - } - - void readAttrDefs() throws IOException { - // attr_definition_bands: - // *attr_definition_headers :BYTE1 - // *attr_definition_name :UNSIGNED5 (cp_Utf8) - // *attr_definition_layout :UNSIGNED5 (cp_Utf8) - attr_definition_headers.expectLength(numAttrDefs); - attr_definition_name.expectLength(numAttrDefs); - attr_definition_layout.expectLength(numAttrDefs); - attr_definition_headers.readFrom(in); - attr_definition_name.readFrom(in); - attr_definition_layout.readFrom(in); - try (PrintStream dump = !optDumpBands ? null - : new PrintStream(getDumpStream(attr_definition_headers, ".def"))) - { - for (int i = 0; i < numAttrDefs; i++) { - int header = attr_definition_headers.getByte(); - Utf8Entry name = (Utf8Entry) attr_definition_name.getRef(); - Utf8Entry layout = (Utf8Entry) attr_definition_layout.getRef(); - int ctype = (header & ADH_CONTEXT_MASK); - int index = (header >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB; - Attribute.Layout def = new Attribute.Layout(ctype, - name.stringValue(), - layout.stringValue()); - // Check layout string for Java 6 extensions. - String pvLayout = def.layoutForClassVersion(getHighestClassVersion()); - if (!pvLayout.equals(def.layout())) { - throw new IOException("Bad attribute layout in archive: "+def.layout()); - } - this.setAttributeLayoutIndex(def, index); - if (dump != null) dump.println(index+" "+def); - } - } - attr_definition_headers.doneDisbursing(); - attr_definition_name.doneDisbursing(); - attr_definition_layout.doneDisbursing(); - // Attribute layouts define bands, one per layout element. - // Create them now, all at once. - makeNewAttributeBands(); - attr_definition_bands.doneDisbursing(); - } - - void readInnerClasses() throws IOException { - // ic_bands: - // *ic_this_class :UDELTA5 (cp_Class) - // *ic_flags :UNSIGNED5 - // *ic_outer_class :DELTA5 (null or cp_Class) - // *ic_name :DELTA5 (null or cp_Utf8) - ic_this_class.expectLength(numInnerClasses); - ic_this_class.readFrom(in); - ic_flags.expectLength(numInnerClasses); - ic_flags.readFrom(in); - int longICCount = 0; - for (int i = 0; i < numInnerClasses; i++) { - int flags = ic_flags.getInt(); - boolean longForm = (flags & ACC_IC_LONG_FORM) != 0; - if (longForm) { - longICCount += 1; - } - } - ic_outer_class.expectLength(longICCount); - ic_outer_class.readFrom(in); - ic_name.expectLength(longICCount); - ic_name.readFrom(in); - ic_flags.resetForSecondPass(); - List icList = new ArrayList<>(numInnerClasses); - for (int i = 0; i < numInnerClasses; i++) { - int flags = ic_flags.getInt(); - boolean longForm = (flags & ACC_IC_LONG_FORM) != 0; - flags &= ~ACC_IC_LONG_FORM; - ClassEntry thisClass = (ClassEntry) ic_this_class.getRef(); - ClassEntry outerClass; - Utf8Entry thisName; - if (longForm) { - outerClass = (ClassEntry) ic_outer_class.getRef(); - thisName = (Utf8Entry) ic_name.getRef(); - } else { - String n = thisClass.stringValue(); - String[] parse = Package.parseInnerClassName(n); - assert(parse != null); - String pkgOuter = parse[0]; - //String number = parse[1]; - String name = parse[2]; - if (pkgOuter == null) - outerClass = null; - else - outerClass = ConstantPool.getClassEntry(pkgOuter); - if (name == null) - thisName = null; - else - thisName = ConstantPool.getUtf8Entry(name); - } - InnerClass ic = - new InnerClass(thisClass, outerClass, thisName, flags); - assert(longForm || ic.predictable); - icList.add(ic); - } - ic_flags.doneDisbursing(); - ic_this_class.doneDisbursing(); - ic_outer_class.doneDisbursing(); - ic_name.doneDisbursing(); - pkg.setAllInnerClasses(icList); - ic_bands.doneDisbursing(); - } - - void readLocalInnerClasses(Class cls) throws IOException { - int nc = class_InnerClasses_N.getInt(); - List localICs = new ArrayList<>(nc); - for (int i = 0; i < nc; i++) { - ClassEntry thisClass = (ClassEntry) class_InnerClasses_RC.getRef(); - int flags = class_InnerClasses_F.getInt(); - if (flags == 0) { - // A zero flag means copy a global IC here. - InnerClass ic = pkg.getGlobalInnerClass(thisClass); - assert(ic != null); // must be a valid global IC reference - localICs.add(ic); - } else { - if (flags == ACC_IC_LONG_FORM) - flags = 0; // clear the marker bit - ClassEntry outer = (ClassEntry) class_InnerClasses_outer_RCN.getRef(); - Utf8Entry name = (Utf8Entry) class_InnerClasses_name_RUN.getRef(); - localICs.add(new InnerClass(thisClass, outer, name, flags)); - } - } - cls.setInnerClasses(localICs); - // cls.expandLocalICs may add more tuples to ics also, - // or may even delete tuples. - // We cannot do that now, because we do not know the - // full contents of the local constant pool yet. - } - - static final int NO_FLAGS_YET = 0; // placeholder for later flag read-in - - Class[] readClasses() throws IOException { - // class_bands: - // *class_this :DELTA5 (cp_Class) - // *class_super :DELTA5 (cp_Class) - // *class_interface_count :DELTA5 - // *class_interface :DELTA5 (cp_Class) - // ...(member bands)... - // class_attr_bands - // code_bands - Class[] classes = new Class[numClasses]; - if (verbose > 0) - Utils.log.info(" ...building "+classes.length+" classes..."); - - class_this.expectLength(numClasses); - class_super.expectLength(numClasses); - class_interface_count.expectLength(numClasses); - - class_this.readFrom(in); - class_super.readFrom(in); - class_interface_count.readFrom(in); - class_interface.expectLength(class_interface_count.getIntTotal()); - class_interface.readFrom(in); - for (int i = 0; i < classes.length; i++) { - ClassEntry thisClass = (ClassEntry) class_this.getRef(); - ClassEntry superClass = (ClassEntry) class_super.getRef(); - ClassEntry[] interfaces = new ClassEntry[class_interface_count.getInt()]; - for (int j = 0; j < interfaces.length; j++) { - interfaces[j] = (ClassEntry) class_interface.getRef(); - } - // Packer encoded rare case of null superClass as thisClass: - if (superClass == thisClass) superClass = null; - Class cls = pkg.new Class(NO_FLAGS_YET, - thisClass, superClass, interfaces); - classes[i] = cls; - } - class_this.doneDisbursing(); - class_super.doneDisbursing(); - class_interface_count.doneDisbursing(); - class_interface.doneDisbursing(); - readMembers(classes); - countAndReadAttrs(ATTR_CONTEXT_CLASS, Arrays.asList(classes)); - pkg.trimToSize(); - readCodeHeaders(); - //code_bands.doneDisbursing(); // still need to read code attrs - //class_bands.doneDisbursing(); // still need to read code attrs - return classes; - } - - private int getOutputIndex(Entry e) { - // Output CPs do not contain signatures. - assert(e.tag != CONSTANT_Signature); - int k = pkg.cp.untypedIndexOf(e); - // In the output ordering, input signatures can serve - // in place of Utf8s. - if (k >= 0) - return k; - if (e.tag == CONSTANT_Utf8) { - Entry se = utf8Signatures.get(e); - return pkg.cp.untypedIndexOf(se); - } - return -1; - } - - Comparator entryOutputOrder = new Comparator() { - public int compare(Entry e0, Entry e1) { - int k0 = getOutputIndex(e0); - int k1 = getOutputIndex(e1); - if (k0 >= 0 && k1 >= 0) - // If both have keys, use the keys. - return k0 - k1; - if (k0 == k1) - // If neither have keys, use their native tags & spellings. - return e0.compareTo(e1); - // Otherwise, the guy with the key comes first. - return (k0 >= 0)? 0-1: 1-0; - } - }; - - void reconstructClass(Class cls) { - if (verbose > 1) Utils.log.fine("reconstruct "+cls); - - // check for local .ClassFile.version - Attribute retroVersion = cls.getAttribute(attrClassFileVersion); - if (retroVersion != null) { - cls.removeAttribute(retroVersion); - cls.version = parseClassFileVersionAttr(retroVersion); - } else { - cls.version = pkg.defaultClassVersion; - } - - // Replace null SourceFile by "obvious" string. - cls.expandSourceFile(); - - // record the local cp: - cls.setCPMap(reconstructLocalCPMap(cls)); - } - - Entry[] reconstructLocalCPMap(Class cls) { - Set ldcRefs = ldcRefMap.get(cls); - Set cpRefs = new HashSet<>(); - - // look for constant pool entries: - cls.visitRefs(VRM_CLASSIC, cpRefs); - - ArrayList bsms = new ArrayList<>(); - /* - * BootstrapMethod(BSMs) are added here before InnerClasses(ICs), - * so as to ensure the order. Noting that the BSMs may be - * removed if they are not found in the CP, after the ICs expansion. - */ - cls.addAttribute(Package.attrBootstrapMethodsEmpty.canonicalInstance()); - - // flesh out the local constant pool - ConstantPool.completeReferencesIn(cpRefs, true, bsms); - - // remove the attr previously set, otherwise add the bsm and - // references as required - if (bsms.isEmpty()) { - cls.attributes.remove(Package.attrBootstrapMethodsEmpty.canonicalInstance()); - } else { - cpRefs.add(Package.getRefString("BootstrapMethods")); - Collections.sort(bsms); - cls.setBootstrapMethods(bsms); - } - - // Now that we know all our local class references, - // compute the InnerClasses attribute. - int changed = cls.expandLocalICs(); - - if (changed != 0) { - if (changed > 0) { - // Just visit the expanded InnerClasses attr. - cls.visitInnerClassRefs(VRM_CLASSIC, cpRefs); - } else { - // Have to recompute from scratch, because of deletions. - cpRefs.clear(); - cls.visitRefs(VRM_CLASSIC, cpRefs); - } - - // flesh out the local constant pool, again - ConstantPool.completeReferencesIn(cpRefs, true, bsms); - } - - // construct a local constant pool - int numDoubles = 0; - for (Entry e : cpRefs) { - if (e.isDoubleWord()) numDoubles++; - } - Entry[] cpMap = new Entry[1+numDoubles+cpRefs.size()]; - int fillp = 1; - - // Add all ldc operands first. - if (ldcRefs != null) { - assert(cpRefs.containsAll(ldcRefs)); - for (Entry e : ldcRefs) { - cpMap[fillp++] = e; - } - assert(fillp == 1+ldcRefs.size()); - cpRefs.removeAll(ldcRefs); - ldcRefs = null; // done with it - } - - // Next add all the two-byte references. - Set wideRefs = cpRefs; - cpRefs = null; // do not use! - int narrowLimit = fillp; - for (Entry e : wideRefs) { - cpMap[fillp++] = e; - } - assert(fillp == narrowLimit+wideRefs.size()); - Arrays.sort(cpMap, 1, narrowLimit, entryOutputOrder); - Arrays.sort(cpMap, narrowLimit, fillp, entryOutputOrder); - - if (verbose > 3) { - Utils.log.fine("CP of "+this+" {"); - for (int i = 0; i < fillp; i++) { - Entry e = cpMap[i]; - Utils.log.fine(" "+((e==null)?-1:getOutputIndex(e)) - +" : "+e); - } - Utils.log.fine("}"); - } - - // Now repack backwards, introducing null elements. - int revp = cpMap.length; - for (int i = fillp; --i >= 1; ) { - Entry e = cpMap[i]; - if (e.isDoubleWord()) - cpMap[--revp] = null; - cpMap[--revp] = e; - } - assert(revp == 1); // do not process the initial null - - return cpMap; - } - - void readMembers(Class[] classes) throws IOException { - // class_bands: - // ... - // *class_field_count :DELTA5 - // *class_method_count :DELTA5 - // - // *field_descr :DELTA5 (cp_Descr) - // field_attr_bands - // - // *method_descr :MDELTA5 (cp_Descr) - // method_attr_bands - // ... - assert(classes.length == numClasses); - class_field_count.expectLength(numClasses); - class_method_count.expectLength(numClasses); - class_field_count.readFrom(in); - class_method_count.readFrom(in); - - // Make a pre-pass over field and method counts to size the descrs: - int totalNF = class_field_count.getIntTotal(); - int totalNM = class_method_count.getIntTotal(); - field_descr.expectLength(totalNF); - method_descr.expectLength(totalNM); - if (verbose > 1) Utils.log.fine("expecting #fields="+totalNF+ - " and #methods="+totalNM+" in #classes="+numClasses); - - List fields = new ArrayList<>(totalNF); - field_descr.readFrom(in); - for (int i = 0; i < classes.length; i++) { - Class c = classes[i]; - int nf = class_field_count.getInt(); - for (int j = 0; j < nf; j++) { - Class.Field f = c.new Field(NO_FLAGS_YET, (DescriptorEntry) - field_descr.getRef()); - fields.add(f); - } - } - class_field_count.doneDisbursing(); - field_descr.doneDisbursing(); - countAndReadAttrs(ATTR_CONTEXT_FIELD, fields); - fields = null; // release to GC - - List methods = new ArrayList<>(totalNM); - method_descr.readFrom(in); - for (int i = 0; i < classes.length; i++) { - Class c = classes[i]; - int nm = class_method_count.getInt(); - for (int j = 0; j < nm; j++) { - Class.Method m = c.new Method(NO_FLAGS_YET, (DescriptorEntry) - method_descr.getRef()); - methods.add(m); - } - } - class_method_count.doneDisbursing(); - method_descr.doneDisbursing(); - countAndReadAttrs(ATTR_CONTEXT_METHOD, methods); - - // Up to this point, Code attributes look like empty attributes. - // Now we start to special-case them. The empty canonical Code - // attributes stay in the method attribute lists, however. - allCodes = buildCodeAttrs(methods); - } - - Code[] allCodes; - List codesWithFlags; - Map> ldcRefMap = new HashMap<>(); - - Code[] buildCodeAttrs(List methods) { - List codes = new ArrayList<>(methods.size()); - for (Class.Method m : methods) { - if (m.getAttribute(attrCodeEmpty) != null) { - m.code = new Code(m); - codes.add(m.code); - } - } - Code[] a = new Code[codes.size()]; - codes.toArray(a); - return a; - } - - void readCodeHeaders() throws IOException { - // code_bands: - // *code_headers :BYTE1 - // - // *code_max_stack :UNSIGNED5 - // *code_max_na_locals :UNSIGNED5 - // *code_handler_count :UNSIGNED5 - // ... - // code_attr_bands - boolean attrsOK = testBit(archiveOptions, AO_HAVE_ALL_CODE_FLAGS); - code_headers.expectLength(allCodes.length); - code_headers.readFrom(in); - List longCodes = new ArrayList<>(allCodes.length / 10); - for (int i = 0; i < allCodes.length; i++) { - Code c = allCodes[i]; - int sc = code_headers.getByte(); - assert(sc == (sc & 0xFF)); - if (verbose > 2) - Utils.log.fine("codeHeader "+c+" = "+sc); - if (sc == LONG_CODE_HEADER) { - // We will read ms/ml/nh/flags from bands shortly. - longCodes.add(c); - continue; - } - // Short code header is the usual case: - c.setMaxStack( shortCodeHeader_max_stack(sc) ); - c.setMaxNALocals( shortCodeHeader_max_na_locals(sc) ); - c.setHandlerCount( shortCodeHeader_handler_count(sc) ); - assert(shortCodeHeader(c) == sc); - } - code_headers.doneDisbursing(); - code_max_stack.expectLength(longCodes.size()); - code_max_na_locals.expectLength(longCodes.size()); - code_handler_count.expectLength(longCodes.size()); - - // Do the long headers now. - code_max_stack.readFrom(in); - code_max_na_locals.readFrom(in); - code_handler_count.readFrom(in); - for (Code c : longCodes) { - c.setMaxStack( code_max_stack.getInt() ); - c.setMaxNALocals( code_max_na_locals.getInt() ); - c.setHandlerCount( code_handler_count.getInt() ); - } - code_max_stack.doneDisbursing(); - code_max_na_locals.doneDisbursing(); - code_handler_count.doneDisbursing(); - - readCodeHandlers(); - - if (attrsOK) { - // Code attributes are common (debug info not stripped). - codesWithFlags = Arrays.asList(allCodes); - } else { - // Code attributes are very sparse (debug info is stripped). - codesWithFlags = longCodes; - } - countAttrs(ATTR_CONTEXT_CODE, codesWithFlags); - // do readAttrs later, after BCs are scanned - } - - void readCodeHandlers() throws IOException { - // code_bands: - // ... - // *code_handler_start_P :BCI5 - // *code_handler_end_PO :BRANCH5 - // *code_handler_catch_PO :BRANCH5 - // *code_handler_class_RCN :UNSIGNED5 (null or cp_Class) - // ... - int nh = 0; - for (int i = 0; i < allCodes.length; i++) { - Code c = allCodes[i]; - nh += c.getHandlerCount(); - } - - ValueBand[] code_handler_bands = { - code_handler_start_P, - code_handler_end_PO, - code_handler_catch_PO, - code_handler_class_RCN - }; - - for (int i = 0; i < code_handler_bands.length; i++) { - code_handler_bands[i].expectLength(nh); - code_handler_bands[i].readFrom(in); - } - - for (int i = 0; i < allCodes.length; i++) { - Code c = allCodes[i]; - for (int j = 0, jmax = c.getHandlerCount(); j < jmax; j++) { - c.handler_class[j] = code_handler_class_RCN.getRef(); - // For now, just record the raw BCI codes. - // We must wait until we have instruction boundaries. - c.handler_start[j] = code_handler_start_P.getInt(); - c.handler_end[j] = code_handler_end_PO.getInt(); - c.handler_catch[j] = code_handler_catch_PO.getInt(); - } - } - for (int i = 0; i < code_handler_bands.length; i++) { - code_handler_bands[i].doneDisbursing(); - } - } - - void fixupCodeHandlers() { - // Actually decode (renumber) the BCIs now. - for (int i = 0; i < allCodes.length; i++) { - Code c = allCodes[i]; - for (int j = 0, jmax = c.getHandlerCount(); j < jmax; j++) { - int sum = c.handler_start[j]; - c.handler_start[j] = c.decodeBCI(sum); - sum += c.handler_end[j]; - c.handler_end[j] = c.decodeBCI(sum); - sum += c.handler_catch[j]; - c.handler_catch[j] = c.decodeBCI(sum); - } - } - } - - // Generic routines for reading attributes of - // classes, fields, methods, and codes. - // The holders is a global list, already collected, - // of attribute "customers". - void countAndReadAttrs(int ctype, Collection holders) - throws IOException { - // class_attr_bands: - // *class_flags :UNSIGNED5 - // *class_attr_count :UNSIGNED5 - // *class_attr_indexes :UNSIGNED5 - // *class_attr_calls :UNSIGNED5 - // *class_Signature_RS :UNSIGNED5 (cp_Signature) - // class_metadata_bands - // *class_SourceFile_RU :UNSIGNED5 (cp_Utf8) - // *class_EnclosingMethod_RM :UNSIGNED5 (cp_Method) - // ic_local_bands - // *class_ClassFile_version_minor_H :UNSIGNED5 - // *class_ClassFile_version_major_H :UNSIGNED5 - // class_type_metadata_bands - // - // field_attr_bands: - // *field_flags :UNSIGNED5 - // *field_attr_count :UNSIGNED5 - // *field_attr_indexes :UNSIGNED5 - // *field_attr_calls :UNSIGNED5 - // *field_Signature_RS :UNSIGNED5 (cp_Signature) - // field_metadata_bands - // *field_ConstantValue_KQ :UNSIGNED5 (cp_Int, etc.; see note) - // field_type_metadata_bands - // - // method_attr_bands: - // *method_flags :UNSIGNED5 - // *method_attr_count :UNSIGNED5 - // *method_attr_indexes :UNSIGNED5 - // *method_attr_calls :UNSIGNED5 - // *method_Signature_RS :UNSIGNED5 (cp_Signature) - // method_metadata_bands - // *method_Exceptions_N :UNSIGNED5 - // *method_Exceptions_RC :UNSIGNED5 (cp_Class) - // *method_MethodParameters_NB: BYTE1 - // *method_MethodParameters_RUN: UNSIGNED5 (cp_Utf8) - // *method_MethodParameters_FH: UNSIGNED5 (flag) - // method_type_metadata_bands - // - // code_attr_bands: - // *code_flags :UNSIGNED5 - // *code_attr_count :UNSIGNED5 - // *code_attr_indexes :UNSIGNED5 - // *code_attr_calls :UNSIGNED5 - // *code_LineNumberTable_N :UNSIGNED5 - // *code_LineNumberTable_bci_P :BCI5 - // *code_LineNumberTable_line :UNSIGNED5 - // *code_LocalVariableTable_N :UNSIGNED5 - // *code_LocalVariableTable_bci_P :BCI5 - // *code_LocalVariableTable_span_O :BRANCH5 - // *code_LocalVariableTable_name_RU :UNSIGNED5 (cp_Utf8) - // *code_LocalVariableTable_type_RS :UNSIGNED5 (cp_Signature) - // *code_LocalVariableTable_slot :UNSIGNED5 - // code_type_metadata_bands - - countAttrs(ctype, holders); - readAttrs(ctype, holders); - } - - // Read flags and count the attributes that are to be placed - // on the given holders. - void countAttrs(int ctype, Collection holders) - throws IOException { - // Here, xxx stands for one of class, field, method, code. - MultiBand xxx_attr_bands = attrBands[ctype]; - long flagMask = attrFlagMask[ctype]; - if (verbose > 1) { - Utils.log.fine("scanning flags and attrs for "+ - Attribute.contextName(ctype)+"["+holders.size()+"]"); - } - - // Fetch the attribute layout definitions which govern the bands - // we are about to read. - List defList = attrDefs.get(ctype); - Attribute.Layout[] defs = new Attribute.Layout[defList.size()]; - defList.toArray(defs); - IntBand xxx_flags_hi = getAttrBand(xxx_attr_bands, AB_FLAGS_HI); - IntBand xxx_flags_lo = getAttrBand(xxx_attr_bands, AB_FLAGS_LO); - IntBand xxx_attr_count = getAttrBand(xxx_attr_bands, AB_ATTR_COUNT); - IntBand xxx_attr_indexes = getAttrBand(xxx_attr_bands, AB_ATTR_INDEXES); - IntBand xxx_attr_calls = getAttrBand(xxx_attr_bands, AB_ATTR_CALLS); - - // Count up the number of holders which have overflow attrs. - int overflowMask = attrOverflowMask[ctype]; - int overflowHolderCount = 0; - boolean haveLongFlags = haveFlagsHi(ctype); - xxx_flags_hi.expectLength(haveLongFlags? holders.size(): 0); - xxx_flags_hi.readFrom(in); - xxx_flags_lo.expectLength(holders.size()); - xxx_flags_lo.readFrom(in); - assert((flagMask & overflowMask) == overflowMask); - for (Attribute.Holder h : holders) { - int flags = xxx_flags_lo.getInt(); - h.flags = flags; - if ((flags & overflowMask) != 0) - overflowHolderCount += 1; - } - - // For each holder with overflow attrs, read a count. - xxx_attr_count.expectLength(overflowHolderCount); - xxx_attr_count.readFrom(in); - xxx_attr_indexes.expectLength(xxx_attr_count.getIntTotal()); - xxx_attr_indexes.readFrom(in); - - // Now it's time to check flag bits that indicate attributes. - // We accumulate (a) a list of attribute types for each holder - // (class/field/method/code), and also we accumulate (b) a total - // count for each attribute type. - int[] totalCounts = new int[defs.length]; - for (Attribute.Holder h : holders) { - assert(h.attributes == null); - // System.out.println("flags="+h.flags+" using fm="+flagMask); - long attrBits = ((h.flags & flagMask) << 32) >>> 32; - // Clean up the flags now. - h.flags -= (int)attrBits; // strip attr bits - assert(h.flags == (char)h.flags); // 16 bits only now - assert((ctype != ATTR_CONTEXT_CODE) || h.flags == 0); - if (haveLongFlags) - attrBits += (long)xxx_flags_hi.getInt() << 32; - if (attrBits == 0) continue; // no attrs on this guy - - int noa = 0; // number of overflow attrs - long overflowBit = (attrBits & overflowMask); - assert(overflowBit >= 0); - attrBits -= overflowBit; - if (overflowBit != 0) { - noa = xxx_attr_count.getInt(); - } - - int nfa = 0; // number of flag attrs - long bits = attrBits; - for (int ai = 0; bits != 0; ai++) { - if ((bits & (1L< ha = new ArrayList<>(nfa + noa); - h.attributes = ha; - bits = attrBits; // iterate again - for (int ai = 0; bits != 0; ai++) { - if ((bits & (1L< 0; noa--) { - int ai = xxx_attr_indexes.getInt(); - totalCounts[ai] += 1; - // This definition index is live in this holder. - if (defs[ai] == null) badAttrIndex(ai, ctype); - Attribute canonical = defs[ai].canonicalInstance(); - ha.add(canonical); - } - } - - xxx_flags_hi.doneDisbursing(); - xxx_flags_lo.doneDisbursing(); - xxx_attr_count.doneDisbursing(); - xxx_attr_indexes.doneDisbursing(); - - // Now each holder has a list of canonical attribute instances. - // For layouts with no elements, we are done. However, for - // layouts with bands, we must replace each canonical (empty) - // instance with a value-bearing one, initialized from the - // appropriate bands. - - // Make a small pass to detect and read backward call counts. - int callCounts = 0; - for (boolean predef = true; ; predef = false) { - for (int ai = 0; ai < defs.length; ai++) { - Attribute.Layout def = defs[ai]; - if (def == null) continue; // unused index - if (predef != isPredefinedAttr(ctype, ai)) - continue; // wrong pass - int totalCount = totalCounts[ai]; - if (totalCount == 0) - continue; // irrelevant - Attribute.Layout.Element[] cbles = def.getCallables(); - for (int j = 0; j < cbles.length; j++) { - assert(cbles[j].kind == Attribute.EK_CBLE); - if (cbles[j].flagTest(Attribute.EF_BACK)) - callCounts += 1; - } - } - if (!predef) break; - } - xxx_attr_calls.expectLength(callCounts); - xxx_attr_calls.readFrom(in); - - // Finally, size all the attribute bands. - for (boolean predef = true; ; predef = false) { - for (int ai = 0; ai < defs.length; ai++) { - Attribute.Layout def = defs[ai]; - if (def == null) continue; // unused index - if (predef != isPredefinedAttr(ctype, ai)) - continue; // wrong pass - int totalCount = totalCounts[ai]; - Band[] ab = attrBandTable.get(def); - if (def == attrInnerClassesEmpty) { - // Special case. - // Size the bands as if using the following layout: - // [RCH TI[ (0)[] ()[RCNH RUNH] ]]. - class_InnerClasses_N.expectLength(totalCount); - class_InnerClasses_N.readFrom(in); - int tupleCount = class_InnerClasses_N.getIntTotal(); - class_InnerClasses_RC.expectLength(tupleCount); - class_InnerClasses_RC.readFrom(in); - class_InnerClasses_F.expectLength(tupleCount); - class_InnerClasses_F.readFrom(in); - // Drop remaining columns wherever flags are zero: - tupleCount -= class_InnerClasses_F.getIntCount(0); - class_InnerClasses_outer_RCN.expectLength(tupleCount); - class_InnerClasses_outer_RCN.readFrom(in); - class_InnerClasses_name_RUN.expectLength(tupleCount); - class_InnerClasses_name_RUN.readFrom(in); - } else if (!optDebugBands && totalCount == 0) { - // Expect no elements at all. Skip quickly. however if we - // are debugging bands, read all bands regardless - for (int j = 0; j < ab.length; j++) { - ab[j].doneWithUnusedBand(); - } - } else { - // Read these bands in sequence. - boolean hasCallables = def.hasCallables(); - if (!hasCallables) { - readAttrBands(def.elems, totalCount, new int[0], ab); - } else { - Attribute.Layout.Element[] cbles = def.getCallables(); - // At first, record initial calls. - // Later, forward calls may also accumulate here: - int[] forwardCounts = new int[cbles.length]; - forwardCounts[0] = totalCount; - for (int j = 0; j < cbles.length; j++) { - assert(cbles[j].kind == Attribute.EK_CBLE); - int entryCount = forwardCounts[j]; - forwardCounts[j] = -1; // No more, please! - if (totalCount > 0 && cbles[j].flagTest(Attribute.EF_BACK)) - entryCount += xxx_attr_calls.getInt(); - readAttrBands(cbles[j].body, entryCount, forwardCounts, ab); - } - } - // mark them read, to satisfy asserts - if (optDebugBands && totalCount == 0) { - for (int j = 0; j < ab.length; j++) { - ab[j].doneDisbursing(); - } - } - } - } - if (!predef) break; - } - xxx_attr_calls.doneDisbursing(); - } - - void badAttrIndex(int ai, int ctype) throws IOException { - throw new IOException("Unknown attribute index "+ai+" for "+ - ATTR_CONTEXT_NAME[ctype]+" attribute"); - } - - void readAttrs(int ctype, Collection holders) - throws IOException { - // Decode band values into attributes. - Set sawDefs = new HashSet<>(); - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - for (final Attribute.Holder h : holders) { - if (h.attributes == null) continue; - for (ListIterator j = h.attributes.listIterator(); j.hasNext(); ) { - Attribute a = j.next(); - Attribute.Layout def = a.layout(); - if (def.bandCount == 0) { - if (def == attrInnerClassesEmpty) { - // Special logic to read this attr. - readLocalInnerClasses((Class) h); - continue; - } - // Canonical empty attr works fine (e.g., Synthetic). - continue; - } - sawDefs.add(def); - boolean isCV = (ctype == ATTR_CONTEXT_FIELD && def == attrConstantValue); - if (isCV) setConstantValueIndex((Class.Field)h); - if (verbose > 2) - Utils.log.fine("read "+a+" in "+h); - final Band[] ab = attrBandTable.get(def); - // Read one attribute of type def from ab into a byte array. - buf.reset(); - Object fixups = a.unparse(new Attribute.ValueStream() { - public int getInt(int bandIndex) { - return ((IntBand) ab[bandIndex]).getInt(); - } - public Entry getRef(int bandIndex) { - return ((CPRefBand) ab[bandIndex]).getRef(); - } - public int decodeBCI(int bciCode) { - Code code = (Code) h; - return code.decodeBCI(bciCode); - } - }, buf); - // Replace the canonical attr with the one just read. - j.set(a.addContent(buf.toByteArray(), fixups)); - if (isCV) setConstantValueIndex(null); // clean up - } - } - - // Mark the bands we just used as done disbursing. - for (Attribute.Layout def : sawDefs) { - if (def == null) continue; // unused index - Band[] ab = attrBandTable.get(def); - for (int j = 0; j < ab.length; j++) { - ab[j].doneDisbursing(); - } - } - - if (ctype == ATTR_CONTEXT_CLASS) { - class_InnerClasses_N.doneDisbursing(); - class_InnerClasses_RC.doneDisbursing(); - class_InnerClasses_F.doneDisbursing(); - class_InnerClasses_outer_RCN.doneDisbursing(); - class_InnerClasses_name_RUN.doneDisbursing(); - } - - MultiBand xxx_attr_bands = attrBands[ctype]; - for (int i = 0; i < xxx_attr_bands.size(); i++) { - Band b = xxx_attr_bands.get(i); - if (b instanceof MultiBand) - b.doneDisbursing(); - } - xxx_attr_bands.doneDisbursing(); - } - - private - void readAttrBands(Attribute.Layout.Element[] elems, - int count, int[] forwardCounts, - Band[] ab) - throws IOException { - for (int i = 0; i < elems.length; i++) { - Attribute.Layout.Element e = elems[i]; - Band eBand = null; - if (e.hasBand()) { - eBand = ab[e.bandIndex]; - eBand.expectLength(count); - eBand.readFrom(in); - } - switch (e.kind) { - case Attribute.EK_REPL: - // Recursive call. - int repCount = ((IntBand)eBand).getIntTotal(); - // Note: getIntTotal makes an extra pass over this band. - readAttrBands(e.body, repCount, forwardCounts, ab); - break; - case Attribute.EK_UN: - int remainingCount = count; - for (int j = 0; j < e.body.length; j++) { - int caseCount; - if (j == e.body.length-1) { - caseCount = remainingCount; - } else { - caseCount = 0; - for (int j0 = j; - (j == j0) - || (j < e.body.length - && e.body[j].flagTest(Attribute.EF_BACK)); - j++) { - caseCount += ((IntBand)eBand).getIntCount(e.body[j].value); - } - --j; // back up to last occurrence of this body - } - remainingCount -= caseCount; - readAttrBands(e.body[j].body, caseCount, forwardCounts, ab); - } - assert(remainingCount == 0); - break; - case Attribute.EK_CALL: - assert(e.body.length == 1); - assert(e.body[0].kind == Attribute.EK_CBLE); - if (!e.flagTest(Attribute.EF_BACK)) { - // Backward calls are pre-counted, but forwards are not. - // Push the present count forward. - assert(forwardCounts[e.value] >= 0); - forwardCounts[e.value] += count; - } - break; - case Attribute.EK_CBLE: - assert(false); - break; - } - } - } - - void readByteCodes() throws IOException { - // bc_bands: - // *bc_codes :BYTE1 - // *bc_case_count :UNSIGNED5 - // *bc_case_value :DELTA5 - // *bc_byte :BYTE1 - // *bc_short :DELTA5 - // *bc_local :UNSIGNED5 - // *bc_label :BRANCH5 - // *bc_intref :DELTA5 (cp_Int) - // *bc_floatref :DELTA5 (cp_Float) - // *bc_longref :DELTA5 (cp_Long) - // *bc_doubleref :DELTA5 (cp_Double) - // *bc_stringref :DELTA5 (cp_String) - // *bc_classref :UNSIGNED5 (current class or cp_Class) - // *bc_fieldref :DELTA5 (cp_Field) - // *bc_methodref :UNSIGNED5 (cp_Method) - // *bc_imethodref :DELTA5 (cp_Imethod) - // *bc_thisfield :UNSIGNED5 (cp_Field, only for current class) - // *bc_superfield :UNSIGNED5 (cp_Field, only for current super) - // *bc_thismethod :UNSIGNED5 (cp_Method, only for current class) - // *bc_supermethod :UNSIGNED5 (cp_Method, only for current super) - // *bc_initref :UNSIGNED5 (cp_Field, only for most recent new) - // *bc_escref :UNSIGNED5 (cp_All) - // *bc_escrefsize :UNSIGNED5 - // *bc_escsize :UNSIGNED5 - // *bc_escbyte :BYTE1 - bc_codes.elementCountForDebug = allCodes.length; - bc_codes.setInputStreamFrom(in); - readByteCodeOps(); // reads from bc_codes and bc_case_count - bc_codes.doneDisbursing(); - - // All the operand bands have now been sized. Read them all in turn. - Band[] operand_bands = { - bc_case_value, - bc_byte, bc_short, - bc_local, bc_label, - bc_intref, bc_floatref, - bc_longref, bc_doubleref, bc_stringref, - bc_loadablevalueref, - bc_classref, bc_fieldref, - bc_methodref, bc_imethodref, - bc_indyref, - bc_thisfield, bc_superfield, - bc_thismethod, bc_supermethod, - bc_initref, - bc_escref, bc_escrefsize, bc_escsize - }; - for (int i = 0; i < operand_bands.length; i++) { - operand_bands[i].readFrom(in); - } - bc_escbyte.expectLength(bc_escsize.getIntTotal()); - bc_escbyte.readFrom(in); - - expandByteCodeOps(); - - // Done fetching values from operand bands: - bc_case_count.doneDisbursing(); - for (int i = 0; i < operand_bands.length; i++) { - operand_bands[i].doneDisbursing(); - } - bc_escbyte.doneDisbursing(); - bc_bands.doneDisbursing(); - - // We must delay the parsing of Code attributes until we - // have a complete model of bytecodes, for BCI encodings. - readAttrs(ATTR_CONTEXT_CODE, codesWithFlags); - // Ditto for exception handlers in codes. - fixupCodeHandlers(); - // Now we can finish with class_bands; cf. readClasses(). - code_bands.doneDisbursing(); - class_bands.doneDisbursing(); - } - - private void readByteCodeOps() throws IOException { - // scratch buffer for collecting code:: - byte[] buf = new byte[1<<12]; - // record of all switch opcodes (these are variable-length) - List allSwitchOps = new ArrayList<>(); - for (int k = 0; k < allCodes.length; k++) { - Code c = allCodes[k]; - scanOneMethod: - for (int i = 0; ; i++) { - int bc = bc_codes.getByte(); - if (i + 10 > buf.length) buf = realloc(buf); - buf[i] = (byte)bc; - boolean isWide = false; - if (bc == _wide) { - bc = bc_codes.getByte(); - buf[++i] = (byte)bc; - isWide = true; - } - assert(bc == (0xFF & bc)); - // Adjust expectations of various band sizes. - switch (bc) { - case _tableswitch: - case _lookupswitch: - bc_case_count.expectMoreLength(1); - allSwitchOps.add(bc); - break; - case _iinc: - bc_local.expectMoreLength(1); - if (isWide) - bc_short.expectMoreLength(1); - else - bc_byte.expectMoreLength(1); - break; - case _sipush: - bc_short.expectMoreLength(1); - break; - case _bipush: - bc_byte.expectMoreLength(1); - break; - case _newarray: - bc_byte.expectMoreLength(1); - break; - case _multianewarray: - assert(getCPRefOpBand(bc) == bc_classref); - bc_classref.expectMoreLength(1); - bc_byte.expectMoreLength(1); - break; - case _ref_escape: - bc_escrefsize.expectMoreLength(1); - bc_escref.expectMoreLength(1); - break; - case _byte_escape: - bc_escsize.expectMoreLength(1); - // bc_escbyte will have to be counted too - break; - default: - if (Instruction.isInvokeInitOp(bc)) { - bc_initref.expectMoreLength(1); - break; - } - if (Instruction.isSelfLinkerOp(bc)) { - CPRefBand bc_which = selfOpRefBand(bc); - bc_which.expectMoreLength(1); - break; - } - if (Instruction.isBranchOp(bc)) { - bc_label.expectMoreLength(1); - break; - } - if (Instruction.isCPRefOp(bc)) { - CPRefBand bc_which = getCPRefOpBand(bc); - bc_which.expectMoreLength(1); - assert(bc != _multianewarray); // handled elsewhere - break; - } - if (Instruction.isLocalSlotOp(bc)) { - bc_local.expectMoreLength(1); - break; - } - break; - case _end_marker: - { - // Transfer from buf to a more permanent place: - c.bytes = realloc(buf, i); - break scanOneMethod; - } - } - } - } - - // To size instruction bands correctly, we need info on switches: - bc_case_count.readFrom(in); - for (Integer i : allSwitchOps) { - int bc = i.intValue(); - int caseCount = bc_case_count.getInt(); - bc_label.expectMoreLength(1+caseCount); // default label + cases - bc_case_value.expectMoreLength(bc == _tableswitch ? 1 : caseCount); - } - bc_case_count.resetForSecondPass(); - } - - private void expandByteCodeOps() throws IOException { - // scratch buffer for collecting code: - byte[] buf = new byte[1<<12]; - // scratch buffer for collecting instruction boundaries: - int[] insnMap = new int[1<<12]; - // list of label carriers, for label decoding post-pass: - int[] labels = new int[1<<10]; - // scratch buffer for registering CP refs: - Fixups fixupBuf = new Fixups(); - - for (int k = 0; k < allCodes.length; k++) { - Code code = allCodes[k]; - byte[] codeOps = code.bytes; - code.bytes = null; // just for now, while we accumulate bits - - Class curClass = code.thisClass(); - - Set ldcRefSet = ldcRefMap.get(curClass); - if (ldcRefSet == null) - ldcRefMap.put(curClass, ldcRefSet = new HashSet<>()); - - ClassEntry thisClass = curClass.thisClass; - ClassEntry superClass = curClass.superClass; - ClassEntry newClass = null; // class of last _new opcode - - int pc = 0; // fill pointer in buf; actual bytecode PC - int numInsns = 0; - int numLabels = 0; - boolean hasEscs = false; - fixupBuf.clear(); - for (int i = 0; i < codeOps.length; i++) { - int bc = Instruction.getByte(codeOps, i); - int curPC = pc; - insnMap[numInsns++] = curPC; - if (pc + 10 > buf.length) buf = realloc(buf); - if (numInsns+10 > insnMap.length) insnMap = realloc(insnMap); - if (numLabels+10 > labels.length) labels = realloc(labels); - boolean isWide = false; - if (bc == _wide) { - buf[pc++] = (byte) bc; - bc = Instruction.getByte(codeOps, ++i); - isWide = true; - } - switch (bc) { - case _tableswitch: // apc: (df, lo, hi, (hi-lo+1)*(label)) - case _lookupswitch: // apc: (df, nc, nc*(case, label)) - { - int caseCount = bc_case_count.getInt(); - while ((pc + 30 + caseCount*8) > buf.length) - buf = realloc(buf); - buf[pc++] = (byte) bc; - //initialize apc, df, lo, hi bytes to reasonable bits: - Arrays.fill(buf, pc, pc+30, (byte)0); - Instruction.Switch isw = (Instruction.Switch) - Instruction.at(buf, curPC); - //isw.setDefaultLabel(getLabel(bc_label, code, curPC)); - isw.setCaseCount(caseCount); - if (bc == _tableswitch) { - isw.setCaseValue(0, bc_case_value.getInt()); - } else { - for (int j = 0; j < caseCount; j++) { - isw.setCaseValue(j, bc_case_value.getInt()); - } - } - // Make our getLabel calls later. - labels[numLabels++] = curPC; - pc = isw.getNextPC(); - continue; - } - case _iinc: - { - buf[pc++] = (byte) bc; - int local = bc_local.getInt(); - int delta; - if (isWide) { - delta = bc_short.getInt(); - Instruction.setShort(buf, pc, local); pc += 2; - Instruction.setShort(buf, pc, delta); pc += 2; - } else { - delta = (byte) bc_byte.getByte(); - buf[pc++] = (byte)local; - buf[pc++] = (byte)delta; - } - continue; - } - case _sipush: - { - int val = bc_short.getInt(); - buf[pc++] = (byte) bc; - Instruction.setShort(buf, pc, val); pc += 2; - continue; - } - case _bipush: - case _newarray: - { - int val = bc_byte.getByte(); - buf[pc++] = (byte) bc; - buf[pc++] = (byte) val; - continue; - } - case _ref_escape: - { - // Note that insnMap has one entry for this. - hasEscs = true; - int size = bc_escrefsize.getInt(); - Entry ref = bc_escref.getRef(); - if (size == 1) ldcRefSet.add(ref); - int fmt; - switch (size) { - case 1: fixupBuf.addU1(pc, ref); break; - case 2: fixupBuf.addU2(pc, ref); break; - default: assert(false); fmt = 0; - } - buf[pc+0] = buf[pc+1] = 0; - pc += size; - } - continue; - case _byte_escape: - { - // Note that insnMap has one entry for all these bytes. - hasEscs = true; - int size = bc_escsize.getInt(); - while ((pc + size) > buf.length) - buf = realloc(buf); - while (size-- > 0) { - buf[pc++] = (byte) bc_escbyte.getByte(); - } - } - continue; - default: - if (Instruction.isInvokeInitOp(bc)) { - int idx = (bc - _invokeinit_op); - int origBC = _invokespecial; - ClassEntry classRef; - switch (idx) { - case _invokeinit_self_option: - classRef = thisClass; break; - case _invokeinit_super_option: - classRef = superClass; break; - default: - assert(idx == _invokeinit_new_option); - classRef = newClass; break; - } - buf[pc++] = (byte) origBC; - int coding = bc_initref.getInt(); - // Find the nth overloading of in classRef. - MemberEntry ref = pkg.cp.getOverloadingForIndex(CONSTANT_Methodref, classRef, "", coding); - fixupBuf.addU2(pc, ref); - buf[pc+0] = buf[pc+1] = 0; - pc += 2; - assert(Instruction.opLength(origBC) == (pc - curPC)); - continue; - } - if (Instruction.isSelfLinkerOp(bc)) { - int idx = (bc - _self_linker_op); - boolean isSuper = (idx >= _self_linker_super_flag); - if (isSuper) idx -= _self_linker_super_flag; - boolean isAload = (idx >= _self_linker_aload_flag); - if (isAload) idx -= _self_linker_aload_flag; - int origBC = _first_linker_op + idx; - boolean isField = Instruction.isFieldOp(origBC); - CPRefBand bc_which; - ClassEntry which_cls = isSuper ? superClass : thisClass; - Index which_ix; - if (isField) { - bc_which = isSuper ? bc_superfield : bc_thisfield; - which_ix = pkg.cp.getMemberIndex(CONSTANT_Fieldref, which_cls); - } else { - bc_which = isSuper ? bc_supermethod : bc_thismethod; - which_ix = pkg.cp.getMemberIndex(CONSTANT_Methodref, which_cls); - } - assert(bc_which == selfOpRefBand(bc)); - MemberEntry ref = (MemberEntry) bc_which.getRef(which_ix); - if (isAload) { - buf[pc++] = (byte) _aload_0; - curPC = pc; - // Note: insnMap keeps the _aload_0 separate. - insnMap[numInsns++] = curPC; - } - buf[pc++] = (byte) origBC; - fixupBuf.addU2(pc, ref); - buf[pc+0] = buf[pc+1] = 0; - pc += 2; - assert(Instruction.opLength(origBC) == (pc - curPC)); - continue; - } - if (Instruction.isBranchOp(bc)) { - buf[pc++] = (byte) bc; - assert(!isWide); // no wide prefix for branches - int nextPC = curPC + Instruction.opLength(bc); - // Make our getLabel calls later. - labels[numLabels++] = curPC; - //Instruction.at(buf, curPC).setBranchLabel(getLabel(bc_label, code, curPC)); - while (pc < nextPC) buf[pc++] = 0; - continue; - } - if (Instruction.isCPRefOp(bc)) { - CPRefBand bc_which = getCPRefOpBand(bc); - Entry ref = bc_which.getRef(); - if (ref == null) { - if (bc_which == bc_classref) { - // Shorthand for class self-references. - ref = thisClass; - } else { - assert(false); - } - } - int origBC = bc; - int size = 2; - switch (bc) { - case _invokestatic_int: - origBC = _invokestatic; - break; - case _invokespecial_int: - origBC = _invokespecial; - break; - case _ildc: - case _cldc: - case _fldc: - case _sldc: - case _qldc: - origBC = _ldc; - size = 1; - ldcRefSet.add(ref); - break; - case _ildc_w: - case _cldc_w: - case _fldc_w: - case _sldc_w: - case _qldc_w: - origBC = _ldc_w; - break; - case _lldc2_w: - case _dldc2_w: - origBC = _ldc2_w; - break; - case _new: - newClass = (ClassEntry) ref; - break; - } - buf[pc++] = (byte) origBC; - int fmt; - switch (size) { - case 1: fixupBuf.addU1(pc, ref); break; - case 2: fixupBuf.addU2(pc, ref); break; - default: assert(false); fmt = 0; - } - buf[pc+0] = buf[pc+1] = 0; - pc += size; - if (origBC == _multianewarray) { - // Copy the trailing byte also. - int val = bc_byte.getByte(); - buf[pc++] = (byte) val; - } else if (origBC == _invokeinterface) { - int argSize = ((MemberEntry)ref).descRef.typeRef.computeSize(true); - buf[pc++] = (byte)( 1 + argSize ); - buf[pc++] = 0; - } else if (origBC == _invokedynamic) { - buf[pc++] = 0; - buf[pc++] = 0; - } - assert(Instruction.opLength(origBC) == (pc - curPC)); - continue; - } - if (Instruction.isLocalSlotOp(bc)) { - buf[pc++] = (byte) bc; - int local = bc_local.getInt(); - if (isWide) { - Instruction.setShort(buf, pc, local); - pc += 2; - if (bc == _iinc) { - int iVal = bc_short.getInt(); - Instruction.setShort(buf, pc, iVal); - pc += 2; - } - } else { - Instruction.setByte(buf, pc, local); - pc += 1; - if (bc == _iinc) { - int iVal = bc_byte.getByte(); - Instruction.setByte(buf, pc, iVal); - pc += 1; - } - } - assert(Instruction.opLength(bc) == (pc - curPC)); - continue; - } - // Random bytecode. Just copy it. - if (bc >= _bytecode_limit) - Utils.log.warning("unrecognized bytescode "+bc - +" "+Instruction.byteName(bc)); - assert(bc < _bytecode_limit); - buf[pc++] = (byte) bc; - assert(Instruction.opLength(bc) == (pc - curPC)); - continue; - } - } - // now make a permanent copy of the bytecodes - code.setBytes(realloc(buf, pc)); - code.setInstructionMap(insnMap, numInsns); - // fix up labels, now that code has its insnMap - Instruction ibr = null; // temporary branch instruction - for (int i = 0; i < numLabels; i++) { - int curPC = labels[i]; - // (Note: Passing ibr in allows reuse, a speed hack.) - ibr = Instruction.at(code.bytes, curPC, ibr); - if (ibr instanceof Instruction.Switch) { - Instruction.Switch isw = (Instruction.Switch) ibr; - isw.setDefaultLabel(getLabel(bc_label, code, curPC)); - int caseCount = isw.getCaseCount(); - for (int j = 0; j < caseCount; j++) { - isw.setCaseLabel(j, getLabel(bc_label, code, curPC)); - } - } else { - ibr.setBranchLabel(getLabel(bc_label, code, curPC)); - } - } - if (fixupBuf.size() > 0) { - if (verbose > 2) - Utils.log.fine("Fixups in code: "+fixupBuf); - code.addFixups(fixupBuf); - } - } - } -} diff --git a/src/IKVM.Java/local/ikvm/lang/ModuleInitializer.java b/src/IKVM.Java/local/ikvm/lang/ModuleInitializer.java new file mode 100644 index 0000000000..6f2b61ca28 --- /dev/null +++ b/src/IKVM.Java/local/ikvm/lang/ModuleInitializer.java @@ -0,0 +1,15 @@ +package ikvm.lang; + +import java.lang.annotation.*; + +/** + * Used to indicate to the compiler that a method should be called in its containing module's initializer. + */ + +@Documented +@Retention(RetentionPolicy.CLASS) +@Target({ ElementType.METHOD }) +public @interface ModuleInitializer +{ + +} diff --git a/src/IKVM.Java/local/java/io/DefaultFileSystem.java b/src/IKVM.Java/local/java/io/DefaultFileSystem.java deleted file mode 100644 index 64e84b7964..0000000000 --- a/src/IKVM.Java/local/java/io/DefaultFileSystem.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright (C) 2014 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -package java.io; - -class DefaultFileSystem { - - static FileSystem getFileSystem() { - return cli.IKVM.Runtime.RuntimeUtil.get_IsWindows() ? new WinNTFileSystem() : new UnixFileSystem(); - } - -} diff --git a/src/IKVM.Java/local/java/io/FileDescriptor.java b/src/IKVM.Java/local/java/io/FileDescriptor.java index 50d4db9b7a..6eabdac75d 100644 --- a/src/IKVM.Java/local/java/io/FileDescriptor.java +++ b/src/IKVM.Java/local/java/io/FileDescriptor.java @@ -40,7 +40,7 @@ public long getHandle(FileDescriptor obj) { ); } - private volatile Object obj; + private volatile cli.System.IO.Stream stream; private volatile long ptr; @ikvm.lang.Property(get = "getFd", set = "setFd") @@ -58,15 +58,6 @@ public long getHandle(FileDescriptor obj) { private Closeable parent; private List otherParents; private boolean closed; - - private cli.System.Threading.SemaphoreSlim semaphore; - private cli.System.Threading.Tasks.Task task; - - @ikvm.lang.Internal - public native cli.System.IO.Stream getStream(); - - @ikvm.lang.Internal - public native cli.System.Net.Sockets.Socket getSocket(); /** * Constructs an (invalid) FileDescriptor @@ -220,4 +211,4 @@ synchronized void closeAll(Closeable releaser) throws IOException { } } -} +} \ No newline at end of file diff --git a/src/IKVM.Java/local/java/lang/ClassLoaderHelper.java b/src/IKVM.Java/local/java/lang/ClassLoaderHelper.java deleted file mode 100644 index 1c08b6e50a..0000000000 --- a/src/IKVM.Java/local/java/lang/ClassLoaderHelper.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package java.lang; - -import java.io.File; - -class ClassLoaderHelper { - - private ClassLoaderHelper() {} - - /** - * Returns an alternate path name for the given file - * such that if the original pathname did not exist, then the - * file may be located at the alternate location. - * For mac, this replaces the final .dylib suffix with .jnilib - */ - static File mapAlternativeName(File lib) { - if (cli.IKVM.Runtime.RuntimeUtil.get_IsOSX() == false) { - return null; - } - - String name = lib.toString(); - int index = name.lastIndexOf('.'); - if (index < 0) { - return null; - } - return new File(name.substring(0, index) + ".jnilib"); - } -} diff --git a/src/IKVM.Java/local/java/lang/ProcessImpl.java b/src/IKVM.Java/local/java/lang/ProcessImpl.java deleted file mode 100644 index a931aa029d..0000000000 --- a/src/IKVM.Java/local/java/lang/ProcessImpl.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang; - -import java.io.IOException; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.lang.ProcessBuilder.Redirect; -import java.util.*; - -/** - * This class is for the exclusive use of ProcessBuilder.start() to - * create new processes. - * - * @author Martin Buchholz - * @since 1.5 - */ -final class ProcessImpl { - - public native void dummy(); - - private static final sun.misc.JavaIOFileDescriptorAccess fdAccess - = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess(); - - private ProcessImpl() {} // Not instantiable - - private static byte[] toCString(String s) { - if (s == null) - return null; - byte[] bytes = s.getBytes(); - byte[] result = new byte[bytes.length + 1]; - System.arraycopy(bytes, 0, - result, 0, - bytes.length); - result[result.length-1] = (byte)0; - return result; - } - - // Only for use by ProcessBuilder.start() - static Process start(String[] cmdarray, - java.util.Map environment, - String dir, - ProcessBuilder.Redirect[] redirects, - boolean redirectErrorStream) - throws IOException - { - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - return Win32Process.start(cmdarray, environment, dir, redirects, redirectErrorStream); - } else { - - assert cmdarray != null && cmdarray.length > 0; - - // Convert arguments to a contiguous block; it's easier to do - // memory management in Java than in C. - byte[][] args = new byte[cmdarray.length-1][]; - int size = args.length; // For added NUL bytes - for (int i = 0; i < args.length; i++) { - args[i] = cmdarray[i+1].getBytes(); - size += args[i].length; - } - byte[] argBlock = new byte[size]; - int i = 0; - for (byte[] arg : args) { - System.arraycopy(arg, 0, argBlock, i, arg.length); - i += arg.length + 1; - // No need to write NUL bytes explicitly - } - - int[] envc = new int[1]; - byte[] envBlock = UNIXProcessEnvironment.toEnvironmentBlock(environment, envc); - - int[] std_fds; - - FileInputStream f0 = null; - FileOutputStream f1 = null; - FileOutputStream f2 = null; - - try { - if (redirects == null) { - std_fds = new int[] { -1, -1, -1 }; - } else { - std_fds = new int[3]; - - if (redirects[0] == Redirect.PIPE) - std_fds[0] = -1; - else if (redirects[0] == Redirect.INHERIT) - std_fds[0] = 0; - else { - f0 = new FileInputStream(redirects[0].file()); - std_fds[0] = fdAccess.get(f0.getFD()); - } - - if (redirects[1] == Redirect.PIPE) - std_fds[1] = -1; - else if (redirects[1] == Redirect.INHERIT) - std_fds[1] = 1; - else { - f1 = new FileOutputStream(redirects[1].file(), - redirects[1].append()); - std_fds[1] = fdAccess.get(f1.getFD()); - } - - if (redirects[2] == Redirect.PIPE) - std_fds[2] = -1; - else if (redirects[2] == Redirect.INHERIT) - std_fds[2] = 2; - else { - f2 = new FileOutputStream(redirects[2].file(), - redirects[2].append()); - std_fds[2] = fdAccess.get(f2.getFD()); - } - } - - return new UNIXProcess - (toCString(cmdarray[0]), - argBlock, args.length, - envBlock, envc[0], - toCString(dir), - std_fds, - redirectErrorStream); - } finally { - // In theory, close() can throw IOException - // (although it is rather unlikely to happen here) - try { if (f0 != null) f0.close(); } - finally { - try { if (f1 != null) f1.close(); } - finally { if (f2 != null) f2.close(); } - } - } - - } - } -} diff --git a/src/IKVM.Java/local/java/lang/Thread.java b/src/IKVM.Java/local/java/lang/Thread.java index b48ef57efe..6c9512666a 100644 --- a/src/IKVM.Java/local/java/lang/Thread.java +++ b/src/IKVM.Java/local/java/lang/Thread.java @@ -139,6 +139,7 @@ */ public class Thread implements Runnable { + // [IKVM] static { // force the set/getContextClassLoader methods to be JIT compiled, because isCCLOverridden(Thread) depends on it @@ -147,14 +148,17 @@ class Thread implements Runnable { dummy.getContextClassLoader(); dummy.setContextClassLoader(ClassLoader.DUMMY); } + private Thread(Void _) { // body replaced in map.xml } + final class Cleanup { protected void finalize() { Thread.this.die(); } } + /* --- start IKVM specific state --- */ static final int[] nonDaemonCount = new int[1]; @cli.System.ThreadStaticAttribute.Annotation @@ -166,6 +170,8 @@ protected void finalize() { private Throwable stillborn; private boolean running; // used only for coordination with stop0(), is never set to false private volatile boolean interruptPending; + @ikvm.lang.Internal // made available through libjvm as JVM_GetThreadInterruptEvent + public volatile cli.System.Threading.ManualResetEvent interruptEvent = new cli.System.Threading.ManualResetEvent(false); private volatile boolean nativeInterruptPending; private volatile boolean interruptableWait; private boolean timedWait; @@ -322,8 +328,10 @@ private void enterInterruptableWait(boolean timedWait) throws InterruptedExcepti synchronized (lock) { if (interruptPending) { interruptPending = false; + interruptEvent.Reset(); throw new InterruptedException(); } + interruptableWait = true; this.timedWait = timedWait; } @@ -338,6 +346,7 @@ private void leaveInterruptableWait() throws InterruptedException { synchronized (lock) { if (nativeInterruptPending) { nativeInterruptPending = false; + // HACK if there is a pending Interrupt (on the .NET thread), we need to consume that // (if there was no contention on "lock (this)" above the interrupted state isn't checked) try { @@ -351,8 +360,10 @@ private void leaveInterruptableWait() throws InterruptedException { catch (cli.System.Threading.ThreadInterruptedException _) { } } + if (interruptPending) { interruptPending = false; + interruptEvent.Reset(); throw new InterruptedException(); } } @@ -363,6 +374,7 @@ private void leaveInterruptableWait() throws InterruptedException { nativeInterruptPending = false; } } + if (dotnetInterrupt != null) { ikvm.runtime.Util.throwException(dotnetInterrupt); } @@ -1219,10 +1231,12 @@ public void interrupt() { */ public static boolean interrupted() { Thread current = currentThread(); - if (!current.interruptPending) { + if (current.interruptPending == false) { return false; } + current.interruptPending = false; + current.interruptEvent.Reset(); return true; } @@ -2504,8 +2518,11 @@ private void interrupt0() { if (nativeThread == null) { return; } - if (!interruptPending) { + + if (interruptPending == false) { interruptPending = true; + interruptEvent.Set(); + if (interruptableWait) { nativeInterruptPending = true; nativeThread.Interrupt(); diff --git a/src/IKVM.Java/local/java/lang/UNIXProcess.java b/src/IKVM.Java/local/java/lang/UNIXProcess.java deleted file mode 100644 index 735cbdae91..0000000000 --- a/src/IKVM.Java/local/java/lang/UNIXProcess.java +++ /dev/null @@ -1,829 +0,0 @@ -/* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.ByteArrayInputStream; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.Executor; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.security.AccessController; -import static java.security.AccessController.doPrivileged; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; - -/** - * java.lang.Process subclass in the UNIX environment. - * - * @author Mario Wolczko and Ross Knippel. - * @author Konstantin Kladko (ported to Linux and Bsd) - * @author Martin Buchholz - * @author Volker Simonis (ported to AIX) - */ -final class UNIXProcess extends Process { - private static final sun.misc.JavaIOFileDescriptorAccess fdAccess - = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess(); - - private final int pid; - private int exitcode; - private boolean hasExited; - - private /* final */ OutputStream stdin; - private /* final */ InputStream stdout; - private /* final */ InputStream stderr; - - // only used on Solaris - private /* final */ DeferredCloseInputStream stdout_inner_stream; - - private static enum LaunchMechanism { - // order IS important! - FORK, - POSIX_SPAWN, - VFORK - } - - private static enum Platform { - - LINUX(LaunchMechanism.VFORK, LaunchMechanism.FORK), - - BSD(LaunchMechanism.FORK), - - SOLARIS(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK), - - AIX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK); - - final LaunchMechanism defaultLaunchMechanism; - final Set validLaunchMechanisms; - - Platform(LaunchMechanism ... launchMechanisms) { - this.defaultLaunchMechanism = launchMechanisms[0]; - this.validLaunchMechanisms = - EnumSet.copyOf(Arrays.asList(launchMechanisms)); - } - - private String helperPath(String javahome, String osArch) { - switch (this) { - case SOLARIS: - if (osArch.equals("x86")) { osArch = "i386"; } - else if (osArch.equals("x86_64")) { osArch = "amd64"; } - // fall through... - case LINUX: - case AIX: - return javahome + "/lib/" + osArch + "/jspawnhelper"; - - case BSD: - return javahome + "/lib/jspawnhelper"; - - default: - throw new AssertionError("Unsupported platform: " + this); - } - } - - String helperPath() { - return AccessController.doPrivileged( - (PrivilegedAction) () -> - helperPath(System.getProperty("java.home"), - System.getProperty("os.arch")) - ); - } - - LaunchMechanism launchMechanism() { - return AccessController.doPrivileged( - (PrivilegedAction) () -> { - String s = System.getProperty( - "jdk.lang.Process.launchMechanism"); - LaunchMechanism lm; - if (s == null) { - lm = defaultLaunchMechanism; - s = lm.name().toLowerCase(Locale.ENGLISH); - } else { - try { - lm = LaunchMechanism.valueOf( - s.toUpperCase(Locale.ENGLISH)); - } catch (IllegalArgumentException e) { - lm = null; - } - } - if (lm == null || !validLaunchMechanisms.contains(lm)) { - throw new Error( - s + " is not a supported " + - "process launch mechanism on this platform." - ); - } - return lm; - } - ); - } - - static Platform get() { - String osName = AccessController.doPrivileged( - (PrivilegedAction) () -> System.getProperty("os.name") - ); - - if (osName.equals("Linux")) { return LINUX; } - if (osName.contains("OS X")) { return BSD; } - if (osName.equals("SunOS")) { return SOLARIS; } - if (osName.equals("AIX")) { return AIX; } - - throw new Error(osName + " is not a supported OS platform."); - } - } - - private static final Platform platform = Platform.get(); - private static final LaunchMechanism launchMechanism = platform.launchMechanism(); - private static final byte[] helperpath = toCString(platform.helperPath()); - - private static byte[] toCString(String s) { - if (s == null) - return null; - byte[] bytes = s.getBytes(); - byte[] result = new byte[bytes.length + 1]; - System.arraycopy(bytes, 0, - result, 0, - bytes.length); - result[result.length-1] = (byte)0; - return result; - } - - /* this is for the reaping thread */ - private native int waitForProcessExit(int pid); - - /** - * Creates a process. Depending on the {@code mode} flag, this is done by - * one of the following mechanisms: - *
-     *   1 - fork(2) and exec(2)
-     *   2 - posix_spawn(3P)
-     *   3 - vfork(2) and exec(2)
-     *
-     *  (4 - clone(2) and exec(2) - obsolete and currently disabled in native code)
-     * 
- * @param fds an array of three file descriptors. - * Indexes 0, 1, and 2 correspond to standard input, - * standard output and standard error, respectively. On - * input, a value of -1 means to create a pipe to connect - * child and parent processes. On output, a value which - * is not -1 is the parent pipe fd corresponding to the - * pipe which has been created. An element of this array - * is -1 on input if and only if it is not -1 on - * output. - * @return the pid of the subprocess - */ - private native int forkAndExec(int mode, byte[] helperpath, - byte[] prog, - byte[] argBlock, int argc, - byte[] envBlock, int envc, - byte[] dir, - int[] fds, - boolean redirectErrorStream) - throws IOException; - - /** - * The thread pool of "process reaper" daemon threads. - */ - private static final Executor processReaperExecutor = - doPrivileged((PrivilegedAction) () -> { - - ThreadGroup tg = Thread.currentThread().getThreadGroup(); - while (tg.getParent() != null) tg = tg.getParent(); - ThreadGroup systemThreadGroup = tg; - - ThreadFactory threadFactory = grimReaper -> { - long stackSize = Boolean.getBoolean("jdk.lang.processReaperUseDefaultStackSize") ? 0 : 32768; - Thread t = new Thread(systemThreadGroup, grimReaper,"process reaper", stackSize); - t.setDaemon(true); - // A small attempt (probably futile) to avoid priority inversion - t.setPriority(Thread.MAX_PRIORITY); - return t; - }; - - return Executors.newCachedThreadPool(threadFactory); - }); - - UNIXProcess(final byte[] prog, - final byte[] argBlock, final int argc, - final byte[] envBlock, final int envc, - final byte[] dir, - final int[] fds, - final boolean redirectErrorStream) - throws IOException { - - pid = forkAndExec(launchMechanism.ordinal() + 1, - helperpath, - prog, - argBlock, argc, - envBlock, envc, - dir, - fds, - redirectErrorStream); - - try { - doPrivileged((PrivilegedExceptionAction) () -> { - initStreams(fds); - return null; - }); - } catch (PrivilegedActionException ex) { - throw (IOException) ex.getException(); - } - } - - static FileDescriptor newFileDescriptor(int fd) { - FileDescriptor fileDescriptor = new FileDescriptor(); - fdAccess.set(fileDescriptor, fd); - return fileDescriptor; - } - - void initStreams(int[] fds) throws IOException { - switch (platform) { - case LINUX: - case BSD: - stdin = (fds[0] == -1) ? - ProcessBuilder.NullOutputStream.INSTANCE : - new ProcessPipeOutputStream(fds[0]); - - stdout = (fds[1] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new ProcessPipeInputStream(fds[1]); - - stderr = (fds[2] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new ProcessPipeInputStream(fds[2]); - - processReaperExecutor.execute(() -> { - int exitcode = waitForProcessExit(pid); - - synchronized (this) { - this.exitcode = exitcode; - this.hasExited = true; - this.notifyAll(); - } - - if (stdout instanceof ProcessPipeInputStream) - ((ProcessPipeInputStream) stdout).processExited(); - - if (stderr instanceof ProcessPipeInputStream) - ((ProcessPipeInputStream) stderr).processExited(); - - if (stdin instanceof ProcessPipeOutputStream) - ((ProcessPipeOutputStream) stdin).processExited(); - }); - break; - - case SOLARIS: - stdin = (fds[0] == -1) ? - ProcessBuilder.NullOutputStream.INSTANCE : - new BufferedOutputStream( - new FileOutputStream(newFileDescriptor(fds[0]))); - - stdout = (fds[1] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new BufferedInputStream( - stdout_inner_stream = - new DeferredCloseInputStream( - newFileDescriptor(fds[1]))); - - stderr = (fds[2] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new DeferredCloseInputStream(newFileDescriptor(fds[2])); - - /* - * For each subprocess forked a corresponding reaper task - * is submitted. That task is the only thread which waits - * for the subprocess to terminate and it doesn't hold any - * locks while doing so. This design allows waitFor() and - * exitStatus() to be safely executed in parallel (and they - * need no native code). - */ - processReaperExecutor.execute(() -> { - int exitcode = waitForProcessExit(pid); - - synchronized (this) { - this.exitcode = exitcode; - this.hasExited = true; - this.notifyAll(); - } - }); - break; - - case AIX: - stdin = (fds[0] == -1) ? - ProcessBuilder.NullOutputStream.INSTANCE : - new ProcessPipeOutputStream(fds[0]); - - stdout = (fds[1] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new DeferredCloseProcessPipeInputStream(fds[1]); - - stderr = (fds[2] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new DeferredCloseProcessPipeInputStream(fds[2]); - - processReaperExecutor.execute(() -> { - int exitcode = waitForProcessExit(pid); - - synchronized (this) { - this.exitcode = exitcode; - this.hasExited = true; - this.notifyAll(); - } - - if (stdout instanceof DeferredCloseProcessPipeInputStream) - ((DeferredCloseProcessPipeInputStream) stdout).processExited(); - - if (stderr instanceof DeferredCloseProcessPipeInputStream) - ((DeferredCloseProcessPipeInputStream) stderr).processExited(); - - if (stdin instanceof ProcessPipeOutputStream) - ((ProcessPipeOutputStream) stdin).processExited(); - }); - break; - - default: throw new AssertionError("Unsupported platform: " + platform); - } - } - - public OutputStream getOutputStream() { - return stdin; - } - - public InputStream getInputStream() { - return stdout; - } - - public InputStream getErrorStream() { - return stderr; - } - - public synchronized int waitFor() throws InterruptedException { - while (!hasExited) { - wait(); - } - return exitcode; - } - - @Override - public synchronized boolean waitFor(long timeout, TimeUnit unit) - throws InterruptedException - { - if (hasExited) return true; - if (timeout <= 0) return false; - - long remainingNanos = unit.toNanos(timeout); - long deadline = System.nanoTime() + remainingNanos; - - do { - // Round up to next millisecond - wait(TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L)); - if (hasExited) { - return true; - } - remainingNanos = deadline - System.nanoTime(); - } while (remainingNanos > 0); - return hasExited; - } - - public synchronized int exitValue() { - if (!hasExited) { - throw new IllegalThreadStateException("process hasn't exited"); - } - return exitcode; - } - - private static native void destroyProcess(int pid, boolean force); - - private void destroy(boolean force) { - switch (platform) { - case LINUX: - case BSD: - case AIX: - // There is a risk that pid will be recycled, causing us to - // kill the wrong process! So we only terminate processes - // that appear to still be running. Even with this check, - // there is an unavoidable race condition here, but the window - // is very small, and OSes try hard to not recycle pids too - // soon, so this is quite safe. - synchronized (this) { - if (!hasExited) - destroyProcess(pid, force); - } - try { stdin.close(); } catch (IOException ignored) {} - try { stdout.close(); } catch (IOException ignored) {} - try { stderr.close(); } catch (IOException ignored) {} - break; - - case SOLARIS: - // There is a risk that pid will be recycled, causing us to - // kill the wrong process! So we only terminate processes - // that appear to still be running. Even with this check, - // there is an unavoidable race condition here, but the window - // is very small, and OSes try hard to not recycle pids too - // soon, so this is quite safe. - synchronized (this) { - if (!hasExited) - destroyProcess(pid, force); - try { - stdin.close(); - if (stdout_inner_stream != null) - stdout_inner_stream.closeDeferred(stdout); - if (stderr instanceof DeferredCloseInputStream) - ((DeferredCloseInputStream) stderr) - .closeDeferred(stderr); - } catch (IOException e) { - // ignore - } - } - break; - - default: throw new AssertionError("Unsupported platform: " + platform); - } - } - - public void destroy() { - destroy(false); - } - - @Override - public Process destroyForcibly() { - destroy(true); - return this; - } - - @Override - public synchronized boolean isAlive() { - return !hasExited; - } - - private static native void init(); - - static { - init(); - } - - /** - * A buffered input stream for a subprocess pipe file descriptor - * that allows the underlying file descriptor to be reclaimed when - * the process exits, via the processExited hook. - * - * This is tricky because we do not want the user-level InputStream to be - * closed until the user invokes close(), and we need to continue to be - * able to read any buffered data lingering in the OS pipe buffer. - */ - private static class ProcessPipeInputStream extends BufferedInputStream { - private final Object closeLock = new Object(); - - ProcessPipeInputStream(int fd) { - super(new FileInputStream(newFileDescriptor(fd))); - } - private static byte[] drainInputStream(InputStream in) - throws IOException { - int n = 0; - int j; - byte[] a = null; - while ((j = in.available()) > 0) { - a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j); - n += in.read(a, n, j); - } - return (a == null || n == a.length) ? a : Arrays.copyOf(a, n); - } - - /** Called by the process reaper thread when the process exits. */ - synchronized void processExited() { - synchronized (closeLock) { - try { - InputStream in = this.in; - // this stream is closed if and only if: in == null - if (in != null) { - byte[] stragglers = drainInputStream(in); - in.close(); - this.in = (stragglers == null) ? - ProcessBuilder.NullInputStream.INSTANCE : - new ByteArrayInputStream(stragglers); - } - } catch (IOException ignored) {} - } - } - - @Override - public void close() throws IOException { - // BufferedInputStream#close() is not synchronized unlike most other - // methods. Synchronizing helps avoid race with processExited(). - synchronized (closeLock) { - super.close(); - } - } - } - - /** - * A buffered output stream for a subprocess pipe file descriptor - * that allows the underlying file descriptor to be reclaimed when - * the process exits, via the processExited hook. - */ - private static class ProcessPipeOutputStream extends BufferedOutputStream { - ProcessPipeOutputStream(int fd) { - super(new FileOutputStream(newFileDescriptor(fd))); - } - - /** Called by the process reaper thread when the process exits. */ - synchronized void processExited() { - OutputStream out = this.out; - if (out != null) { - try { - out.close(); - } catch (IOException ignored) { - // We know of no reason to get an IOException, but if - // we do, there's nothing else to do but carry on. - } - this.out = ProcessBuilder.NullOutputStream.INSTANCE; - } - } - } - - // A FileInputStream that supports the deferment of the actual close - // operation until the last pending I/O operation on the stream has - // finished. This is required on Solaris because we must close the stdin - // and stdout streams in the destroy method in order to reclaim the - // underlying file descriptors. Doing so, however, causes any thread - // currently blocked in a read on one of those streams to receive an - // IOException("Bad file number"), which is incompatible with historical - // behavior. By deferring the close we allow any pending reads to see -1 - // (EOF) as they did before. - // - private static class DeferredCloseInputStream extends FileInputStream - { - DeferredCloseInputStream(FileDescriptor fd) { - super(fd); - } - - private Object lock = new Object(); // For the following fields - private boolean closePending = false; - private int useCount = 0; - private InputStream streamToClose; - - private void raise() { - synchronized (lock) { - useCount++; - } - } - - private void lower() throws IOException { - synchronized (lock) { - useCount--; - if (useCount == 0 && closePending) { - streamToClose.close(); - } - } - } - - // stc is the actual stream to be closed; it might be this object, or - // it might be an upstream object for which this object is downstream. - // - private void closeDeferred(InputStream stc) throws IOException { - synchronized (lock) { - if (useCount == 0) { - stc.close(); - } else { - closePending = true; - streamToClose = stc; - } - } - } - - public void close() throws IOException { - synchronized (lock) { - useCount = 0; - closePending = false; - } - super.close(); - } - - public int read() throws IOException { - raise(); - try { - return super.read(); - } finally { - lower(); - } - } - - public int read(byte[] b) throws IOException { - raise(); - try { - return super.read(b); - } finally { - lower(); - } - } - - public int read(byte[] b, int off, int len) throws IOException { - raise(); - try { - return super.read(b, off, len); - } finally { - lower(); - } - } - - public long skip(long n) throws IOException { - raise(); - try { - return super.skip(n); - } finally { - lower(); - } - } - - public int available() throws IOException { - raise(); - try { - return super.available(); - } finally { - lower(); - } - } - } - - /** - * A buffered input stream for a subprocess pipe file descriptor - * that allows the underlying file descriptor to be reclaimed when - * the process exits, via the processExited hook. - * - * This is tricky because we do not want the user-level InputStream to be - * closed until the user invokes close(), and we need to continue to be - * able to read any buffered data lingering in the OS pipe buffer. - * - * On AIX this is especially tricky, because the 'close()' system call - * will block if another thread is at the same time blocked in a file - * operation (e.g. 'read()') on the same file descriptor. We therefore - * combine 'ProcessPipeInputStream' approach used on Linux and Bsd - * with the DeferredCloseInputStream approach used on Solaris. This means - * that every potentially blocking operation on the file descriptor - * increments a counter before it is executed and decrements it once it - * finishes. The 'close()' operation will only be executed if there are - * no pending operations. Otherwise it is deferred after the last pending - * operation has finished. - * - */ - private static class DeferredCloseProcessPipeInputStream - extends BufferedInputStream { - - private final Object closeLock = new Object(); - private int useCount = 0; - private boolean closePending = false; - - DeferredCloseProcessPipeInputStream(int fd) { - super(new FileInputStream(newFileDescriptor(fd))); - } - - private InputStream drainInputStream(InputStream in) - throws IOException { - int n = 0; - int j; - byte[] a = null; - synchronized (closeLock) { - if (buf == null) // asynchronous close()? - return null; // discard - j = in.available(); - } - while (j > 0) { - a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j); - synchronized (closeLock) { - if (buf == null) // asynchronous close()? - return null; // discard - n += in.read(a, n, j); - j = in.available(); - } - } - return (a == null) ? - ProcessBuilder.NullInputStream.INSTANCE : - new ByteArrayInputStream(n == a.length ? a : Arrays.copyOf(a, n)); - } - - /** Called by the process reaper thread when the process exits. */ - synchronized void processExited() { - try { - InputStream in = this.in; - if (in != null) { - InputStream stragglers = drainInputStream(in); - in.close(); - this.in = stragglers; - } - } catch (IOException ignored) { } - } - - private void raise() { - synchronized (closeLock) { - useCount++; - } - } - - private void lower() throws IOException { - synchronized (closeLock) { - useCount--; - if (useCount == 0 && closePending) { - closePending = false; - super.close(); - } - } - } - - @Override - public int read() throws IOException { - raise(); - try { - return super.read(); - } finally { - lower(); - } - } - - @Override - public int read(byte[] b) throws IOException { - raise(); - try { - return super.read(b); - } finally { - lower(); - } - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - raise(); - try { - return super.read(b, off, len); - } finally { - lower(); - } - } - - @Override - public long skip(long n) throws IOException { - raise(); - try { - return super.skip(n); - } finally { - lower(); - } - } - - @Override - public int available() throws IOException { - raise(); - try { - return super.available(); - } finally { - lower(); - } - } - - @Override - public void close() throws IOException { - // BufferedInputStream#close() is not synchronized unlike most other - // methods. Synchronizing helps avoid racing with drainInputStream(). - synchronized (closeLock) { - if (useCount == 0) { - super.close(); - } - else { - closePending = true; - } - } - } - } -} diff --git a/src/IKVM.Java/local/java/lang/UNIXProcessEnvironment.java b/src/IKVM.Java/local/java/lang/UNIXProcessEnvironment.java deleted file mode 100644 index fbe4f37ef2..0000000000 --- a/src/IKVM.Java/local/java/lang/UNIXProcessEnvironment.java +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* We use APIs that access the standard Unix environ array, which - * is defined by UNIX98 to look like: - * - * char **environ; - * - * These are unsorted, case-sensitive, null-terminated arrays of bytes - * of the form FOO=BAR\000 which are usually encoded in the user's - * default encoding (file.encoding is an excellent choice for - * encoding/decoding these). However, even though the user cannot - * directly access the underlying byte representation, we take pains - * to pass on the child the exact byte representation we inherit from - * the parent process for any environment name or value not created by - * Javaland. So we keep track of all the byte representations. - * - * Internally, we define the types Variable and Value that exhibit - * String/byteArray duality. The internal representation of the - * environment then looks like a Map. But we don't - * expose this to the user -- we only provide a Map - * view, although we could also provide a Map view. - * - * The non-private methods in this class are not for general use even - * within this package. Instead, they are the system-dependent parts - * of the system-independent method of the same name. Don't even - * think of using this class unless your method's name appears below. - * - * @author Martin Buchholz - * @since 1.5 - */ - - // IKVM Largely a copy of the UNIX version of ProcessEnvironment. Used currently to provide the toEnvironmentBlock method needed by JNI for UNIXProcess. - -package java.lang; - -import java.io.*; -import java.util.*; - - -final class UNIXProcessEnvironment -{ - private static final HashMap theEnvironment; - private static final Map theUnmodifiableEnvironment; - static final int MIN_NAME_LENGTH = 0; - - static { - // We cache the C environment. This means that subsequent calls - // to putenv/setenv from C will not be visible from Java code. - byte[][] environ = environ(); - theEnvironment = new HashMap<>(environ.length/2 + 3); - // Read environment variables back to front, - // so that earlier variables override later ones. - for (int i = environ.length-1; i > 0; i-=2) - theEnvironment.put(Variable.valueOf(environ[i-1]), - Value.valueOf(environ[i])); - - theUnmodifiableEnvironment - = Collections.unmodifiableMap - (new StringEnvironment(theEnvironment)); - } - - /* Only for use by System.getenv(String) */ - static String getenv(String name) { - return theUnmodifiableEnvironment.get(name); - } - - /* Only for use by System.getenv() */ - static Map getenv() { - return theUnmodifiableEnvironment; - } - - /* Only for use by ProcessBuilder.environment() */ - @SuppressWarnings("unchecked") - static Map environment() { - return new StringEnvironment - ((Map)(theEnvironment.clone())); - } - - /* Only for use by Runtime.exec(...String[]envp...) */ - static Map emptyEnvironment(int capacity) { - return new StringEnvironment(new HashMap(capacity)); - } - - private static native byte[][] environ(); - - // This class is not instantiable. - private UNIXProcessEnvironment() {} - - // Check that name is suitable for insertion into Environment map - private static void validateVariable(String name) { - if (name.indexOf('=') != -1 || - name.indexOf('\u0000') != -1) - throw new IllegalArgumentException - ("Invalid environment variable name: \"" + name + "\""); - } - - // Check that value is suitable for insertion into Environment map - private static void validateValue(String value) { - if (value.indexOf('\u0000') != -1) - throw new IllegalArgumentException - ("Invalid environment variable value: \"" + value + "\""); - } - - // A class hiding the byteArray-String duality of - // text data on Unixoid operating systems. - private static abstract class ExternalData { - protected final String str; - protected final byte[] bytes; - - protected ExternalData(String str, byte[] bytes) { - this.str = str; - this.bytes = bytes; - } - - public byte[] getBytes() { - return bytes; - } - - public String toString() { - return str; - } - - public boolean equals(Object o) { - return o instanceof ExternalData - && arrayEquals(getBytes(), ((ExternalData) o).getBytes()); - } - - public int hashCode() { - return arrayHash(getBytes()); - } - } - - private static class Variable - extends ExternalData implements Comparable - { - protected Variable(String str, byte[] bytes) { - super(str, bytes); - } - - public static Variable valueOfQueryOnly(Object str) { - return valueOfQueryOnly((String) str); - } - - public static Variable valueOfQueryOnly(String str) { - return new Variable(str, str.getBytes()); - } - - public static Variable valueOf(String str) { - validateVariable(str); - return valueOfQueryOnly(str); - } - - public static Variable valueOf(byte[] bytes) { - return new Variable(new String(bytes), bytes); - } - - public int compareTo(Variable variable) { - return arrayCompare(getBytes(), variable.getBytes()); - } - - public boolean equals(Object o) { - return o instanceof Variable && super.equals(o); - } - } - - private static class Value - extends ExternalData implements Comparable - { - protected Value(String str, byte[] bytes) { - super(str, bytes); - } - - public static Value valueOfQueryOnly(Object str) { - return valueOfQueryOnly((String) str); - } - - public static Value valueOfQueryOnly(String str) { - return new Value(str, str.getBytes()); - } - - public static Value valueOf(String str) { - validateValue(str); - return valueOfQueryOnly(str); - } - - public static Value valueOf(byte[] bytes) { - return new Value(new String(bytes), bytes); - } - - public int compareTo(Value value) { - return arrayCompare(getBytes(), value.getBytes()); - } - - public boolean equals(Object o) { - return o instanceof Value && super.equals(o); - } - } - - // This implements the String map view the user sees. - private static class StringEnvironment - extends AbstractMap - { - private Map m; - private static String toString(Value v) { - return v == null ? null : v.toString(); - } - public StringEnvironment(Map m) {this.m = m;} - public int size() {return m.size();} - public boolean isEmpty() {return m.isEmpty();} - public void clear() { m.clear();} - public boolean containsKey(Object key) { - return m.containsKey(Variable.valueOfQueryOnly(key)); - } - public boolean containsValue(Object value) { - return m.containsValue(Value.valueOfQueryOnly(value)); - } - public String get(Object key) { - return toString(m.get(Variable.valueOfQueryOnly(key))); - } - public String put(String key, String value) { - return toString(m.put(Variable.valueOf(key), - Value.valueOf(value))); - } - public String remove(Object key) { - return toString(m.remove(Variable.valueOfQueryOnly(key))); - } - public Set keySet() { - return new StringKeySet(m.keySet()); - } - public Set> entrySet() { - return new StringEntrySet(m.entrySet()); - } - public Collection values() { - return new StringValues(m.values()); - } - - // It is technically feasible to provide a byte-oriented view - // as follows: - // public Map asByteArrayMap() { - // return new ByteArrayEnvironment(m); - // } - - - // Convert to Unix style environ as a monolithic byte array - // inspired by the Windows Environment Block, except we work - // exclusively with bytes instead of chars, and we need only - // one trailing NUL on Unix. - // This keeps the JNI as simple and efficient as possible. - public byte[] toEnvironmentBlock(int[]envc) { - int count = m.size() * 2; // For added '=' and NUL - for (Map.Entry entry : m.entrySet()) { - count += entry.getKey().getBytes().length; - count += entry.getValue().getBytes().length; - } - - byte[] block = new byte[count]; - - int i = 0; - for (Map.Entry entry : m.entrySet()) { - byte[] key = entry.getKey ().getBytes(); - byte[] value = entry.getValue().getBytes(); - System.arraycopy(key, 0, block, i, key.length); - i+=key.length; - block[i++] = (byte) '='; - System.arraycopy(value, 0, block, i, value.length); - i+=value.length + 1; - // No need to write NUL byte explicitly - //block[i++] = (byte) '\u0000'; - } - envc[0] = m.size(); - return block; - } - } - - static byte[] toEnvironmentBlock(Map map, int[]envc) { - if (map == null) { - return null; - } - - StringEnvironment env = new StringEnvironment(new HashMap(map.size())); - for (Map.Entry entry : map.entrySet()) { - env.put(entry.getKey(), entry.getValue()); - } - - return env.toEnvironmentBlock(envc); - } - - - private static class StringEntry - implements Map.Entry - { - private final Map.Entry e; - public StringEntry(Map.Entry e) {this.e = e;} - public String getKey() {return e.getKey().toString();} - public String getValue() {return e.getValue().toString();} - public String setValue(String newValue) { - return e.setValue(Value.valueOf(newValue)).toString(); - } - public String toString() {return getKey() + "=" + getValue();} - public boolean equals(Object o) { - return o instanceof StringEntry - && e.equals(((StringEntry)o).e); - } - public int hashCode() {return e.hashCode();} - } - - private static class StringEntrySet - extends AbstractSet> - { - private final Set> s; - public StringEntrySet(Set> s) {this.s = s;} - public int size() {return s.size();} - public boolean isEmpty() {return s.isEmpty();} - public void clear() { s.clear();} - public Iterator> iterator() { - return new Iterator>() { - Iterator> i = s.iterator(); - public boolean hasNext() {return i.hasNext();} - public Map.Entry next() { - return new StringEntry(i.next()); - } - public void remove() {i.remove();} - }; - } - private static Map.Entry vvEntry(final Object o) { - if (o instanceof StringEntry) - return ((StringEntry)o).e; - return new Map.Entry() { - public Variable getKey() { - return Variable.valueOfQueryOnly(((Map.Entry)o).getKey()); - } - public Value getValue() { - return Value.valueOfQueryOnly(((Map.Entry)o).getValue()); - } - public Value setValue(Value value) { - throw new UnsupportedOperationException(); - } - }; - } - public boolean contains(Object o) { return s.contains(vvEntry(o)); } - public boolean remove(Object o) { return s.remove(vvEntry(o)); } - public boolean equals(Object o) { - return o instanceof StringEntrySet - && s.equals(((StringEntrySet) o).s); - } - public int hashCode() {return s.hashCode();} - } - - private static class StringValues - extends AbstractCollection - { - private final Collection c; - public StringValues(Collection c) {this.c = c;} - public int size() {return c.size();} - public boolean isEmpty() {return c.isEmpty();} - public void clear() { c.clear();} - public Iterator iterator() { - return new Iterator() { - Iterator i = c.iterator(); - public boolean hasNext() {return i.hasNext();} - public String next() {return i.next().toString();} - public void remove() {i.remove();} - }; - } - public boolean contains(Object o) { - return c.contains(Value.valueOfQueryOnly(o)); - } - public boolean remove(Object o) { - return c.remove(Value.valueOfQueryOnly(o)); - } - public boolean equals(Object o) { - return o instanceof StringValues - && c.equals(((StringValues)o).c); - } - public int hashCode() {return c.hashCode();} - } - - private static class StringKeySet extends AbstractSet { - private final Set s; - public StringKeySet(Set s) {this.s = s;} - public int size() {return s.size();} - public boolean isEmpty() {return s.isEmpty();} - public void clear() { s.clear();} - public Iterator iterator() { - return new Iterator() { - Iterator i = s.iterator(); - public boolean hasNext() {return i.hasNext();} - public String next() {return i.next().toString();} - public void remove() { i.remove();} - }; - } - public boolean contains(Object o) { - return s.contains(Variable.valueOfQueryOnly(o)); - } - public boolean remove(Object o) { - return s.remove(Variable.valueOfQueryOnly(o)); - } - } - - // Replace with general purpose method someday - private static int arrayCompare(byte[]x, byte[] y) { - int min = x.length < y.length ? x.length : y.length; - for (int i = 0; i < min; i++) - if (x[i] != y[i]) - return x[i] - y[i]; - return x.length - y.length; - } - - // Replace with general purpose method someday - private static boolean arrayEquals(byte[] x, byte[] y) { - if (x.length != y.length) - return false; - for (int i = 0; i < x.length; i++) - if (x[i] != y[i]) - return false; - return true; - } - - // Replace with general purpose method someday - private static int arrayHash(byte[] x) { - int hash = 0; - for (int i = 0; i < x.length; i++) - hash = 31 * hash + x[i]; - return hash; - } - -} diff --git a/src/IKVM.Java/local/java/lang/Win32Process.java b/src/IKVM.Java/local/java/lang/Win32Process.java deleted file mode 100644 index 9f804716be..0000000000 --- a/src/IKVM.Java/local/java/lang/Win32Process.java +++ /dev/null @@ -1,46 +0,0 @@ -package java.lang; - -import java.io.*; -import java.util.*; - -final class Win32Process extends Process { - - cli.System.Diagnostics.Process process; - OutputStream outputStream; - InputStream inputStream; - InputStream errorStream; - - static native Process start(String cmdarray[], java.util.Map environment, String dir, ProcessBuilder.Redirect[] redirects, boolean redirectErrorStream) throws IOException; - - private Win32Process(cli.System.Diagnostics.Process process, OutputStream outputStream, InputStream inputStream, InputStream errorStream) { - this.process = process; - this.outputStream = outputStream; - this.inputStream = inputStream; - this.errorStream = errorStream; - } - - @Override - public OutputStream getOutputStream() { - return outputStream; - } - - @Override - public InputStream getInputStream() { - return inputStream; - } - - @Override - public InputStream getErrorStream() { - return errorStream; - } - - @Override - public native int waitFor() throws InterruptedException; - - @Override - public native int exitValue(); - - @Override - public native void destroy(); - -} diff --git a/src/IKVM.Java/local/sun/management/ManagementFactoryHelper.java b/src/IKVM.Java/local/sun/management/ManagementFactoryHelper.java index 68f9724611..211d32a11e 100644 --- a/src/IKVM.Java/local/sun/management/ManagementFactoryHelper.java +++ b/src/IKVM.Java/local/sun/management/ManagementFactoryHelper.java @@ -293,7 +293,7 @@ public static HashMap getPlatformDynamicMBeans() { } static void registerInternalMBeans(MBeanServer mbs) { - + } private static void unregisterMBean(MBeanServer mbs, String mbeanName) { @@ -319,10 +319,17 @@ public Void run() throws MBeanRegistrationException, } static void unregisterInternalMBeans(MBeanServer mbs) { - + } static { + AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + System.loadLibrary("management"); + return null; + } + }); jvm = new VMManagementImpl(); } diff --git a/src/IKVM.Java/local/sun/misc/FileURLMapper.java b/src/IKVM.Java/local/sun/misc/FileURLMapper.java deleted file mode 100644 index 94caff650e..0000000000 --- a/src/IKVM.Java/local/sun/misc/FileURLMapper.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * This is a merged version of the Windows & Solaris platform specific versions. - * Since the IKVM class library binary can be used both on Windows and on *nix, - * I've merged the platform specific classes into a generic class that at - * runtime determines if it runs on Windows or not. - */ - -package sun.misc; - -import java.net.URL; -import java.io.File; - -import sun.net.www.ParseUtil; - -public class FileURLMapper { - - URL url; - String file; - - public FileURLMapper(URL url) { - this.url = url; - } - - /** - * @returns the platform specific path corresponding to the URL, and in particular returns a UNC when the authority contains a hostname - */ - public String getPath () { - if (file != null) { - return file; - } - - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - String host = url.getHost(); - if (host != null && !host.equals("") && - !"localhost".equalsIgnoreCase(host)) { - String rest = url.getFile(); - String s = host + ParseUtil.decode (url.getFile()); - file = "\\\\"+ s.replace('/', '\\'); - return file; - } - String path = url.getFile().replace('/', '\\'); - file = ParseUtil.decode(path); - return file; - } else { - String host = url.getHost(); - if (host == null || "".equals(host) || "localhost".equalsIgnoreCase (host)) { - file = url.getFile(); - file = ParseUtil.decode (file); - } - return file; - } - } - - public boolean exists() { - String s = getPath(); - if (s == null) { - return false; - } else { - File f = new File(s); - return f.exists(); - } - } - -} diff --git a/src/IKVM.Java/local/sun/misc/OSEnvironment.java b/src/IKVM.Java/local/sun/misc/OSEnvironment.java index d51ac0f12c..2fea318f52 100644 --- a/src/IKVM.Java/local/sun/misc/OSEnvironment.java +++ b/src/IKVM.Java/local/sun/misc/OSEnvironment.java @@ -1,32 +1,12 @@ -/* - Copyright (C) 2007 Jeroen Frijters +// Licensed to the IKVM project under one or more agreements. +// The IKVM project licenses this file to you under the Zlib license. - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: +package sun.misc; - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. +public class OSEnvironment { - Jeroen Frijters - jeroen@frijters.net - -*/ + public static void initialize() { -package sun.misc; - -public class OSEnvironment -{ - public static void initialize() - { } + } diff --git a/src/IKVM.Java/local/sun/net/dns/ResolverConfigurationImpl.java b/src/IKVM.Java/local/sun/net/dns/ResolverConfigurationImpl.java deleted file mode 100644 index d0e3acbcf7..0000000000 --- a/src/IKVM.Java/local/sun/net/dns/ResolverConfigurationImpl.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.net.dns; - -import java.util.List; -import java.util.LinkedList; -import java.util.StringTokenizer; -import java.io.IOException; -import cli.System.Net.NetworkInformation.IPAddressCollection; -import cli.System.Net.NetworkInformation.IPInterfaceProperties; -import cli.System.Net.NetworkInformation.NetworkInterface; - -/* - * An implementation of sun.net.ResolverConfiguration for Windows. - */ - -public class ResolverConfigurationImpl - extends ResolverConfiguration -{ - // Lock helds whilst loading configuration or checking - private static Object lock = new Object(); - - // Resolver options - private final Options opts; - - // Addreses have changed - private static boolean changed = false; - - // Time of last refresh. - private static long lastRefresh = -1; - - // Cache timeout (120 seconds) - should be converted into property - // or configured as preference in the future. - private static final int TIMEOUT = 120000; - - // DNS suffix list and name servers populated by native method - private static String os_searchlist; - private static String os_nameservers; - - // Cached lists - private static LinkedList searchlist; - private static LinkedList nameservers; - - // Parse string that consists of token delimited by space or commas - // and return LinkedHashMap - private LinkedList stringToList(String str) { - LinkedList ll = new LinkedList<>(); - - // comma and space are valid delimites - StringTokenizer st = new StringTokenizer(str, ", "); - while (st.hasMoreTokens()) { - String s = st.nextToken(); - if (!ll.contains(s)) { - ll.add(s); - } - } - return ll; - } - - // Load DNS configuration from OS - - private void loadConfig() { - assert Thread.holdsLock(lock); - - // if address have changed then DNS probably changed aswell; - // otherwise check if cached settings have expired. - // - if (changed) { - changed = false; - } else { - if (lastRefresh >= 0) { - long currTime = System.currentTimeMillis(); - if ((currTime - lastRefresh) < TIMEOUT) { - return; - } - } - } - - // load DNS configuration, update timestamp, create - // new HashMaps from the loaded configuration - // - loadDNSconfig0(); - - lastRefresh = System.currentTimeMillis(); - searchlist = stringToList(os_searchlist); - nameservers = stringToList(os_nameservers); - os_searchlist = null; // can be GC'ed - os_nameservers = null; - } - - ResolverConfigurationImpl() { - opts = new OptionsImpl(); - } - - @SuppressWarnings("unchecked") // clone() - public List searchlist() { - synchronized (lock) { - loadConfig(); - - // List is mutable so return a shallow copy - return (List)searchlist.clone(); - } - } - - @SuppressWarnings("unchecked") // clone() - public List nameservers() { - synchronized (lock) { - loadConfig(); - - // List is mutable so return a shallow copy - return (List)nameservers.clone(); - } - } - - public Options options() { - return opts; - } - - // --- Address Change Listener - - static class AddressChangeListener extends Thread { - public void run() { - for (;;) { - // wait for configuration to change - if (notifyAddrChange0() != 0) - return; - synchronized (lock) { - changed = true; - } - } - } - } - - - // --- Native methods -- - - static void init0() { - } - - static void loadDNSconfig0() { - String searchlist = ""; - String nameservers = ""; - for (NetworkInterface iface : NetworkInterface.GetAllNetworkInterfaces()) { - IPInterfaceProperties props = iface.GetIPProperties(); - IPAddressCollection addresses = props.get_DnsAddresses(); - for (int i = 0; i < addresses.get_Count(); i++) { - cli.System.Net.IPAddress addr = addresses.get_Item(i); - // no IPv6 support - if (addr.get_AddressFamily().Value == cli.System.Net.Sockets.AddressFamily.InterNetwork) { - nameservers = strAppend(nameservers, addr.toString()); - } - } - try { - if (false) throw new cli.System.PlatformNotSupportedException(); - searchlist = strAppend(searchlist, props.get_DnsSuffix()); - } - catch (cli.System.PlatformNotSupportedException _) { - } - } - os_searchlist = searchlist; - os_nameservers = nameservers; - } - - private static String strAppend(String s, String app) { - if (s.equals("")) { - return app; - } - if (app.equals("")) { - return s; - } - return s + " " + app; - } - - static int notifyAddrChange0() { - // TODO we could use System.Net.NetworkInformation.NetworkChange to detect changes - return -1; - } - - static { - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Void run() { - System.loadLibrary("net"); - return null; - } - }); - init0(); - - // start the address listener thread - AddressChangeListener thr = new AddressChangeListener(); - thr.setDaemon(true); - thr.start(); - } -} - -/** - * Implementation of {@link ResolverConfiguration.Options} - */ -class OptionsImpl extends ResolverConfiguration.Options { -} diff --git a/src/IKVM.Java/local/sun/net/sdp/SdpSupport.java b/src/IKVM.Java/local/sun/net/sdp/SdpSupport.java deleted file mode 100644 index 9a7437e0c5..0000000000 --- a/src/IKVM.Java/local/sun/net/sdp/SdpSupport.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.net.sdp; - -import java.io.IOException; -import java.io.FileDescriptor; - - -/** - * This class defines methods for creating SDP sockets or "converting" existing - * file descriptors, referencing (unbound) TCP sockets, to SDP. - */ - -public final class SdpSupport { - - private SdpSupport() { } - - /** - * Creates a SDP socket, returning file descriptor referencing the socket. - */ - public static FileDescriptor createSocket() throws IOException { - throw new UnsupportedOperationException("SDP not supported on this platform"); - } - - /** - * Converts an existing file descriptor, that references an unbound TCP socket, - * to SDP. - */ - public static void convertSocket(FileDescriptor fd) throws IOException { - throw new UnsupportedOperationException("SDP not supported on this platform"); - } -} diff --git a/src/IKVM.Java/local/sun/net/www/protocol/file/FileURLConnection.java b/src/IKVM.Java/local/sun/net/www/protocol/file/FileURLConnection.java deleted file mode 100644 index 43c94b317e..0000000000 --- a/src/IKVM.Java/local/sun/net/www/protocol/file/FileURLConnection.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * Open an file input stream given a URL. - * @author James Gosling - * @author Steven B. Byrne - */ - -package sun.net.www.protocol.file; - -import java.net.URL; -import java.net.FileNameMap; -import java.io.*; -import java.text.Collator; -import java.security.Permission; -import sun.net.*; -import sun.net.www.*; -import java.util.*; -import java.text.SimpleDateFormat; - -import sun.security.action.GetPropertyAction; -import sun.security.action.GetIntegerAction; -import sun.security.action.GetBooleanAction; - -public class FileURLConnection extends URLConnection { - - static String CONTENT_LENGTH = "content-length"; - static String CONTENT_TYPE = "content-type"; - static String TEXT_PLAIN = "text/plain"; - static String LAST_MODIFIED = "last-modified"; - - String contentType; - InputStream is; - - File file; - String filename; - boolean isDirectory = false; - boolean exists = false; - List files; - - long length = -1; - long lastModified = 0; - - protected FileURLConnection(URL u, File file) { - super(u); - this.file = file; - } - - /* - * Note: the semantics of FileURLConnection object is that the - * results of the various URLConnection calls, such as - * getContentType, getInputStream or getContentLength reflect - * whatever was true when connect was called. - */ - public void connect() throws IOException { - if (!connected) { - try { - filename = file.toString(); - isDirectory = file.isDirectory(); - if (isDirectory) { - String[] fileList = file.list(); - if (fileList == null) - throw new FileNotFoundException(filename + " exists, but is not accessible"); - files = Arrays.asList(fileList); - } else { - - is = new BufferedInputStream(new FileInputStream(filename)); - - // Check if URL should be metered - boolean meteredInput = ProgressMonitor.getDefault().shouldMeterInput(url, "GET"); - if (meteredInput) { - ProgressSource pi = new ProgressSource(url, "GET", file.length()); - is = new MeteredStream(is, pi, file.length()); - } - } - } catch (IOException e) { - throw e; - } - connected = true; - } - } - - private boolean initializedHeaders = false; - - private void initializeHeaders() { - try { - connect(); - exists = file.exists(); - } catch (IOException e) { - } - if (!initializedHeaders || !exists) { - length = file.length(); - lastModified = file.lastModified(); - - if (!isDirectory) { - FileNameMap map = java.net.URLConnection.getFileNameMap(); - contentType = map.getContentTypeFor(filename); - if (contentType != null) { - properties.add(CONTENT_TYPE, contentType); - } - properties.add(CONTENT_LENGTH, String.valueOf(length)); - - /* - * Format the last-modified field into the preferred - * Internet standard - ie: fixed-length subset of that - * defined by RFC 1123 - */ - if (lastModified != 0) { - Date date = new Date(lastModified); - SimpleDateFormat fo = - new SimpleDateFormat ("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US); - fo.setTimeZone(TimeZone.getTimeZone("GMT")); - properties.add(LAST_MODIFIED, fo.format(date)); - } - } else { - properties.add(CONTENT_TYPE, TEXT_PLAIN); - } - initializedHeaders = true; - } - } - - public String getHeaderField(String name) { - initializeHeaders(); - return super.getHeaderField(name); - } - - public String getHeaderField(int n) { - initializeHeaders(); - return super.getHeaderField(n); - } - - public int getContentLength() { - initializeHeaders(); - if (length > Integer.MAX_VALUE) - return -1; - return (int) length; - } - - public long getContentLengthLong() { - initializeHeaders(); - return length; - } - - public String getHeaderFieldKey(int n) { - initializeHeaders(); - return super.getHeaderFieldKey(n); - } - - public MessageHeader getProperties() { - initializeHeaders(); - return super.getProperties(); - } - - public long getLastModified() { - initializeHeaders(); - return lastModified; - } - - public synchronized InputStream getInputStream() - throws IOException { - - int iconHeight; - int iconWidth; - - connect(); - - if (is == null) { - if (isDirectory) { - FileNameMap map = java.net.URLConnection.getFileNameMap(); - - StringBuffer buf = new StringBuffer(); - - if (files == null) { - throw new FileNotFoundException(filename); - } - - sort(files); - - for (int i = 0 ; i < files.size() ; i++) { - String fileName = files.get(i); - buf.append(fileName); - buf.append("\n"); - } - // Put it into a (default) locale-specific byte-stream. - is = new ByteArrayInputStream(buf.toString().getBytes()); - } else { - throw new FileNotFoundException(filename); - } - } - return is; - } - - // IKVM specific method (sorting moved here to delay java.text.Collator dependency) - private static void sort(List files) { - Collections.sort(files, Collator.getInstance()); - } - - Permission permission; - - /* since getOutputStream isn't supported, only read permission is - * relevant - */ - public Permission getPermission() throws IOException { - if (permission == null) { - String decodedPath = ParseUtil.decode(url.getPath()); - if (File.separatorChar == '/') { - permission = new FilePermission(decodedPath, "read"); - } else { - permission = new FilePermission( - decodedPath.replace('/',File.separatorChar), "read"); - } - } - return permission; - } -} diff --git a/src/IKVM.Java/local/sun/net/www/protocol/file/Handler.java b/src/IKVM.Java/local/sun/net/www/protocol/file/Handler.java deleted file mode 100644 index 3ea4412558..0000000000 --- a/src/IKVM.Java/local/sun/net/www/protocol/file/Handler.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.net.www.protocol.file; - -import java.net.InetAddress; -import java.net.URLConnection; -import java.net.URL; -import java.net.Proxy; -import java.net.MalformedURLException; -import java.net.URLStreamHandler; -import java.io.InputStream; -import java.io.IOException; -import sun.net.www.ParseUtil; -import java.io.File; - -/** - * Open an file input stream given a URL. - * @author James Gosling - */ -public class Handler extends URLStreamHandler { - - private String getHost(URL url) { - String host = url.getHost(); - if (host == null) - host = ""; - return host; - } - - - protected void parseURL(URL u, String spec, int start, int limit) { - /* - * Ugly backwards compatibility. Flip any file separator - * characters to be forward slashes. This is a nop on Unix - * and "fixes" win32 file paths. According to RFC 2396, - * only forward slashes may be used to represent hierarchy - * separation in a URL but previous releases unfortunately - * performed this "fixup" behavior in the file URL parsing code - * rather than forcing this to be fixed in the caller of the URL - * class where it belongs. Since backslash is an "unwise" - * character that would normally be encoded if literally intended - * as a non-seperator character the damage of veering away from the - * specification is presumably limited. - */ - super.parseURL(u, spec.replace(File.separatorChar, '/'), start, limit); - } - - public synchronized URLConnection openConnection(URL url) - throws IOException { - return openConnection(url, null); - } - - public synchronized URLConnection openConnection(URL url, Proxy p) - throws IOException { - - String path; - String file = url.getFile(); - String host = url.getHost(); - - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - path = ParseUtil.decode(file); - path = path.replace('/', '\\'); - path = path.replace('|', ':'); - } else { - path = ParseUtil.decode(url.getPath()); - } - - if ((host == null) || host.equals("") || - host.equalsIgnoreCase("localhost") || - host.equals("~")) { - return createFileURLConnection(url, new File(path)); - } - - /* - * attempt to treat this as a UNC path. See 4180841 - */ - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - path = "\\\\" + host + path; - File f = new File(path); - if (f.exists()) { - return createFileURLConnection(url, f); - } - } - - /* - * Now attempt an ftp connection. - */ - URLConnection uc; - URL newurl; - - try { - newurl = new URL("ftp", host, file + - (url.getRef() == null ? "": - "#" + url.getRef())); - if (p != null) { - uc = newurl.openConnection(p); - } else { - uc = newurl.openConnection(); - } - } catch (IOException e) { - uc = null; - } - if (uc == null) { - throw new IOException("Unable to connect to: " + - url.toExternalForm()); - } - return uc; - } - - /** - * Template method to be overriden by Java Plug-in. [stanleyh] - */ - protected URLConnection createFileURLConnection(URL url, File file) { - return new FileURLConnection(url, file); - } - - /** - * Compares the host components of two URLs. - * @param u1 the URL of the first host to compare - * @param u2 the URL of the second host to compare - * @return true if and only if they - * are equal, false otherwise. - */ - protected boolean hostsEqual(URL u1, URL u2) { - /* - * Special case for file: URLs - * per RFC 1738 no hostname is equivalent to 'localhost' - * i.e. file:///path is equal to file://localhost/path - */ - String s1 = u1.getHost(); - String s2 = u2.getHost(); - if ("localhost".equalsIgnoreCase(s1) && ( s2 == null || "".equals(s2))) - return true; - if ("localhost".equalsIgnoreCase(s2) && ( s1 == null || "".equals(s1))) - return true; - return super.hostsEqual(u1, u2); - } -} diff --git a/src/IKVM.Java/local/sun/net/www/protocol/jar/JarFileFactory.java b/src/IKVM.Java/local/sun/net/www/protocol/jar/JarFileFactory.java deleted file mode 100644 index 74398f6af5..0000000000 --- a/src/IKVM.Java/local/sun/net/www/protocol/jar/JarFileFactory.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/*IKVM*/ -/* - * Modified for IKVM by Jeroen Frijters on May 22, 2007. - * - * This is a merged version of the Windows & Solaris platform specific versions. - * Since the IKVM class library binary can be used both on Windows and on *nix, - * I've merged the platform specific classes into a generic class that at - * runtime determines if it runs on Windows or not. - * -/*IKVM*/ - -package sun.net.www.protocol.jar; - -import java.io.IOException; -import java.io.FileNotFoundException; -import java.net.URL; -import java.net.URLConnection; -import java.util.HashMap; -import java.util.jar.JarFile; -import java.security.Permission; -import sun.net.util.URLUtil; - -/* A factory for cached JAR file. This class is used to both retrieve - * and cache Jar files. - * - * @author Benjamin Renaud - * @since JDK1.2 - */ -class JarFileFactory implements URLJarFile.URLJarFileCloseController { - - /* the url to file cache */ - private static final HashMap fileCache = new HashMap<>(); - - /* the file to url cache */ - private static final HashMap urlCache = new HashMap<>(); - - private static final JarFileFactory instance = new JarFileFactory(); - - private JarFileFactory() { } - - public static JarFileFactory getInstance() { - return instance; - } - - URLConnection getConnection(JarFile jarFile) throws IOException { - URL u; - synchronized (instance) { - u = urlCache.get(jarFile); - } - if (u != null) - return u.openConnection(); - - return null; - } - - public JarFile get(URL url) throws IOException { - return get(url, true); - } - - JarFile get(URL url, boolean useCaches) throws IOException { - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows() && url.getProtocol().equalsIgnoreCase("file")) { - // Deal with UNC pathnames specially. See 4180841 - - String host = url.getHost(); - if (host != null && !host.equals("") && - !host.equalsIgnoreCase("localhost")) { - - url = new URL("file", "", "//" + host + url.getPath()); - } - } - - JarFile result; - JarFile local_result; - - if (useCaches) { - synchronized (instance) { - result = getCachedJarFile(url); - } - if (result == null) { - local_result = URLJarFile.getJarFile(url, this); - synchronized (instance) { - result = getCachedJarFile(url); - if (result == null) { - fileCache.put(URLUtil.urlNoFragString(url), local_result); - urlCache.put(local_result, url); - result = local_result; - } else { - if (local_result != null) { - local_result.close(); - } - } - } - } - } else { - result = URLJarFile.getJarFile(url, this); - } - if (result == null) - throw new FileNotFoundException(url.toString()); - - return result; - } - - /** - * Callback method of the URLJarFileCloseController to - * indicate that the JarFile is close. This way we can - * remove the JarFile from the cache - */ - public void close(JarFile jarFile) { - synchronized (instance) { - URL urlRemoved = urlCache.remove(jarFile); - if (urlRemoved != null) - fileCache.remove(URLUtil.urlNoFragString(urlRemoved)); - } - } - - private JarFile getCachedJarFile(URL url) { - assert Thread.holdsLock(instance); - JarFile result = fileCache.get(URLUtil.urlNoFragString(url)); - - /* if the JAR file is cached, the permission will always be there */ - if (result != null) { - Permission perm = getPermission(result); - if (perm != null) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - try { - sm.checkPermission(perm); - } catch (SecurityException se) { - // fallback to checkRead/checkConnect for pre 1.2 - // security managers - if ((perm instanceof java.io.FilePermission) && - perm.getActions().indexOf("read") != -1) { - sm.checkRead(perm.getName()); - } else if ((perm instanceof - java.net.SocketPermission) && - perm.getActions().indexOf("connect") != -1) { - sm.checkConnect(url.getHost(), url.getPort()); - } else { - throw se; - } - } - } - } - } - return result; - } - - private Permission getPermission(JarFile jarFile) { - try { - URLConnection uc = getConnection(jarFile); - if (uc != null) - return uc.getPermission(); - } catch (IOException ioe) { - // gulp - } - - return null; - } -} diff --git a/src/IKVM.Java/local/sun/nio/ch/DatagramDispatcher.java b/src/IKVM.Java/local/sun/nio/ch/DatagramDispatcher.java deleted file mode 100644 index a200ef4c72..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/DatagramDispatcher.java +++ /dev/null @@ -1,21 +0,0 @@ -package sun.nio.ch; - -import java.io.*; - -class DatagramDispatcher extends NativeDispatcher { - - static { - IOUtil.load(); - } - - native int read(FileDescriptor fd, long address, int len) throws IOException; - - native long readv(FileDescriptor fd, long address, int len) throws IOException; - - native int write(FileDescriptor fd, long address, int len) throws IOException; - - native long writev(FileDescriptor fd, long address, int len) throws IOException; - - native void close(FileDescriptor fd) throws IOException; - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/DefaultAsynchronousChannelProvider.java b/src/IKVM.Java/local/sun/nio/ch/DefaultAsynchronousChannelProvider.java deleted file mode 100644 index 25f33fdf87..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/DefaultAsynchronousChannelProvider.java +++ /dev/null @@ -1,15 +0,0 @@ -package sun.nio.ch; - -import java.nio.channels.spi.AsynchronousChannelProvider; - -public class DefaultAsynchronousChannelProvider { - - private DefaultAsynchronousChannelProvider() { - - } - - public static AsynchronousChannelProvider create() { - return new DotNetAsynchronousChannelProvider(); - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/DefaultSelectorProvider.java b/src/IKVM.Java/local/sun/nio/ch/DefaultSelectorProvider.java deleted file mode 100644 index 4e6bebb736..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/DefaultSelectorProvider.java +++ /dev/null @@ -1,21 +0,0 @@ -package sun.nio.ch; - -import java.io.IOException; -import java.nio.channels.spi.AbstractSelector; -import java.nio.channels.spi.SelectorProvider; - -public class DefaultSelectorProvider { - - private DefaultSelectorProvider() { - - } - - public static SelectorProvider create() { - return new SelectorProviderImpl() { - public AbstractSelector openSelector() throws IOException { - return new DotNetSelectorImpl(this); - } - }; - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousChannelGroup.java b/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousChannelGroup.java deleted file mode 100644 index f86b7e98ec..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousChannelGroup.java +++ /dev/null @@ -1,61 +0,0 @@ -package sun.nio.ch; - -import java.nio.channels.*; -import java.nio.channels.spi.AsynchronousChannelProvider; -import java.io.Closeable; -import java.io.IOException; -import java.io.FileDescriptor; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import ikvm.internal.NotYetImplementedError; - -/** - * .NET implementation of AsynchronousChannelGroup. - */ -class DotNetAsynchronousChannelGroup extends AsynchronousChannelGroupImpl { - - private boolean closed; - - DotNetAsynchronousChannelGroup(AsynchronousChannelProvider provider, ThreadPool pool) throws IOException { - super(provider, pool); - } - - // release all resources - synchronized void implClose() { - closed = true; - } - - @Override - boolean isEmpty() { - return true; - } - - @Override - final Object attachForeignChannel(final Channel channel, FileDescriptor fdObj) throws IOException { - throw new NotYetImplementedError(); - } - - @Override - final void detachForeignChannel(Object key) { - throw new NotYetImplementedError(); - } - - @Override - void closeAllChannels() { - - } - - @Override - void executeOnHandlerTask(Runnable task) { - throw new NotYetImplementedError(); - } - - @Override - void shutdownHandlerTasks() { - - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousChannelProvider.java b/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousChannelProvider.java deleted file mode 100644 index d096956056..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousChannelProvider.java +++ /dev/null @@ -1,60 +0,0 @@ -package sun.nio.ch; - -import java.nio.channels.*; -import java.nio.channels.spi.AsynchronousChannelProvider; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ThreadFactory; -import java.io.IOException; - -public class DotNetAsynchronousChannelProvider extends AsynchronousChannelProvider { - - private static volatile DotNetAsynchronousChannelGroup defaultGroup; - - public DotNetAsynchronousChannelProvider() { - // nothing to do - } - - private DotNetAsynchronousChannelGroup defaultGroup() throws IOException { - if (defaultGroup == null) { - synchronized (DotNetAsynchronousChannelProvider.class) { - if (defaultGroup == null) { - defaultGroup = new DotNetAsynchronousChannelGroup(this, ThreadPool.getDefault()); - } - } - } - - return defaultGroup; - } - - @Override - public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory) throws IOException { - return new DotNetAsynchronousChannelGroup(this, ThreadPool.create(nThreads, factory)); - } - - @Override - public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize) throws IOException { - return new DotNetAsynchronousChannelGroup(this, ThreadPool.wrap(executor, initialSize)); - } - - private DotNetAsynchronousChannelGroup toDotNet(AsynchronousChannelGroup group) throws IOException { - if (group == null) { - return defaultGroup(); - } else { - if (!(group instanceof DotNetAsynchronousChannelGroup)) - throw new IllegalChannelGroupException(); - - return (DotNetAsynchronousChannelGroup)group; - } - } - - @Override - public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group) throws IOException { - return new DotNetAsynchronousServerSocketChannelImpl(toDotNet(group)); - } - - @Override - public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group) throws IOException { - return new DotNetAsynchronousSocketChannelImpl(toDotNet(group)); - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousFileChannelImpl.java b/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousFileChannelImpl.java deleted file mode 100644 index 3b27cef592..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousFileChannelImpl.java +++ /dev/null @@ -1,134 +0,0 @@ -package sun.nio.ch; - -import java.io.*; -import java.nio.*; -import java.nio.channels.*; -import java.util.concurrent.*; - -/** - * .NET implementation of AsynchronousFileChannel. - */ -public class DotNetAsynchronousFileChannelImpl extends AsynchronousFileChannelImpl implements Cancellable, Groupable { - - private static class DefaultGroupHolder { - - static final DotNetAsynchronousChannelGroup defaultGroup = defaultGroup(); - - private static DotNetAsynchronousChannelGroup defaultGroup() { - try { - return new DotNetAsynchronousChannelGroup(null, ThreadPool.createDefault()); - } catch (IOException ioe) { - throw new InternalError(ioe); - } - } - - } - - public static AsynchronousFileChannel open(FileDescriptor fdo, boolean reading, boolean writing, ThreadPool pool) throws IOException - { - DotNetAsynchronousChannelGroup group; - boolean isDefaultGroup; - - if (pool == null) { - group = DefaultGroupHolder.defaultGroup; - isDefaultGroup = true; - } else { - group = new DotNetAsynchronousChannelGroup(null, pool); - isDefaultGroup = false; - } - try { - return new DotNetAsynchronousFileChannelImpl(fdo, reading, writing, group, isDefaultGroup); - } catch (IOException x) { - // error binding to port so need to close it (if created for this channel) - if (!isDefaultGroup) - group.implClose(); - - throw x; - } - } - - protected final DotNetAsynchronousChannelGroup group; - protected final boolean isDefaultGroup; - - private DotNetAsynchronousFileChannelImpl(FileDescriptor fdObj, boolean reading, boolean writing, DotNetAsynchronousChannelGroup group, boolean isDefaultGroup) throws IOException { - super(fdObj, reading, writing, group.executor()); - this.group = group; - this.isDefaultGroup = isDefaultGroup; - } - - @Override - public AsynchronousChannelGroupImpl group() { - return group; - } - - @Override - public void onCancel(PendingFuture task) { - onCancel0(task); - } - - @Override - public void close() throws IOException { - close0(); - } - - @Override - public long size() throws IOException { - return size0(); - } - - @Override - public AsynchronousFileChannel truncate(long size) throws IOException { - return truncate0(size); - } - - @Override - public void force(boolean metaData) throws IOException { - force0(metaData); - } - - @Override - Future implLock(final long position, final long size, final boolean shared, A attachment, final CompletionHandler handler) { - return implLock0(position, size, shared, attachment, handler); - } - - @Override - public FileLock tryLock(long position, long size, boolean shared) throws IOException { - return tryLock0(position, size, shared); - } - - @Override - protected void implRelease(FileLockImpl fli) throws IOException { - implRelease0(fli); - } - - @Override - Future implRead(ByteBuffer dst, long position, A attachment, CompletionHandler handler) - { - return implRead0(dst, position, attachment, handler); - } - - Future implWrite(ByteBuffer src, long position, A attachment, CompletionHandler handler) { - return implWrite0(src, position, attachment, handler); - } - - private native void onCancel0(PendingFuture task); - - private native void close0(); - - private native long size0(); - - private native AsynchronousFileChannel truncate0(long size); - - private native void force0(boolean metaData); - - private native Future implLock0(final long position, final long size, final boolean shared, A attachment, final CompletionHandler handler); - - private native FileLock tryLock0(long position, long size, boolean shared); - - private native void implRelease0(FileLockImpl fli); - - private native Future implRead0(ByteBuffer dst, long position, A attachment, CompletionHandler handler); - - private native Future implWrite0(ByteBuffer src, long position, A attachment, CompletionHandler handler); - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousServerSocketChannelImpl.java b/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousServerSocketChannelImpl.java deleted file mode 100644 index 5b726c0c30..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousServerSocketChannelImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -package sun.nio.ch; - -import java.io.IOException; -import java.nio.channels.*; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * .NET implementation of AsynchronousServerSocketChannel using overlapped I/O. - */ -class DotNetAsynchronousServerSocketChannelImpl extends AsynchronousServerSocketChannelImpl { - - protected final DotNetAsynchronousChannelGroup group; - protected AtomicBoolean accepting = new AtomicBoolean(); - - DotNetAsynchronousServerSocketChannelImpl(DotNetAsynchronousChannelGroup group) throws IOException { - super(group); - this.group = group; - } - - @Override - public AsynchronousChannelGroupImpl group() { - return group; - } - - @Override - void implClose() throws IOException { - implClose0(); - } - - @Override - Future implAccept(Object attachment, final CompletionHandler handler) { - return implAccept0(attachment, handler); - } - - private native Future implAccept0(Object attachment, final CompletionHandler handler); - - private native void implClose0() throws IOException; - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousSocketChannelImpl.java b/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousSocketChannelImpl.java deleted file mode 100644 index 45525e0e8b..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/DotNetAsynchronousSocketChannelImpl.java +++ /dev/null @@ -1,70 +0,0 @@ -package sun.nio.ch; - -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; -import java.util.concurrent.*; - -/** - * .NET implementation of AsynchronousSocketChannelImpl. - */ -class DotNetAsynchronousSocketChannelImpl extends AsynchronousSocketChannelImpl { - - private final DotNetAsynchronousChannelGroup group; - - DotNetAsynchronousSocketChannelImpl(DotNetAsynchronousChannelGroup group, boolean failIfGroupShutdown) throws IOException { - super(group); - this.group = group; - } - - DotNetAsynchronousSocketChannelImpl(DotNetAsynchronousChannelGroup group) throws IOException { - this(group, true); - } - - DotNetAsynchronousSocketChannelImpl(DotNetAsynchronousChannelGroup group, FileDescriptor fd, InetSocketAddress remote) throws IOException { - super(group, fd, remote); - this.group = group; - } - - @Override - public AsynchronousChannelGroupImpl group() { - return group; - } - - @Override - public void onCancel(PendingFuture task) { - onCancel0(task); - } - - @Override - void implClose() throws IOException { - implClose0(); - } - - @Override - Future implConnect(SocketAddress remote, A attachment, CompletionHandler handler) { - return implConnect0(remote, attachment, handler); - } - - @Override - Future implRead(boolean isScatteringRead, ByteBuffer dst, ByteBuffer[] dsts, long timeout, TimeUnit unit, A attachment, CompletionHandler handler) { - return implRead0(isScatteringRead, dst, dsts, timeout, unit, attachment, handler); - } - - @Override - Future implWrite(boolean gatheringWrite, ByteBuffer src, ByteBuffer[] srcs, long timeout, TimeUnit unit, A attachment, CompletionHandler handler) { - return implWrite0(gatheringWrite, src, srcs, timeout, unit, attachment, handler); - } - - private native void onCancel0(PendingFuture task); - - private native void implClose0(); - - private native Future implConnect0(SocketAddress remote, A attachment, CompletionHandler handler); - - private native Future implRead0(boolean isScatteringRead, ByteBuffer dst, ByteBuffer[] dsts, long timeout, TimeUnit unit, A attachment, CompletionHandler handler); - - private native Future implWrite0(boolean gatheringWrite, ByteBuffer src, ByteBuffer[] srcs, long timeout, TimeUnit unit, A attachment, CompletionHandler handler); - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/DotNetSelectorImpl.java b/src/IKVM.Java/local/sun/nio/ch/DotNetSelectorImpl.java deleted file mode 100644 index e86e1dda97..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/DotNetSelectorImpl.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// Parts Copyright (C) 2002-2007 Jeroen Frijters - -package sun.nio.ch; - -import java.io.IOException; -import java.nio.channels.ClosedSelectorException; -import java.nio.channels.Pipe; -import java.nio.channels.SelectableChannel; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.spi.AbstractSelectableChannel; -import java.nio.channels.spi.AbstractSelector; -import java.nio.channels.spi.SelectorProvider; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import cli.System.Net.Sockets.Socket; -import cli.System.Net.Sockets.SocketException; -import cli.System.Net.Sockets.AddressFamily; -import cli.System.Net.Sockets.SocketType; -import cli.System.Net.Sockets.ProtocolType; -import cli.System.Net.Sockets.SelectMode; -import cli.System.Collections.ArrayList; - -final class DotNetSelectorImpl extends SelectorImpl { - - // class for fdMap entries - private final static class MapEntry { - - SelectionKeyImpl ski; - long updateCount = 0; - long clearedCount = 0; - - MapEntry(SelectionKeyImpl ski) { - this.ski = ski; - } - - } - - private ArrayList channelArray = new ArrayList(); - private long updateCount = 0; - - // pipe used as a wakeup object - private final Pipe wakeupPipe; - - // file descriptors corresponding to source and sink - private final Socket wakeupSourceFd, wakeupSinkFd; - - // lock for interrupt triggering and clearing - private final Object interruptLock = new Object(); - private volatile boolean interruptTriggered = false; - - private final HashMap fdMap = new HashMap(); - - DotNetSelectorImpl(SelectorProvider sp) throws IOException { - super(sp); - - wakeupPipe = Pipe.open(); - wakeupSourceFd = ((SelChImpl)wakeupPipe.source()).getFD().getSocket(); - - // disable the Nagle algorithm so that the wakeup is more immediate - SinkChannelImpl sink = (SinkChannelImpl)wakeupPipe.sink(); - (sink.sc).socket().setTcpNoDelay(true); - wakeupSinkFd = ((SelChImpl)sink).getFD().getSocket(); - } - - protected int doSelect(long timeout) throws IOException { - if (channelArray == null) - throw new ClosedSelectorException(); - - processDeregisterQueue(); - if (interruptTriggered) { - resetWakeupSocket(); - return 0; - } - - ArrayList read = new ArrayList(); - ArrayList write = new ArrayList(); - ArrayList error = new ArrayList(); - for (int i = 0; i < channelArray.get_Count(); i++) { - SelectionKeyImpl ski = (SelectionKeyImpl)channelArray.get_Item(i); - int ops = ski.interestOps(); - if (ski.channel() instanceof SocketChannelImpl) { - // TODO there's a race condition here... - if (((SocketChannelImpl)ski.channel()).isConnected()) { - ops &= SelectionKey.OP_READ | SelectionKey.OP_WRITE; - } else { - ops &= SelectionKey.OP_CONNECT; - } - } - - if ((ops & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0) { - read.Add(((SelChImpl)ski.channel()).getFD().getSocket()); - } - - if ((ops & (SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT)) != 0) { - write.Add(((SelChImpl)ski.channel()).getFD().getSocket()); - } - - if ((ops & SelectionKey.OP_CONNECT) != 0) { - error.Add(((SelChImpl)ski.channel()).getFD().getSocket()); - } - } - - read.Add(wakeupSourceFd); - - try - { - begin(); - int microSeconds = 1000 * (int)Math.min(Integer.MAX_VALUE / 1000, timeout); - try { - if (false) throw new SocketException(); - // FXBUG docs say that -1 is infinite timeout, but that doesn't appear to work - Socket.Select(read, write, error, timeout < 0 ? Integer.MAX_VALUE : microSeconds); - } catch (SocketException _) { - read.Clear(); - write.Clear(); - error.Clear(); - } - } finally { - end(); - } - - processDeregisterQueue(); - int updated = updateSelectedKeys(read, write, error); - - // done with poll(), set wakeupSocket to nonsignaled for the next run. - resetWakeupSocket(); - return updated; - } - - private int updateSelectedKeys(ArrayList read, ArrayList write, ArrayList error) { - updateCount++; - int keys = processFDSet(updateCount, read, Net.POLLIN); - keys += processFDSet(updateCount, write, Net.POLLCONN | Net.POLLOUT); - keys += processFDSet(updateCount, error, Net.POLLIN | Net.POLLCONN | Net.POLLOUT); - return keys; - } - - private int processFDSet(long updateCount, ArrayList sockets, int rOps) { - int numKeysUpdated = 0; - - for (int i = 0; i < sockets.get_Count(); i++) { - Socket desc = (Socket)sockets.get_Item(i); - if (desc == wakeupSourceFd) { - synchronized (interruptLock) { - interruptTriggered = true; - } - - continue; - } - - // if me is null, the key was deregistered in the previous processDeregisterQueue - MapEntry me = fdMap.get(desc); - if (me == null) - continue; - SelectionKeyImpl sk = me.ski; - if (selectedKeys.contains(sk)) { - if (me.clearedCount != updateCount) { - // key in selected set - if (sk.channel.translateAndSetReadyOps(rOps, sk) && (me.updateCount != updateCount)) { - me.updateCount = updateCount; - numKeysUpdated++; - } - } else { - // the readyOps have been set; now add - if (sk.channel.translateAndUpdateReadyOps(rOps, sk) && (me.updateCount != updateCount)) { - me.updateCount = updateCount; - numKeysUpdated++; - } - } - - me.clearedCount = updateCount; - } else { - if (me.clearedCount != updateCount) { - // Key is not in selected set yet - sk.channel.translateAndSetReadyOps(rOps, sk); - if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) { - selectedKeys.add(sk); - me.updateCount = updateCount; - numKeysUpdated++; - } - } else { - // The readyOps have been set; now add - sk.channel.translateAndUpdateReadyOps(rOps, sk); - if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) { - selectedKeys.add(sk); - me.updateCount = updateCount; - numKeysUpdated++; - } - } - - me.clearedCount = updateCount; - } - } - - return numKeysUpdated; - } - - protected void implClose() throws IOException { - if (channelArray != null) { - // prevent further wakeup - synchronized (interruptLock) { - interruptTriggered = true; - } - - wakeupPipe.sink().close(); - wakeupPipe.source().close(); - for (int i = 0; i < channelArray.get_Count(); i++) { - // Deregister channels - SelectionKeyImpl ski = (SelectionKeyImpl)channelArray.get_Item(i); - deregister(ski); - SelectableChannel selch = ski.channel(); - if (!selch.isOpen() && !selch.isRegistered()) - ((SelChImpl)selch).kill(); - } - selectedKeys = null; - channelArray = null; - } - } - - protected void implRegister(SelectionKeyImpl ski) { - channelArray.Add(ski); - fdMap.put(((SelChImpl)ski.channel()).getFD().getSocket(), new MapEntry(ski)); - keys.add(ski); - } - - protected void implDereg(SelectionKeyImpl ski) throws IOException { - channelArray.Remove(ski); - fdMap.remove(((SelChImpl)ski.channel()).getFD().getSocket()); - keys.remove(ski); - selectedKeys.remove(ski); - deregister(ski); - - SelectableChannel selch = ski.channel(); - if (!selch.isOpen() && !selch.isRegistered()) { - ((SelChImpl)selch).kill(); - } - } - - public Selector wakeup() { - synchronized (interruptLock) { - if (!interruptTriggered) { - setWakeupSocket(); - interruptTriggered = true; - } - } - - return this; - } - - // Sets Windows wakeup socket to a signaled state. - private void setWakeupSocket() { - wakeupSinkFd.Send(new byte[1]); - } - - // Sets Windows wakeup socket to a non-signaled state. - private void resetWakeupSocket() { - synchronized (interruptLock) { - if (interruptTriggered == false) - return; - - resetWakeupSocket0(wakeupSourceFd); - interruptTriggered = false; - } - } - - private static void resetWakeupSocket0(Socket wakeupSourceFd) { - while (wakeupSourceFd.get_Available() > 0) { - wakeupSourceFd.Receive(new byte[1]); - } - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/FileDispatcherImpl.java b/src/IKVM.Java/local/sun/nio/ch/FileDispatcherImpl.java deleted file mode 100644 index a22cc59f37..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/FileDispatcherImpl.java +++ /dev/null @@ -1,141 +0,0 @@ -package sun.nio.ch; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.security.PrivilegedAction; - -import sun.misc.SharedSecrets; -import sun.misc.JavaIOFileDescriptorAccess; - -class FileDispatcherImpl extends FileDispatcher { - - // set to true if fast file transmission (TransmitFile) is enabled - private static final boolean fastFileTransfer; - - /** - * Indicates if the dispatcher should first advance the file position - * to the end of file when writing. - */ - private final boolean append; - - FileDispatcherImpl(boolean append) { - this.append = append; - } - - FileDispatcherImpl() { - this(false); - } - - @Override - boolean needsPositionLock() { - return true; - } - - int read(FileDescriptor fd, long address, int len) throws IOException { - return read0(fd, address, len); - } - - static native int read0(FileDescriptor fd, long address, int len) throws IOException; - - int pread(FileDescriptor fd, long address, int len, long position) throws IOException { - return pread0(fd, address, len, position); - } - - static native int pread0(FileDescriptor fd, long address, int len, long position) throws IOException; - - long readv(FileDescriptor fd, long address, int len) throws IOException { - return readv0(fd, address, len); - } - - static native long readv0(FileDescriptor fd, long address, int len) throws IOException; - - int write(FileDescriptor fd, long address, int len) throws IOException { - return write0(fd, address, len, append); - } - - static native int write0(FileDescriptor fd, long address, int len, boolean append) throws IOException; - - int pwrite(FileDescriptor fd, long address, int len, long position) throws IOException { - return pwrite0(fd, address, len, position); - } - - static native int pwrite0(FileDescriptor fd, long address, int len, long position) throws IOException; - - long writev(FileDescriptor fd, long address, int len) throws IOException { - return writev0(fd, address, len, append); - } - - static native long writev0(FileDescriptor fd, long address, int len, boolean append) throws IOException; - - int force(FileDescriptor fd, boolean metaData) throws IOException { - return force0(fd, metaData); - } - - static native int force0(FileDescriptor fd, boolean metaData) throws IOException; - - int truncate(FileDescriptor fd, long size) throws IOException { - return truncate0(fd, size); - } - - static native int truncate0(FileDescriptor fd, long size) throws IOException; - - long size(FileDescriptor fd) throws IOException { - return size0(fd); - } - - static native long size0(FileDescriptor fd) throws IOException; - - int lock(FileDescriptor fd, boolean blocking, long pos, long size, boolean shared) throws IOException { - return lock0(fd, blocking, pos, size, shared); - } - - static native int lock0(FileDescriptor fd, boolean blocking, long pos, long size, boolean shared) throws IOException; - - void release(FileDescriptor fd, long pos, long size) throws IOException { - release0(fd, pos, size); - } - - static native void release0(FileDescriptor fd, long pos, long size) throws IOException; - - void close(FileDescriptor fd) throws IOException { - close0(fd); - } - - static native void close0(FileDescriptor fd) throws IOException; - - native FileDescriptor duplicateForMapping(FileDescriptor fd) throws IOException; - - boolean canTransferToDirectly(java.nio.channels.SelectableChannel sc) { - return fastFileTransfer && sc.isBlocking(); - } - - boolean transferToDirectlyNeedsPositionLock() { - return transferToDirectlyNeedsPositionLock0(); - } - - static native boolean transferToDirectlyNeedsPositionLock0(); - - static boolean isFastFileTransferRequested() { - String fileTransferProp = java.security.AccessController.doPrivileged(new PrivilegedAction() { - @Override - public String run() { - return System.getProperty("jdk.nio.enableFastFileTransfer"); - } - }); - - boolean enable; - if ("".equals(fileTransferProp)) { - enable = true; - } else { - enable = Boolean.parseBoolean(fileTransferProp); - } - - return enable; - } - - static { - IOUtil.load(); - fastFileTransfer = isFastFileTransferRequested(); - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/FileKey.java b/src/IKVM.Java/local/sun/nio/ch/FileKey.java deleted file mode 100644 index 4feec5d318..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/FileKey.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright (C) 2007 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -package sun.nio.ch; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.IOException; - -public class FileKey -{ - private String path; - - public static FileKey create(FileDescriptor fd) - { - FileKey fk = new FileKey(); - fk.path = ((cli.System.IO.FileStream)fd.getStream()).get_Name(); - try - { - fk.path = new File(fk.path).getCanonicalPath(); - } - catch (IOException x) - { - } - return fk; - } - - public int hashCode() - { - return path.hashCode(); - } - - public boolean equals(Object obj) - { - return obj == this || (obj instanceof FileKey && ((FileKey)obj).path.equals(path)); - } -} diff --git a/src/IKVM.Java/local/sun/nio/ch/PipeImpl.java b/src/IKVM.Java/local/sun/nio/ch/PipeImpl.java deleted file mode 100644 index b86580dcca..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/PipeImpl.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - */ - -package sun.nio.ch; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.nio.*; -import java.nio.channels.*; -import java.nio.channels.spi.*; -import java.security.AccessController; -import java.security.PrivilegedExceptionAction; -import java.security.PrivilegedActionException; -import java.util.Random; - - -/** - * A simple Pipe implementation based on a socket connection. - */ - -class PipeImpl - extends Pipe -{ - - // Source and sink channels - private SourceChannel source; - private SinkChannel sink; - - // Random object for handshake values - private static final Random rnd; - - static { - byte[] someBytes = new byte[8]; - boolean resultOK = IOUtil.randomBytes(someBytes); - if (resultOK) { - rnd = new Random(ByteBuffer.wrap(someBytes).getLong()); - } else { - rnd = new Random(); - } - } - - private class Initializer - implements PrivilegedExceptionAction - { - - private final SelectorProvider sp; - - private IOException ioe = null; - - private Initializer(SelectorProvider sp) { - this.sp = sp; - } - - @Override - public Void run() throws IOException { - LoopbackConnector connector = new LoopbackConnector(); - connector.run(); - if (ioe instanceof ClosedByInterruptException) { - ioe = null; - Thread connThread = new Thread(connector) { - @Override - public void interrupt() {} - }; - connThread.start(); - for (;;) { - try { - connThread.join(); - break; - } catch (InterruptedException ex) {} - } - Thread.currentThread().interrupt(); - } - - if (ioe != null) - throw new IOException("Unable to establish loopback connection", ioe); - - return null; - } - - private class LoopbackConnector implements Runnable { - - @Override - public void run() { - ServerSocketChannel ssc = null; - SocketChannel sc1 = null; - SocketChannel sc2 = null; - - try { - // Loopback address - InetAddress lb = InetAddress.getByName("127.0.0.1"); - assert(lb.isLoopbackAddress()); - InetSocketAddress sa = null; - for(;;) { - // Bind ServerSocketChannel to a port on the loopback - // address - if (ssc == null || !ssc.isOpen()) { - ssc = ServerSocketChannel.open(); - ssc.socket().bind(new InetSocketAddress(lb, 0)); - sa = new InetSocketAddress(lb, ssc.socket().getLocalPort()); - } - - // Establish connection (assume connections are eagerly - // accepted) - sc1 = SocketChannel.open(sa); - ByteBuffer bb = ByteBuffer.allocate(8); - long secret = rnd.nextLong(); - bb.putLong(secret).flip(); - sc1.write(bb); - - // Get a connection and verify it is legitimate - sc2 = ssc.accept(); - bb.clear(); - sc2.read(bb); - bb.rewind(); - if (bb.getLong() == secret) - break; - sc2.close(); - sc1.close(); - } - - // Create source and sink channels - source = new SourceChannelImpl(sp, sc1); - sink = new SinkChannelImpl(sp, sc2); - } catch (IOException e) { - try { - if (sc1 != null) - sc1.close(); - if (sc2 != null) - sc2.close(); - } catch (IOException e2) {} - ioe = e; - } finally { - try { - if (ssc != null) - ssc.close(); - } catch (IOException e2) {} - } - } - } - } - - PipeImpl(final SelectorProvider sp) throws IOException { - try { - AccessController.doPrivileged(new Initializer(sp)); - } catch (PrivilegedActionException x) { - throw (IOException)x.getCause(); - } - } - - public SourceChannel source() { - return source; - } - - public SinkChannel sink() { - return sink; - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/PollArrayWrapper.java b/src/IKVM.Java/local/sun/nio/ch/PollArrayWrapper.java deleted file mode 100644 index f05f2b5cd7..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/PollArrayWrapper.java +++ /dev/null @@ -1,87 +0,0 @@ -package sun.nio.ch; - -import java.lang.annotation.Native; - -/** - * Manipulates a native array of structs corresponding to (fd, events) pairs. - * - * typedef struct pollfd { - * SOCKET fd; // 4 bytes - * short events; // 2 bytes - * } pollfd_t; - * - * @author Konstantin Kladko - * @author Mike McCloskey - */ - -class PollArrayWrapper { - - private AllocatedNativeObject pollArray; // The fd array - - long pollArrayAddress; // pollArrayAddress - - @Native private static final short FD_OFFSET = 0; // fd offset in pollfd - @Native private static final short EVENT_OFFSET = 4; // events offset in pollfd - - static short SIZE_POLLFD = 8; // sizeof pollfd struct - - private int size; // Size of the pollArray - - PollArrayWrapper(int newSize) { - int allocationSize = newSize * SIZE_POLLFD; - pollArray = new AllocatedNativeObject(allocationSize, true); - pollArrayAddress = pollArray.address(); - this.size = newSize; - } - - // Prepare another pollfd struct for use. - void addEntry(int index, SelectionKeyImpl ski) { - putDescriptor(index, ski.channel.getFDVal()); - } - - // Writes the pollfd entry from the source wrapper at the source index - // over the entry in the target wrapper at the target index. - void replaceEntry(PollArrayWrapper source, int sindex, PollArrayWrapper target, int tindex) { - target.putDescriptor(tindex, source.getDescriptor(sindex)); - target.putEventOps(tindex, source.getEventOps(sindex)); - } - - // Grows the pollfd array to new size - void grow(int newSize) { - PollArrayWrapper temp = new PollArrayWrapper(newSize); - for (int i = 0; i < size; i++) - replaceEntry(this, i, temp, i); - pollArray.free(); - pollArray = temp.pollArray; - this.size = temp.size; - pollArrayAddress = pollArray.address(); - } - - void free() { - pollArray.free(); - } - - // Access methods for fd structures - void putDescriptor(int i, int fd) { - pollArray.putInt(SIZE_POLLFD * i + FD_OFFSET, fd); - } - - void putEventOps(int i, int event) { - pollArray.putShort(SIZE_POLLFD * i + EVENT_OFFSET, (short)event); - } - - int getEventOps(int i) { - return pollArray.getShort(SIZE_POLLFD * i + EVENT_OFFSET); - } - - int getDescriptor(int i) { - return pollArray.getInt(SIZE_POLLFD * i + FD_OFFSET); - } - - // Adds Windows wakeup socket at a given index. - void addWakeupSocket(int fdVal, int index) { - putDescriptor(index, fdVal); - putEventOps(index, Net.POLLIN); - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/SinkChannelImpl.java b/src/IKVM.Java/local/sun/nio/ch/SinkChannelImpl.java deleted file mode 100644 index 57e88ac38c..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/SinkChannelImpl.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - */ - -package sun.nio.ch; - -import java.io.IOException; -import java.io.FileDescriptor; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.nio.channels.spi.*; - - -/** - * Pipe.SinkChannel implementation based on socket connection. - */ - -class SinkChannelImpl - extends Pipe.SinkChannel - implements SelChImpl -{ - // The SocketChannel assoicated with this pipe - SocketChannel sc; - - public FileDescriptor getFD() { - return ((SocketChannelImpl)sc).getFD(); - } - - public int getFDVal() { - return ((SocketChannelImpl)sc).getFDVal(); - } - - SinkChannelImpl(SelectorProvider sp, SocketChannel sc) { - super(sp); - this.sc = sc; - } - - protected void implCloseSelectableChannel() throws IOException { - if (!isRegistered()) - kill(); - } - - public void kill() throws IOException { - sc.close(); - } - - protected void implConfigureBlocking(boolean block) throws IOException { - sc.configureBlocking(block); - } - - public boolean translateReadyOps(int ops, int initialOps, - SelectionKeyImpl sk) { - int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes - int oldOps = sk.nioReadyOps(); - int newOps = initialOps; - - if ((ops & Net.POLLNVAL) != 0) - throw new Error("POLLNVAL detected"); - - if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) { - newOps = intOps; - sk.nioReadyOps(newOps); - return (newOps & ~oldOps) != 0; - } - - if (((ops & Net.POLLOUT) != 0) && - ((intOps & SelectionKey.OP_WRITE) != 0)) - newOps |= SelectionKey.OP_WRITE; - - sk.nioReadyOps(newOps); - return (newOps & ~oldOps) != 0; - } - - public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) { - return translateReadyOps(ops, sk.nioReadyOps(), sk); - } - - public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) { - return translateReadyOps(ops, 0, sk); - } - - public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) { - if ((ops & SelectionKey.OP_WRITE) != 0) - ops = Net.POLLOUT; - sk.selector.putEventOps(sk, ops); - } - - public int write(ByteBuffer src) throws IOException { - try { - return sc.write(src); - } catch (AsynchronousCloseException x) { - close(); - throw x; - } - } - - public long write(ByteBuffer[] srcs) throws IOException { - try { - return sc.write(srcs); - } catch (AsynchronousCloseException x) { - close(); - throw x; - } - } - - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) - throw new IndexOutOfBoundsException(); - try { - return write(Util.subsequence(srcs, offset, length)); - } catch (AsynchronousCloseException x) { - close(); - throw x; - } - } -} diff --git a/src/IKVM.Java/local/sun/nio/ch/SocketDispatcher.java b/src/IKVM.Java/local/sun/nio/ch/SocketDispatcher.java deleted file mode 100644 index bfeaf9889f..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/SocketDispatcher.java +++ /dev/null @@ -1,23 +0,0 @@ -package sun.nio.ch; - -import java.io.*; - -class SocketDispatcher extends NativeDispatcher { - - static { - IOUtil.load(); - } - - native int read(FileDescriptor fd, long address, int len) throws IOException; - - native long readv(FileDescriptor fd, long address, int len) throws IOException; - - native int write(FileDescriptor fd, long address, int len) throws IOException; - - native long writev(FileDescriptor fd, long address, int len) throws IOException; - - native void preClose(FileDescriptor fd) throws IOException; - - native void close(FileDescriptor fd) throws IOException; - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/SocketOptionRegistry.java b/src/IKVM.Java/local/sun/nio/ch/SocketOptionRegistry.java deleted file mode 100644 index d94d36efeb..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/SocketOptionRegistry.java +++ /dev/null @@ -1,92 +0,0 @@ -package sun.nio.ch; - -import java.net.SocketOption; -import java.net.StandardSocketOptions; -import java.net.ProtocolFamily; -import java.net.StandardProtocolFamily; -import java.util.Map; -import java.util.HashMap; - -import cli.System.Net.Sockets.SocketOptionLevel; -import cli.System.Net.Sockets.SocketOptionName; - -class SocketOptionRegistry -{ - - private SocketOptionRegistry() - { - - } - - private static class RegistryKey - { - - private final SocketOption name; - private final ProtocolFamily family; - - RegistryKey(SocketOption name, ProtocolFamily family) - { - this.name = name; - this.family = family; - } - - public int hashCode() - { - return name.hashCode() + family.hashCode(); - } - - public boolean equals(Object ob) - { - if (ob == null) - return false; - if (!(ob instanceof RegistryKey)) - return false; - - RegistryKey other = (RegistryKey)ob; - if (this.name != other.name) - return false; - if (this.family != other.family) - return false; - - return true; - } - - } - - private static class LazyInitialization - { - - static final Map options = options(); - - private static Map options() - { - Map map = new HashMap(); - map.put(new RegistryKey(StandardSocketOptions.SO_BROADCAST, Net.UNSPEC), new OptionKey(SocketOptionLevel.Socket, SocketOptionName.Broadcast)); - map.put(new RegistryKey(StandardSocketOptions.SO_KEEPALIVE, Net.UNSPEC), new OptionKey(SocketOptionLevel.Socket, SocketOptionName.KeepAlive)); - map.put(new RegistryKey(StandardSocketOptions.SO_LINGER, Net.UNSPEC), new OptionKey(SocketOptionLevel.Socket, SocketOptionName.Linger)); - map.put(new RegistryKey(StandardSocketOptions.SO_SNDBUF, Net.UNSPEC), new OptionKey(SocketOptionLevel.Socket, SocketOptionName.SendBuffer)); - map.put(new RegistryKey(StandardSocketOptions.SO_RCVBUF, Net.UNSPEC), new OptionKey(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer)); - map.put(new RegistryKey(StandardSocketOptions.SO_REUSEADDR, Net.UNSPEC), new OptionKey(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress)); - map.put(new RegistryKey(StandardSocketOptions.TCP_NODELAY, Net.UNSPEC), new OptionKey(SocketOptionLevel.Tcp, SocketOptionName.NoDelay)); - map.put(new RegistryKey(StandardSocketOptions.IP_TOS, StandardProtocolFamily.INET), new OptionKey(SocketOptionLevel.IP, SocketOptionName.TypeOfService)); - map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, StandardProtocolFamily.INET), new OptionKey(SocketOptionLevel.IP, SocketOptionName.MulticastInterface)); - map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, StandardProtocolFamily.INET), new OptionKey(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive)); - map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, StandardProtocolFamily.INET), new OptionKey(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)); - map.put(new RegistryKey(StandardSocketOptions.IP_TOS, StandardProtocolFamily.INET6), new OptionKey(SocketOptionLevel.IPv6, 39)); // TODO this whole file needs to be auto generated for OS - map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, StandardProtocolFamily.INET6), new OptionKey(SocketOptionLevel.IPv6, SocketOptionName.MulticastInterface)); - map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, StandardProtocolFamily.INET6), new OptionKey(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive)); - map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, StandardProtocolFamily.INET6), new OptionKey(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)); - map.put(new RegistryKey(ExtendedSocketOption.SO_OOBINLINE, Net.UNSPEC), new OptionKey(SocketOptionLevel.Socket, SocketOptionName.OutOfBandInline)); - return map; - } - } - - public static OptionKey findOption(SocketOption name, ProtocolFamily family) - { - - RegistryKey key = new RegistryKey(name, family); - return LazyInitialization.options.get(key); - - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/SourceChannelImpl.java b/src/IKVM.Java/local/sun/nio/ch/SourceChannelImpl.java deleted file mode 100644 index 2605d61b47..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/SourceChannelImpl.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - */ - -package sun.nio.ch; - -import java.io.IOException; -import java.io.FileDescriptor; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.nio.channels.spi.*; - -/** - * Pipe.SourceChannel implementation based on socket connection. - */ - -class SourceChannelImpl - extends Pipe.SourceChannel - implements SelChImpl -{ - // The SocketChannel assoicated with this pipe - SocketChannel sc; - - public FileDescriptor getFD() { - return ((SocketChannelImpl) sc).getFD(); - } - - public int getFDVal() { - return ((SocketChannelImpl) sc).getFDVal(); - } - - SourceChannelImpl(SelectorProvider sp, SocketChannel sc) { - super(sp); - this.sc = sc; - } - - protected void implCloseSelectableChannel() throws IOException { - if (!isRegistered()) - kill(); - } - - public void kill() throws IOException { - sc.close(); - } - - protected void implConfigureBlocking(boolean block) throws IOException { - sc.configureBlocking(block); - } - - public boolean translateReadyOps(int ops, int initialOps, - SelectionKeyImpl sk) { - int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes - int oldOps = sk.nioReadyOps(); - int newOps = initialOps; - - if ((ops & Net.POLLNVAL) != 0) - throw new Error("POLLNVAL detected"); - - if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) { - newOps = intOps; - sk.nioReadyOps(newOps); - return (newOps & ~oldOps) != 0; - } - - if (((ops & Net.POLLIN) != 0) && - ((intOps & SelectionKey.OP_READ) != 0)) - newOps |= SelectionKey.OP_READ; - - sk.nioReadyOps(newOps); - return (newOps & ~oldOps) != 0; - } - - public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) { - return translateReadyOps(ops, sk.nioReadyOps(), sk); - } - - public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) { - return translateReadyOps(ops, 0, sk); - } - - public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) { - if ((ops & SelectionKey.OP_READ) != 0) - ops = Net.POLLIN; - sk.selector.putEventOps(sk, ops); - } - - public int read(ByteBuffer dst) throws IOException { - try { - return sc.read(dst); - } catch (AsynchronousCloseException x) { - close(); - throw x; - } - } - - public long read(ByteBuffer[] dsts, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) - throw new IndexOutOfBoundsException(); - try { - return read(Util.subsequence(dsts, offset, length)); - } catch (AsynchronousCloseException x) { - close(); - throw x; - } - } - - public long read(ByteBuffer[] dsts) throws IOException { - try { - return sc.read(dsts); - } catch (AsynchronousCloseException x) { - close(); - throw x; - } - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/sctp/SctpChannelImpl.java b/src/IKVM.Java/local/sun/nio/ch/sctp/SctpChannelImpl.java deleted file mode 100644 index 53ac4846d8..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/sctp/SctpChannelImpl.java +++ /dev/null @@ -1,115 +0,0 @@ -package sun.nio.ch.sctp; - -import java.net.SocketAddress; -import java.net.InetAddress; -import java.io.IOException; -import java.util.Set; -import java.nio.ByteBuffer; -import java.nio.channels.spi.SelectorProvider; - -import com.sun.nio.sctp.Association; -import com.sun.nio.sctp.MessageInfo; -import com.sun.nio.sctp.NotificationHandler; -import com.sun.nio.sctp.SctpChannel; -import com.sun.nio.sctp.SctpSocketOption; - -public class SctpChannelImpl extends SctpChannel { - - private static final String message = "SCTP not supported on this platform"; - - public SctpChannelImpl(SelectorProvider provider) { - super(provider); - throw new UnsupportedOperationException(message); - } - - @Override - public Association association() { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpChannel bind(SocketAddress local) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpChannel bindAddress(InetAddress address) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpChannel unbindAddress(InetAddress address) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public boolean connect(SocketAddress remote) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public boolean connect(SocketAddress remote, int maxOutStreams, int maxInStreams) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public boolean isConnectionPending() { - throw new UnsupportedOperationException(message); - } - - @Override - public boolean finishConnect() throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public Set getAllLocalAddresses() throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public Set getRemoteAddresses() throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpChannel shutdown() throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public T getOption(SctpSocketOption name) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpChannel setOption(SctpSocketOption name, T value) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public Set> supportedOptions() { - throw new UnsupportedOperationException(message); - } - - @Override - public MessageInfo receive(ByteBuffer dst, T attachment, NotificationHandler handler) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public int send(ByteBuffer src, MessageInfo messageInfo) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - protected void implConfigureBlocking(boolean block) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public void implCloseSelectableChannel() throws IOException { - throw new UnsupportedOperationException(message); - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/sctp/SctpMultiChannelImpl.java b/src/IKVM.Java/local/sun/nio/ch/sctp/SctpMultiChannelImpl.java deleted file mode 100644 index bab2870f5a..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/sctp/SctpMultiChannelImpl.java +++ /dev/null @@ -1,101 +0,0 @@ -package sun.nio.ch.sctp; - -import java.net.SocketAddress; -import java.net.InetAddress; -import java.io.IOException; -import java.util.Set; -import java.nio.ByteBuffer; -import java.nio.channels.spi.SelectorProvider; - -import com.sun.nio.sctp.Association; -import com.sun.nio.sctp.SctpChannel; -import com.sun.nio.sctp.MessageInfo; -import com.sun.nio.sctp.NotificationHandler; -import com.sun.nio.sctp.SctpMultiChannel; -import com.sun.nio.sctp.SctpSocketOption; - -public class SctpMultiChannelImpl extends SctpMultiChannel { - - private static final String message = "SCTP not supported on this platform"; - - public SctpMultiChannelImpl(SelectorProvider provider) { - super(provider); - throw new UnsupportedOperationException(message); - } - - @Override - public Set associations() { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpMultiChannel bind(SocketAddress local, int backlog) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpMultiChannel bindAddress(InetAddress address) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpMultiChannel unbindAddress(InetAddress address) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public Set getAllLocalAddresses() throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public Set getRemoteAddresses (Association association) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpMultiChannel shutdown(Association association) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public T getOption(SctpSocketOption name, Association association) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpMultiChannel setOption(SctpSocketOption name, T value, Association association) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public Set> supportedOptions() { - throw new UnsupportedOperationException(message); - } - - @Override - public MessageInfo receive(ByteBuffer buffer, T attachment, NotificationHandler handler) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public int send(ByteBuffer buffer, MessageInfo messageInfo) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpChannel branch(Association association) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - protected void implConfigureBlocking(boolean block) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public void implCloseSelectableChannel() throws IOException { - throw new UnsupportedOperationException(message); - } - -} diff --git a/src/IKVM.Java/local/sun/nio/ch/sctp/SctpServerChannelImpl.java b/src/IKVM.Java/local/sun/nio/ch/sctp/SctpServerChannelImpl.java deleted file mode 100644 index d8b1afbfb4..0000000000 --- a/src/IKVM.Java/local/sun/nio/ch/sctp/SctpServerChannelImpl.java +++ /dev/null @@ -1,72 +0,0 @@ -package sun.nio.ch.sctp; - -import java.net.SocketAddress; -import java.net.InetAddress; -import java.io.IOException; -import java.util.Set; -import java.nio.channels.spi.SelectorProvider; - -import com.sun.nio.sctp.SctpChannel; -import com.sun.nio.sctp.SctpServerChannel; -import com.sun.nio.sctp.SctpSocketOption; - -public class SctpServerChannelImpl extends SctpServerChannel { - - private static final String message = "SCTP not supported on this platform"; - - public SctpServerChannelImpl(SelectorProvider provider) { - super(provider); - throw new UnsupportedOperationException(message); - } - - @Override - public SctpChannel accept() throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpServerChannel bind(SocketAddress local, int backlog) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpServerChannel bindAddress(InetAddress address) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpServerChannel unbindAddress(InetAddress address) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public Set getAllLocalAddresses() throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public T getOption(SctpSocketOption name) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public SctpServerChannel setOption(SctpSocketOption name, T value) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public Set> supportedOptions() { - throw new UnsupportedOperationException(message); - } - - @Override - protected void implConfigureBlocking(boolean block) throws IOException { - throw new UnsupportedOperationException(message); - } - - @Override - public void implCloseSelectableChannel() throws IOException { - throw new UnsupportedOperationException(message); - } - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/DefaultFileSystemProvider.java b/src/IKVM.Java/local/sun/nio/fs/DefaultFileSystemProvider.java deleted file mode 100644 index e8eea74c82..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/DefaultFileSystemProvider.java +++ /dev/null @@ -1,19 +0,0 @@ -package sun.nio.fs; - -import java.nio.file.spi.FileSystemProvider; - -public class DefaultFileSystemProvider { - - public static FileSystemProvider create() { - return new DotNetFileSystemProvider(); - - //if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - // return new WindowsFileSystemProvider(); - //} else if (cli.IKVM.Runtime.RuntimeUtil.get_IsLinux()) { - // return new LinuxFileSystemProvider(); - //} else { - // return new DotNetFileSystemProvider(); - //} - } - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/DefaultFileTypeDetector.java b/src/IKVM.Java/local/sun/nio/fs/DefaultFileTypeDetector.java deleted file mode 100644 index f488b3fc26..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/DefaultFileTypeDetector.java +++ /dev/null @@ -1,32 +0,0 @@ -package sun.nio.fs; - -import java.io.IOException; -import java.nio.file.FileSystems; -import java.nio.file.Path; -import java.nio.file.spi.FileTypeDetector; -import java.nio.file.spi.FileSystemProvider; - -public class DefaultFileTypeDetector { - - public static FileTypeDetector create() { - return new AbstractFileTypeDetector() { - public String implProbeContentType(Path obj) throws IOException { - return null; - } - }; - - //FileSystemProvider provider = FileSystems.getDefault().provider(); - //if (provider instanceof UnixFileSystemProvider) { - // return ((UnixFileSystemProvider)provider).getFileTypeDetector(); - //} else if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - // return new RegistryFileTypeDetector(); - //} else { - // return new AbstractFileTypeDetector() { - // public String implProbeContentType(Path obj) throws IOException { - // return null; - // } - // }; - //} - } - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/DotNetBasicFileAttributeView.java b/src/IKVM.Java/local/sun/nio/fs/DotNetBasicFileAttributeView.java deleted file mode 100644 index 4002df5f67..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/DotNetBasicFileAttributeView.java +++ /dev/null @@ -1,29 +0,0 @@ -package sun.nio.fs; - -import java.io.*; -import java.nio.file.*; -import java.nio.file.attribute.*; - -class DotNetBasicFileAttributeView extends AbstractBasicFileAttributeView { - - static cli.System.DateTime toDateTime(FileTime fileTime) { - if (fileTime != null) { - return new cli.System.DateTime(fileTime.to(java.util.concurrent.TimeUnit.MICROSECONDS) * 10 + 621355968000000000L); - } else { - return cli.System.DateTime.MinValue; - } - } - - protected final String path; - - DotNetBasicFileAttributeView(String path) { - this.path = path; - } - - public BasicFileAttributes readAttributes() throws IOException { - return DotNetDosFileAttributes.read(path); - } - - public native void setTimes(FileTime lastModifiedTime, FileTime lastAccessTime, FileTime createTime) throws IOException; - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/DotNetDirectoryStream.java b/src/IKVM.Java/local/sun/nio/fs/DotNetDirectoryStream.java deleted file mode 100644 index e1b07bae1b..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/DotNetDirectoryStream.java +++ /dev/null @@ -1,24 +0,0 @@ -package sun.nio.fs; - -import java.util.*; -import java.nio.file.*; - -final class DotNetDirectoryStream implements DirectoryStream { - - private final DotNetPath path; - private final cli.System.Collections.IEnumerable files; - private final DirectoryStream.Filter filter; - - DotNetDirectoryStream(final DotNetPath path, final cli.System.Collections.IEnumerable files, final DirectoryStream.Filter filter) { - this.path = path; - this.files = files; - this.filter = filter; - } - - @Override - public native Iterator iterator(); - - @Override - public native void close(); - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/DotNetDosFileAttributeView.java b/src/IKVM.Java/local/sun/nio/fs/DotNetDosFileAttributeView.java deleted file mode 100644 index 13040f5880..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/DotNetDosFileAttributeView.java +++ /dev/null @@ -1,96 +0,0 @@ -package sun.nio.fs; - -import java.io.*; -import java.nio.file.*; -import java.nio.file.attribute.*; -import java.util.*; - -import cli.System.IO.FileInfo; - -class DotNetDosFileAttributeView extends DotNetBasicFileAttributeView implements DosFileAttributeView { - - private static final String READONLY_NAME = "readonly"; - private static final String ARCHIVE_NAME = "archive"; - private static final String SYSTEM_NAME = "system"; - private static final String HIDDEN_NAME = "hidden"; - private static final Set dosAttributeNames = Util.newSet(basicAttributeNames, READONLY_NAME, ARCHIVE_NAME, SYSTEM_NAME, HIDDEN_NAME); - - DotNetDosFileAttributeView(String path) { - super(path); - } - - public String name() { - return "dos"; - } - - public DosFileAttributes readAttributes() throws IOException { - return DotNetDosFileAttributes.read(path); - } - - public void setArchive(boolean value) throws IOException { - setAttribute(cli.System.IO.FileAttributes.Archive, value); - } - - public void setHidden(boolean value) throws IOException { - setAttribute(cli.System.IO.FileAttributes.Hidden, value); - } - - public void setReadOnly(boolean value) throws IOException { - setAttribute(cli.System.IO.FileAttributes.ReadOnly, value); - } - - public void setSystem(boolean value) throws IOException { - setAttribute(cli.System.IO.FileAttributes.System, value); - } - - private void setAttribute(int attr, boolean value) throws IOException { - setAttribute0(path, attr, value); - } - - private static native void setAttribute0(String path, int attr, boolean value) throws IOException; - - public Map readAttributes(String[] attributes) throws IOException { - AttributesBuilder builder = AttributesBuilder.create(dosAttributeNames, attributes); - DotNetDosFileAttributes attrs = DotNetDosFileAttributes.read(path); - addRequestedBasicAttributes(attrs, builder); - - if (builder.match(READONLY_NAME)) { - builder.add(READONLY_NAME, attrs.isReadOnly()); - } - - if (builder.match(ARCHIVE_NAME)) { - builder.add(ARCHIVE_NAME, attrs.isArchive()); - } - - if (builder.match(SYSTEM_NAME)) { - builder.add(SYSTEM_NAME, attrs.isSystem()); - } - - if (builder.match(HIDDEN_NAME)) { - builder.add(HIDDEN_NAME, attrs.isHidden()); - } - - return builder.unmodifiableMap(); - } - - public void setAttribute(String attribute, Object value) throws IOException { - switch (attribute) { - case READONLY_NAME: - setReadOnly((Boolean)value); - break; - case ARCHIVE_NAME: - setArchive((Boolean)value); - break; - case SYSTEM_NAME: - setSystem((Boolean)value); - break; - case HIDDEN_NAME: - setHidden((Boolean)value); - break; - default: - super.setAttribute(attribute, value); - break; - } - } - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/DotNetDosFileAttributes.java b/src/IKVM.Java/local/sun/nio/fs/DotNetDosFileAttributes.java deleted file mode 100644 index bd9a97e8ca..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/DotNetDosFileAttributes.java +++ /dev/null @@ -1,94 +0,0 @@ -package sun.nio.fs; - -import java.io.*; -import java.nio.file.*; -import java.nio.file.attribute.*; -import java.util.*; - -class DotNetDosFileAttributes implements DosFileAttributes { - - public native static DotNetDosFileAttributes read(String path) throws IOException; - - private final FileTime creationTime; - private final FileTime lastAccessTime; - private final FileTime lastModifiedTime; - private Object fileKey; - private boolean isDirectory; - private boolean isOther; - private boolean isRegularFile; - private boolean isSymbolicLink; - private long size; - private boolean isReadOnly; - private boolean isHidden; - private boolean isArchive; - private boolean isSystem; - - public DotNetDosFileAttributes(FileTime creationTime, FileTime lastAccessTime, FileTime lastModifiedTime, Object fileKey, boolean isDirectory, boolean isOther, boolean isRegularFile, boolean isSymbolicLink, long size, boolean isReadOnly, boolean isHidden, boolean isArchive, boolean isSystem) { - this.creationTime = creationTime; - this.lastAccessTime = lastAccessTime; - this.lastModifiedTime = lastModifiedTime; - this.fileKey = fileKey; - this.isDirectory = isDirectory; - this.isOther = isOther; - this.isRegularFile = isRegularFile; - this.isSymbolicLink = isSymbolicLink; - this.size = size; - this.isReadOnly = isReadOnly; - this.isHidden = isHidden; - this.isArchive = isArchive; - this.isSystem = isSystem; - } - - public FileTime creationTime() { - return creationTime; - } - - public FileTime lastAccessTime() { - return lastAccessTime; - } - - public FileTime lastModifiedTime() { - return lastModifiedTime; - } - - public Object fileKey() { - return fileKey; - } - - public boolean isDirectory() { - return isDirectory; - } - - public boolean isOther() { - return isOther; - } - - public boolean isRegularFile() { - return isRegularFile; - } - - public boolean isSymbolicLink() { - return isSymbolicLink; - } - - public long size() { - return size; - } - - public boolean isReadOnly() { - return isReadOnly; - } - - public boolean isHidden() { - return isHidden; - } - - public boolean isArchive() { - return isArchive; - } - - public boolean isSystem() { - return isSystem; - } - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/DotNetFileSystem.java b/src/IKVM.Java/local/sun/nio/fs/DotNetFileSystem.java deleted file mode 100644 index 250d354979..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/DotNetFileSystem.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - Copyright (C) 2011 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -package sun.nio.fs; - -import cli.System.IO.DriveInfo; -import cli.System.IO.ErrorEventArgs; -import cli.System.IO.ErrorEventHandler; -import cli.System.IO.FileSystemEventArgs; -import cli.System.IO.FileSystemEventHandler; -import cli.System.IO.FileSystemWatcher; -import cli.System.IO.WatcherChangeTypes; - -import java.io.IOException; -import java.nio.file.*; -import java.nio.file.attribute.*; -import java.nio.file.spi.FileSystemProvider; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; - -final class DotNetFileSystem extends FileSystem { - - private static final Set attributes = Collections.unmodifiableSet(new HashSet(Arrays.asList("basic"))); - private final DotNetFileSystemProvider provider; - private final String separator = Character.toString(cli.System.IO.Path.DirectorySeparatorChar); - - DotNetFileSystem(DotNetFileSystemProvider provider) { - this.provider = provider; - } - - public FileSystemProvider provider() { - return provider; - } - - public void close() throws IOException { - throw new UnsupportedOperationException(); - } - - public boolean isOpen() { - return true; - } - - public boolean isReadOnly() { - return false; - } - - public String getSeparator() { - return separator; - } - - public Iterable getRootDirectories() { - SecurityManager sm = System.getSecurityManager(); - ArrayList list = new ArrayList<>(); - for (DriveInfo info : DriveInfo.GetDrives()) { - try { - if (sm != null) { - sm.checkRead(info.get_Name()); - } - } catch (SecurityException _) { - continue; - } - - list.add(getPath(info.get_Name())); - } - - return list; - } - - public Iterable getFileStores() { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - try { - sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); - } catch (SecurityException _) { - return Collections.emptyList(); - } - } - - ArrayList list = new ArrayList<>(); - for (DriveInfo info : DriveInfo.GetDrives()) { - try { - if (sm != null) { - sm.checkRead(info.get_Name()); - } - } catch (SecurityException _) { - continue; - } - try { - list.add(provider.getFileStore(info)); - } catch (IOException _) { - - } - } - - return list; - } - - public Set supportedFileAttributeViews() { - return attributes; - } - - public Path getPath(String first, String... more) { - if (more.length == 0) { - return new DotNetPath(this, first); - } else { - StringBuilder sb = new StringBuilder(first); - String sep = sb.length() == 0 ? "" : separator; - for (String s : more) { - if (s.length() != 0) { - sb.append(sep); - sb.append(s); - sep = separator; - } - } - - return new DotNetPath(this, sb.toString()); - } - } - - public PathMatcher getPathMatcher(String syntaxAndPattern) { - String regex; - if (syntaxAndPattern.startsWith("glob:")) { - String pattern = syntaxAndPattern.substring(5); - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - regex = Globs.toWindowsRegexPattern(pattern); - } else { - regex = Globs.toUnixRegexPattern(pattern); - } - } else if (syntaxAndPattern.startsWith("regex:")) { - regex = syntaxAndPattern.substring(6); - } else if (syntaxAndPattern.indexOf(':') <= 0) { - throw new IllegalArgumentException(); - } else { - throw new UnsupportedOperationException(); - } - - final Pattern pattern = Pattern.compile(regex, cli.IKVM.Runtime.RuntimeUtil.get_IsWindows() ? Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE : 0); - return new PathMatcher() { - @Override - public boolean matches(Path path) { - return pattern.matcher(path.toString()).matches(); - } - }; - } - - public UserPrincipalLookupService getUserPrincipalLookupService() { - throw new UnsupportedOperationException(); - } - - static final class NetWatchService implements WatchService { - - static final WatchEvent overflowEvent = new WatchEvent() { - public Object context() { - return null; - } - public int count() { - return 1; - } - public WatchEvent.Kind kind() { - return StandardWatchEventKinds.OVERFLOW; - } - }; - - private static final WatchKey CLOSED = new WatchKey() { - public boolean isValid() { return false; } - public List> pollEvents() { return null; } - public boolean reset() { return false; } - public void cancel() { } - public Watchable watchable() { return null; } - }; - - private boolean closed; - private final ArrayList keys = new ArrayList<>(); - private final LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); - - public synchronized void close() { - if (!closed) { - closed = true; - for (NetWatchKey key : keys) { - key.close(); - } - enqueue(CLOSED); - } - } - - private WatchKey checkClosed(WatchKey key) { - if (key == CLOSED) { - enqueue(CLOSED); - throw new ClosedWatchServiceException(); - } - - return key; - } - - public WatchKey poll() { - return checkClosed(queue.poll()); - } - - public WatchKey poll(long timeout, TimeUnit unit) throws InterruptedException { - return checkClosed(queue.poll(timeout, unit)); - } - - public WatchKey take() throws InterruptedException { - return checkClosed(queue.take()); - } - - void enqueue(WatchKey key) { - for (;;) { - try { - queue.put(key); - return; - } catch (InterruptedException _) { - - } - } - } - - private final class NetWatchKey implements WatchKey { - - private final DotNetPath path; - private FileSystemWatcher fsw; - private ArrayList> list = new ArrayList<>(); - private HashSet modified = new HashSet<>(); - private boolean signaled; - - NetWatchKey(DotNetPath path) { - this.path = path; - } - - synchronized void init(final boolean create, final boolean delete, final boolean modify, final boolean overflow, final boolean subtree) throws IOException { - try { - if (fsw != null) { - // we could reuse the FileSystemWatcher, but for now we just recreate it - // (and we run the risk of missing some events while we're doing that) - fsw.Dispose(); - fsw = null; - } - - fsw = new FileSystemWatcher(path.path); - if (create) { - fsw.add_Created(new FileSystemEventHandler(new FileSystemEventHandler.Method() { - public void Invoke(Object sender, FileSystemEventArgs e) { - addEvent(createEvent(e), null); - } - })); - } - - if (delete) { - fsw.add_Deleted(new FileSystemEventHandler(new FileSystemEventHandler.Method() { - public void Invoke(Object sender, FileSystemEventArgs e) { - addEvent(createEvent(e), null); - } - })); - } - - if (modify) { - fsw.add_Changed(new FileSystemEventHandler(new FileSystemEventHandler.Method() { - public void Invoke(Object sender, FileSystemEventArgs e) { - synchronized (NetWatchKey.this) { - if (modified.contains(e.get_Name())) { - // we already have an ENTRY_MODIFY event pending - return; - } - } - addEvent(createEvent(e), e.get_Name()); - } - })); - } - - fsw.add_Error(new ErrorEventHandler(new ErrorEventHandler.Method() { - public void Invoke(Object sender, ErrorEventArgs e) { - if (e.GetException() instanceof cli.System.ComponentModel.Win32Exception && ((cli.System.ComponentModel.Win32Exception)e.GetException()).get_ErrorCode() == -2147467259) { - // the directory we were watching was deleted - cancelledByError(); - } else if (overflow) { - addEvent(overflowEvent, null); - } - } - })); - - if (subtree) { - fsw.set_IncludeSubdirectories(true); - } - - fsw.set_EnableRaisingEvents(true); - } catch (Throwable t) { - if (t instanceof cli.System.IO.FileNotFoundException) { - throw new java.nio.file.NoSuchFileException(((cli.System.IO.FileNotFoundException)t).get_FileName()); - } else if (t instanceof cli.System.Exception) { - throw new IOException(((cli.System.Exception)t).get_Message(), t); - } else { - throw new IOException(t); - } - } - } - - WatchEvent createEvent(final FileSystemEventArgs e) { - return new WatchEvent() { - - public Path context() { - return new DotNetPath((DotNetFileSystem)path.getFileSystem(), e.get_Name()); - } - - public int count() { - return 1; - } - - public WatchEvent.Kind kind() { - switch (e.get_ChangeType().Value) { - case WatcherChangeTypes.Created: - return StandardWatchEventKinds.ENTRY_CREATE; - case WatcherChangeTypes.Deleted: - return StandardWatchEventKinds.ENTRY_DELETE; - default: - return StandardWatchEventKinds.ENTRY_MODIFY; - } - } - - }; - } - - void cancelledByError() { - cancel(); - synchronized (this) { - if (!signaled) { - signaled = true; - enqueue(this); - } - } - } - - synchronized void addEvent(WatchEvent event, String modified) { - list.add(event); - if (modified != null) { - this.modified.add(modified); - } - if (!signaled) { - signaled = true; - enqueue(this); - } - } - - public synchronized boolean isValid() { - return fsw != null; - } - - public synchronized List> pollEvents() { - ArrayList> r = list; - list = new ArrayList<>(); - modified.clear(); - return r; - } - - public synchronized boolean reset() { - if (fsw == null) { - return false; - } - - if (signaled) { - if (list.size() == 0) { - signaled = false; - } else { - enqueue(this); - } - } - - return true; - } - - void close() { - if (fsw != null) { - fsw.Dispose(); - fsw = null; - } - } - - public void cancel() { - synchronized (NetWatchService.this) { - keys.remove(this); - close(); - } - } - - public Watchable watchable() { - return path; - } - - } - - synchronized WatchKey register(DotNetPath path, boolean create, boolean delete, boolean modify, boolean overflow, boolean subtree) throws IOException { - if (closed) { - throw new ClosedWatchServiceException(); - } - - NetWatchKey existing = null; - for (NetWatchKey key : keys) { - if (key.watchable().equals(path)) { - existing = key; - break; - } - } - - if (existing == null) { - existing = new NetWatchKey(path); - keys.add(existing); - } - - existing.init(create, delete, modify, overflow, subtree); - return existing; - } - - } - - public WatchService newWatchService() throws IOException { - return new NetWatchService(); - } - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/DotNetFileSystemProvider.java b/src/IKVM.Java/local/sun/nio/fs/DotNetFileSystemProvider.java deleted file mode 100644 index 8af0b6c93f..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/DotNetFileSystemProvider.java +++ /dev/null @@ -1,824 +0,0 @@ -/* - Copyright (C) 2011 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -package sun.nio.fs; - -import ikvm.internal.NotYetImplementedError; -import ikvm.internal.io.FileStreamExtensions; - -import cli.System.IO.Directory; -import cli.System.IO.DirectoryInfo; -import cli.System.IO.DriveInfo; -import cli.System.IO.File; -import cli.System.IO.FileAttributes; -import cli.System.IO.FileInfo; -import cli.System.IO.FileMode; -import cli.System.IO.FileShare; -import cli.System.IO.FileOptions; -import cli.System.Runtime.InteropServices.DllImportAttribute; -import cli.System.Runtime.InteropServices.Marshal; -import cli.System.Security.AccessControl.FileSystemRights; - -import com.sun.nio.file.ExtendedOpenOption; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.net.URI; -import java.nio.channels.*; -import java.nio.file.*; -import java.nio.file.attribute.*; -import java.nio.file.spi.FileSystemProvider; -import java.util.concurrent.ExecutorService; -import java.util.Iterator; -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import sun.nio.ch.DotNetAsynchronousFileChannelImpl; -import sun.nio.ch.FileChannelImpl; -import sun.nio.ch.ThreadPool; - -final class DotNetFileSystemProvider extends AbstractFileSystemProvider { - - static { - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - System.loadLibrary("nio"); - return null; - }}); - } - - private final DotNetFileSystem fs = new DotNetFileSystem(this); - private final HashMap stores = new HashMap(); - - final synchronized FileStore getFileStore(DriveInfo drive) throws IOException { - String name = drive.get_Name().toLowerCase(); - FileStore fs = stores.get(name); - if (fs == null) { - fs = new DotNetFileStore(drive); - stores.put(name, fs); - } - - return fs; - } - - public String getScheme() { - return "file"; - } - - public FileSystem newFileSystem(URI uri, Map env) throws IOException { - throw new FileSystemAlreadyExistsException(); - } - - public FileSystem getFileSystem(URI uri) { - return fs; - } - - public Path getPath(URI uri) { - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - return DotNetWindowsUriSupport.fromUri(fs, uri); - } else { - return DotNetUnixUriUtils.fromUri(fs, uri); - } - } - - public AsynchronousFileChannel newAsynchronousFileChannel(Path path, Set opts, ExecutorService executor, FileAttribute... attrs) throws IOException { - DotNetPath npath = DotNetPath.from(path); - - for (FileAttribute attr : attrs) { - // null check - attr.getClass(); - throw new NotYetImplementedError(); - } - - int mode = FileMode.Open; - int share = FileShare.ReadWrite | FileShare.Delete; - int options = FileOptions.Asynchronous; - - boolean read = false; - boolean write = false; - boolean truncate = false; - - for (OpenOption opt : opts) { - if (opt instanceof StandardOpenOption) { - switch ((StandardOpenOption)opt) { - case CREATE: - mode = FileMode.Create; - break; - case CREATE_NEW: - mode = FileMode.CreateNew; - break; - case DELETE_ON_CLOSE: - options |= FileOptions.DeleteOnClose; - break; - case DSYNC: - options |= FileOptions.WriteThrough; - break; - case READ: - read = true; - break; - case SPARSE: - break; - case SYNC: - options |= FileOptions.WriteThrough; - break; - case TRUNCATE_EXISTING: - truncate = true; - break; - case WRITE: - write = true; - break; - default: - throw new UnsupportedOperationException(); - } - } else if (opt instanceof ExtendedOpenOption) { - switch ((ExtendedOpenOption)opt) { - case NOSHARE_READ: - share &= ~FileShare.Read; - break; - case NOSHARE_WRITE: - share &= ~FileShare.Write; - break; - case NOSHARE_DELETE: - share &= ~FileShare.Delete; - break; - default: - throw new UnsupportedOperationException(); - } - } else { - // null check - opt.getClass(); - throw new UnsupportedOperationException(); - } - } - - if (!read && !write) { - read = true; - } - - if (truncate) { - if (mode == FileMode.Open) { - mode = FileMode.Truncate; - } - } - - int rights = 0; - if (read) { - rights |= FileSystemRights.Read; - } - if (write) { - rights |= FileSystemRights.Write; - } - - ThreadPool pool; - if (executor == null) { - pool = null; - } else { - pool = ThreadPool.wrap(executor, 0); - } - - return DotNetAsynchronousFileChannelImpl.open(open(npath.path, mode, rights, share, options), read, write, pool); - } - - public SeekableByteChannel newByteChannel(Path path, Set opts, FileAttribute... attrs) throws IOException { - return newFileChannel(path, opts, attrs); - } - - public FileChannel newFileChannel(Path path, Set opts, FileAttribute... attrs) throws IOException { - DotNetPath npath = DotNetPath.from(path); - - for (FileAttribute attr : attrs) { - // null check - attr.getClass(); - throw new NotYetImplementedError(); - } - - int mode = FileMode.Open; - int share = FileShare.ReadWrite | FileShare.Delete; - int options = FileOptions.None; - - boolean read = false; - boolean write = false; - boolean append = false; - boolean truncate = false; - - for (OpenOption opt : opts) { - if (opt instanceof StandardOpenOption) { - switch ((StandardOpenOption)opt) { - case APPEND: - append = true; - write = true; - mode = FileMode.Append; - break; - case CREATE: - mode = FileMode.Create; - break; - case CREATE_NEW: - mode = FileMode.CreateNew; - break; - case DELETE_ON_CLOSE: - options |= FileOptions.DeleteOnClose; - break; - case DSYNC: - options |= FileOptions.WriteThrough; - break; - case READ: - read = true; - break; - case SPARSE: - break; - case SYNC: - options |= FileOptions.WriteThrough; - break; - case TRUNCATE_EXISTING: - truncate = true; - break; - case WRITE: - write = true; - break; - default: - throw new UnsupportedOperationException(); - } - } else if (opt instanceof ExtendedOpenOption) { - switch ((ExtendedOpenOption)opt) { - case NOSHARE_READ: - share &= ~FileShare.Read; - break; - case NOSHARE_WRITE: - share &= ~FileShare.Write; - break; - case NOSHARE_DELETE: - share &= ~FileShare.Delete; - break; - default: - throw new UnsupportedOperationException(); - } - } else { - // null check - opt.getClass(); - throw new UnsupportedOperationException(); - } - } - - if (!read && !write) { - read = true; - } - - if (read && append) { - throw new IllegalArgumentException("READ + APPEND not allowed"); - } - - if (truncate) { - if (append) { - throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed"); - } - if (mode == FileMode.Open) { - mode = FileMode.Truncate; - } - } - - int rights = 0; - if (append) { - // for atomic append to work, we can't set FileSystemRights.Write - rights |= FileSystemRights.AppendData; - } else { - if (read) { - rights |= FileSystemRights.Read; - } - if (write) { - rights |= FileSystemRights.Write; - } - } - - return FileChannelImpl.open(open(npath.path, mode, rights, share, options), npath.path, read, write, append, null); - } - - private static FileDescriptor open(String path, int mode, int rights, int share, int options) throws IOException { - return open0(path, FileMode.wrap(mode), FileSystemRights.wrap(rights), FileShare.wrap(share), 1, FileOptions.wrap(options), System.getSecurityManager()); - } - - public native DirectoryStream newDirectoryStream(Path dir, final DirectoryStream.Filter filter) throws IOException; - - public void createDirectory(Path dir, FileAttribute... attrs) throws IOException { - DotNetPath ndir = DotNetPath.from(dir); - - for (FileAttribute attr : attrs) { - // null check - attr.getClass(); - throw new NotYetImplementedError(); - } - - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkWrite(ndir.path); - } - - try { - if (false) throw new cli.System.ArgumentException(); - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.Security.SecurityException(); - if (false) throw new cli.System.UnauthorizedAccessException(); - Directory.CreateDirectory(ndir.path); - } catch (cli.System.ArgumentException | cli.System.IO.IOException | cli.System.Security.SecurityException | cli.System.UnauthorizedAccessException x) { - if (File.Exists(ndir.path)) { - throw new FileAlreadyExistsException(ndir.path); - } - - throw new IOException(x.getMessage()); - } - } - - public void copy(Path source, Path target, CopyOption... options) throws IOException { - DotNetPath nsource = DotNetPath.from(source); - DotNetPath ntarget = DotNetPath.from(target); - - boolean overwrite = false; - boolean copyAttribs = false; - - for (CopyOption opt : options) { - if (opt == StandardCopyOption.REPLACE_EXISTING) { - overwrite = true; - } else if (opt == StandardCopyOption.COPY_ATTRIBUTES) { - copyAttribs = true; - } else { - // null check - opt.getClass(); - throw new UnsupportedOperationException("Unsupported copy option"); - } - } - - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkRead(nsource.path); - sm.checkWrite(ntarget.path); - } - - try { - if (false) throw new cli.System.ArgumentException(); - if (false) throw new cli.System.IO.FileNotFoundException(); - if (false) throw new cli.System.IO.DirectoryNotFoundException(); - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.Security.SecurityException(); - if (false) throw new cli.System.UnauthorizedAccessException(); - - if (File.Exists(ntarget.path)) { - if (!overwrite) { - throw new FileAlreadyExistsException(ntarget.path); - } - - File.Delete(ntarget.path); - } - - if (Directory.Exists(ntarget.path)) { - if (!overwrite) { - throw new FileAlreadyExistsException(ntarget.path); - } - - try { - if (false) throw new cli.System.IO.IOException(); - Directory.Delete(ntarget.path); - } catch (cli.System.IO.IOException _) { - // HACK we assume that the IOException is caused by the directory not being empty - throw new DirectoryNotEmptyException(ntarget.path); - } - } - - if (Directory.Exists(nsource.path)) { - Directory.CreateDirectory(ntarget.path); - } else { - File.Copy(nsource.path, ntarget.path, overwrite); - } - - if (copyAttribs) { - if (Directory.Exists(ntarget.path)) { - File.SetAttributes(ntarget.path, File.GetAttributes(nsource.path)); - Directory.SetCreationTimeUtc(ntarget.path, File.GetCreationTimeUtc(nsource.path)); - Directory.SetLastAccessTimeUtc(ntarget.path, File.GetLastAccessTimeUtc(nsource.path)); - Directory.SetLastWriteTimeUtc(ntarget.path, File.GetLastWriteTimeUtc(nsource.path)); - } else { - File.SetAttributes(ntarget.path, File.GetAttributes(nsource.path)); - File.SetCreationTimeUtc(ntarget.path, File.GetCreationTimeUtc(nsource.path)); - File.SetLastAccessTimeUtc(ntarget.path, File.GetLastAccessTimeUtc(nsource.path)); - File.SetLastWriteTimeUtc(ntarget.path, File.GetLastWriteTimeUtc(nsource.path)); - } - } - } catch (cli.System.IO.FileNotFoundException x) { - throw new NoSuchFileException(x.get_FileName()); - } catch (cli.System.IO.DirectoryNotFoundException x) { - throw new NoSuchFileException(nsource.path, ntarget.path, x.getMessage()); - } catch (cli.System.IO.IOException | cli.System.ArgumentException x) { - throw new FileSystemException(nsource.path, ntarget.path, x.getMessage()); - } catch (cli.System.Security.SecurityException | cli.System.UnauthorizedAccessException x) { - throw new AccessDeniedException(nsource.path, ntarget.path, x.getMessage()); - } - } - - @cli.System.Security.SecuritySafeCriticalAttribute.Annotation - public void move(Path source, Path target, CopyOption... options) throws IOException { - DotNetPath nsource = DotNetPath.from(source); - DotNetPath ntarget = DotNetPath.from(target); - boolean overwrite = false; - boolean atomicMove = false; - - for (CopyOption opt : options) { - if (opt == StandardCopyOption.REPLACE_EXISTING) { - overwrite = true; - } else if (opt == StandardCopyOption.ATOMIC_MOVE) { - atomicMove = true; - } else { - // null check - opt.getClass(); - throw new UnsupportedOperationException("Unsupported copy option"); - } - } - - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkRead(nsource.path); - sm.checkWrite(ntarget.path); - } - - if (atomicMove) { - rename0(nsource.path, ntarget.path); - return; - } - - try { - if (false) throw new cli.System.ArgumentException(); - if (false) throw new cli.System.IO.FileNotFoundException(); - if (false) throw new cli.System.IO.DirectoryNotFoundException(); - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.Security.SecurityException(); - if (false) throw new cli.System.UnauthorizedAccessException(); - - if (File.Exists(ntarget.path)) { - if (!overwrite) { - throw new FileAlreadyExistsException(ntarget.path); - } - File.Delete(ntarget.path); - } - - if (Directory.Exists(ntarget.path)) { - if (!overwrite) { - throw new FileAlreadyExistsException(ntarget.path); - } - - try { - if (false) throw new cli.System.IO.IOException(); - Directory.Delete(ntarget.path); - } catch (cli.System.IO.IOException _) { - // HACK we assume that the IOException is caused by the directory not being empty - throw new DirectoryNotEmptyException(ntarget.path); - } - } - - if (Directory.Exists(nsource.path)) { - Directory.Move(nsource.path, ntarget.path); - } else { - File.Move(nsource.path, ntarget.path); - } - } catch (cli.System.IO.FileNotFoundException x) { - throw new NoSuchFileException(x.get_FileName()); - } catch (cli.System.IO.DirectoryNotFoundException x) { - throw new NoSuchFileException(nsource.path, ntarget.path, x.getMessage()); - } catch (cli.System.IO.IOException | cli.System.ArgumentException x) { - throw new FileSystemException(nsource.path, ntarget.path, x.getMessage()); - } catch (cli.System.Security.SecurityException | cli.System.UnauthorizedAccessException x) { - throw new AccessDeniedException(nsource.path, ntarget.path, x.getMessage()); - } - } - - private static native void rename0(String source, String target) throws IOException; - - public boolean isSameFile(Path path, Path path2) throws IOException { - if (path.equals(path2)) { - return true; - } - - if (!(path instanceof DotNetPath && path2 instanceof DotNetPath)) { - // null check - path2.getClass(); - return false; - } - - return path.toRealPath().equals(path2.toRealPath()); - } - - public boolean isHidden(Path path) throws IOException { - String npath = DotNetPath.from(path).path; - - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkRead(npath); - } - - try { - if (false) throw new cli.System.ArgumentException(); - if (false) throw new cli.System.IO.FileNotFoundException(); - if (false) throw new cli.System.IO.IOException(); - return (File.GetAttributes(npath).Value & (cli.System.IO.FileAttributes.Hidden | cli.System.IO.FileAttributes.Directory)) == cli.System.IO.FileAttributes.Hidden; - } catch (cli.System.IO.FileNotFoundException x) { - throw new NoSuchFileException(npath); - } catch (cli.System.IO.IOException | cli.System.ArgumentException x) { - throw new IOException(x.getMessage()); - } - } - - private static class DotNetFileStore extends FileStore { - - private final DriveInfo info; - private final String name; - private final String type; - - DotNetFileStore(DriveInfo info) throws IOException { - this.info = info; - try { - if (false) throw new cli.System.IO.IOException(); - name = info.get_VolumeLabel(); - type = info.get_DriveFormat(); - } catch (cli.System.IO.IOException x) { - throw new IOException(x.getMessage()); - } - } - - public Object getAttribute(String attribute) throws IOException { - switch (attribute) { - case "totalSpace": - return getTotalSpace(); - case "unallocatedSpace": - return getUnallocatedSpace(); - case "usableSpace": - return getUsableSpace(); - default: - throw new UnsupportedOperationException(); - } - } - - public V getFileStoreAttributeView(Class type) { - return null; - } - - public long getTotalSpace() throws IOException { - try { - if (false) throw new cli.System.IO.IOException(); - return info.get_TotalSize(); - } catch (cli.System.IO.IOException x) { - throw new IOException(x.getMessage()); - } - } - - public long getUnallocatedSpace() throws IOException { - try { - if (false) throw new cli.System.IO.IOException(); - return info.get_TotalFreeSpace(); - } catch (cli.System.IO.IOException x) { - throw new IOException(x.getMessage()); - } - } - - public long getUsableSpace() throws IOException { - try { - if (false) throw new cli.System.IO.IOException(); - return info.get_AvailableFreeSpace(); - } catch (cli.System.IO.IOException x) { - throw new IOException(x.getMessage()); - } - } - - public boolean isReadOnly() { - return false; - } - - public String name() { - return name; - } - - public boolean supportsFileAttributeView(Class type) { - // null check - type.getClass(); - return type == BasicFileAttributeView.class || type == DosFileAttributeView.class; - } - - public boolean supportsFileAttributeView(String name) { - return name.equals("basic") || name.equals("dos"); - } - - public String type() { - return type; - } - - public String toString() { - return name + " (" + info.get_Name().charAt(0) + ":)"; - } - - } - - public FileStore getFileStore(Path path) throws IOException { - DotNetPath npath = DotNetPath.from(path.toAbsolutePath()); - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkRead(npath.path); - } - - return getFileStore(new DriveInfo(npath.path)); - } - - public void checkAccess(Path path, AccessMode... modes) throws IOException { - String npath = DotNetPath.from(path).path; - - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - if (modes.length == 0) { - sm.checkRead(npath); - } - - for (AccessMode m : modes) { - switch (m) { - case READ: - sm.checkRead(npath); - break; - case WRITE: - sm.checkWrite(npath); - break; - case EXECUTE: - sm.checkExec(npath); - break; - default: - throw new UnsupportedOperationException(); - } - } - } - - try { - if (false) throw new cli.System.ArgumentException(); - if (false) throw new cli.System.IO.DirectoryNotFoundException(); - if (false) throw new cli.System.IO.FileNotFoundException(); - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.NotSupportedException(); - if (false) throw new cli.System.Security.SecurityException(); - if (false) throw new cli.System.UnauthorizedAccessException(); - // note that File.GetAttributes() works for directories as well - int attr = File.GetAttributes(npath).Value; - for (AccessMode m : modes) { - switch (m) { - case READ: - case EXECUTE: - break; - case WRITE: - if ((attr & (cli.System.IO.FileAttributes.ReadOnly | cli.System.IO.FileAttributes.Directory)) == cli.System.IO.FileAttributes.ReadOnly) { - throw new AccessDeniedException(npath, null, "file has read-only attribute set"); - } - if (getFileStore(path).isReadOnly()) { - throw new AccessDeniedException(npath, null, "volume is read-only"); - } - break; - default: - throw new UnsupportedOperationException(); - } - } - } catch (cli.System.IO.FileNotFoundException | cli.System.IO.DirectoryNotFoundException _) { - throw new NoSuchFileException(npath); - } catch (cli.System.Security.SecurityException | cli.System.UnauthorizedAccessException x) { - throw new AccessDeniedException(npath, null, x.getMessage()); - } catch (cli.System.ArgumentException | cli.System.IO.IOException | cli.System.NotSupportedException x) { - throw new IOException(x.getMessage()); - } - } - - - private static void validateLinkOption(LinkOption... options) { - for (LinkOption option : options) { - if (option == LinkOption.NOFOLLOW_LINKS) { - // ignored - } else { - // null check - option.getClass(); - throw new UnsupportedOperationException(); - } - } - } - - public V getFileAttributeView(Path path, Class type, LinkOption... options) { - String npath = DotNetPath.from(path).path; - validateLinkOption(options); - if (type == BasicFileAttributeView.class) { - return (V)new DotNetBasicFileAttributeView(npath); - } else if (type == DosFileAttributeView.class) { - return (V)new DotNetDosFileAttributeView(npath); - } else { - // null check - type.getClass(); - return null; - } - } - - public A readAttributes(Path path, Class type, LinkOption... options) throws IOException { - String npath = DotNetPath.from(path).path; - // null check - type.getClass(); - validateLinkOption(options); - if (type != BasicFileAttributes.class && type != DosFileAttributes.class) { - throw new UnsupportedOperationException(); - } - - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkRead(npath); - } - - return (A)DotNetDosFileAttributes.read(npath); - } - - DynamicFileAttributeView getFileAttributeView(Path file, String name, LinkOption... options) { - validateLinkOption(options); - if (name.equals("basic")) { - return new DotNetBasicFileAttributeView(DotNetPath.from(file).path); - } else if (name.equals("dos")) { - return new DotNetDosFileAttributeView(DotNetPath.from(file).path); - } else { - return null; - } - } - - boolean implDelete(Path file, boolean failIfNotExists) throws IOException { - String path = DotNetPath.from(file).path; - - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkDelete(path); - } - - try - { - if (false) throw new cli.System.ArgumentException(); - if (false) throw new cli.System.IO.FileNotFoundException(); - if (false) throw new cli.System.IO.DirectoryNotFoundException(); - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.Security.SecurityException(); - if (false) throw new cli.System.UnauthorizedAccessException(); - - int attr = cli.System.IO.File.GetAttributes(path).Value; - if ((attr & cli.System.IO.FileAttributes.Directory) != 0) { - try { - if (false) throw new cli.System.IO.IOException(); - cli.System.IO.Directory.Delete(path); - } catch (cli.System.IO.IOException _) { - // HACK we assume that the IOException is caused by the directory not being empty - throw new DirectoryNotEmptyException(path); - } - - return true; - } else { - cli.System.IO.File.Delete(path); - return true; - } - } catch (cli.System.ArgumentException x) { - throw new FileSystemException(path, null, x.getMessage()); - } catch (cli.System.IO.FileNotFoundException _) { - if (failIfNotExists) { - throw new NoSuchFileException(path); - } else { - return false; - } - } catch (cli.System.IO.DirectoryNotFoundException _) { - if (failIfNotExists) { - throw new NoSuchFileException(path); - } else { - return false; - } - } catch (cli.System.IO.IOException x) { - throw new FileSystemException(path, null, x.getMessage()); - } catch (cli.System.Security.SecurityException _) { - throw new AccessDeniedException(path); - } catch (cli.System.UnauthorizedAccessException _) { - throw new AccessDeniedException(path); - } - } - - static native FileDescriptor open0(String path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options, SecurityManager sm) throws java.io.IOException; - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/DotNetPath.java b/src/IKVM.Java/local/sun/nio/fs/DotNetPath.java deleted file mode 100644 index 2766c08381..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/DotNetPath.java +++ /dev/null @@ -1,606 +0,0 @@ -/* - Copyright (C) 2011 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -package sun.nio.fs; - -import com.sun.nio.file.ExtendedWatchEventModifier; -import com.sun.nio.file.SensitivityWatchEventModifier; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.file.*; -import java.util.ArrayList; -import java.util.Iterator; - -final class DotNetPath extends AbstractPath { - - private static final char[] invalid = cli.System.IO.Path.GetInvalidFileNameChars(); - private final DotNetFileSystem fs; - final String path; - - DotNetPath(DotNetFileSystem fs, String path) { - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - path = WindowsPathParser.parse(path).path(); - } else { - StringBuilder sb = null; - int separatorCount = 0; - boolean prevWasSeparator = false; - for (int i = 0; i < path.length(); i++) - { - char c = path.charAt(i); - if (c == 0) - { - throw new InvalidPathException(path, "Nul character not allowed"); - } - else if (c == '/') - { - if (prevWasSeparator) - { - if (sb == null) - { - sb = new StringBuilder(); - sb.append(path, 0, i); - } - continue; - } - separatorCount++; - prevWasSeparator = true; - } - else - { - prevWasSeparator = false; - } - if (sb != null) - { - sb.append(c); - } - } - if (sb != null) - { - path = sb.toString(); - } - if (path.length() > 1 && path.charAt(path.length() - 1) == '/') - { - path = path.substring(0, path.length() - 1); - } - } - this.fs = fs; - this.path = path; - } - - public FileSystem getFileSystem() { - return fs; - } - - public boolean isAbsolute() { - return cli.System.IO.Path.IsPathRooted(path) && (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows() == false || path.startsWith("\\\\") || (path.length() >= 3 && path.charAt(1) == ':' && path.charAt(2) == '\\')); - } - - public Path getRoot() { - int len = getRootLength(); - return len == 0 ? null : new DotNetPath(fs, path.substring(0, len)); - } - - private int getRootLength() { - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - if (path.length() >= 2 && path.charAt(1) == ':') { - if (path.length() >= 3 && path.charAt(2) == '\\') { - return 3; - } else { - return 2; - } - } else if (path.startsWith("\\\\")) { - return path.indexOf('\\', path.indexOf('\\', 2) + 1) + 1; - } - } - - if (path.length() >= 1 && path.charAt(0) == cli.System.IO.Path.DirectorySeparatorChar) { - return 1; - } else { - return 0; - } - } - - public Path getFileName() { - if (path.length() == 0) { - return this; - } - if (path.length() == getRootLength()) { - return null; - } - String name = cli.System.IO.Path.GetFileName(path); - if (name == null || name.length() == 0) { - return null; - } - - return new DotNetPath(fs, name); - } - - public Path getParent() { - if (path.length() == getRootLength()) { - return null; - } - String parent = cli.System.IO.Path.GetDirectoryName(path); - if (parent == null || parent.length() == 0) { - return null; - } - - return new DotNetPath(fs, parent); - } - - public int getNameCount() { - int len = getRootLength(); - if (path.length() == len) { - return len == 0 ? 1 : 0; - } - int count = 1; - for (int i = len; i < path.length(); i++) { - if (path.charAt(i) == cli.System.IO.Path.DirectorySeparatorChar) { - count++; - } - } - - return count; - } - - public Path getName(int index) { - return new DotNetPath(fs, getNameImpl(index)); - } - - private String getNameImpl(int index) { - for (int pos = getRootLength(); pos < path.length(); index--) { - int next = path.indexOf(cli.System.IO.Path.DirectorySeparatorChar, pos); - if (index == 0) { - return next == -1 ? path.substring(pos) : path.substring(pos, next); - } - if (next == -1) { - break; - } - pos = next + 1; - } - - if (path.length() == 0 && index == 0) { - return ""; - } - - throw new IllegalArgumentException(); - } - - public Path subpath(int beginIndex, int endIndex) { - StringBuilder sb = new StringBuilder(); - for (int i = beginIndex; i < endIndex; i++) { - if (i != beginIndex) { - sb.append(cli.System.IO.Path.DirectorySeparatorChar); - } - sb.append(getNameImpl(i)); - } - - return new DotNetPath(fs, sb.toString()); - } - - public boolean startsWith(Path other) { - String npath = DotNetPath.from(other).path; - if (npath.length() == 0) { - return path.length() == 0; - } - - return path.regionMatches(cli.IKVM.Runtime.RuntimeUtil.get_IsWindows(), 0, npath, 0, npath.length()) - && (npath.length() == getRootLength() - || (npath.length() > getRootLength() - && (path.length() == npath.length() - || (path.length() > npath.length() && path.charAt(npath.length()) == cli.System.IO.Path.DirectorySeparatorChar)))); - } - - public boolean endsWith(Path other) { - DotNetPath nother = DotNetPath.from(other); - String npath = nother.path; - if (npath.length() > path.length()) { - return false; - } - if (npath.length() == 0) { - return path.length() == 0; - } - int nameCount = getNameCount(); - int otherNameCount = nother.getNameCount(); - if (otherNameCount > nameCount) { - return false; - } - int otherRootLength = nother.getRootLength(); - if (otherRootLength > 0) { - if (otherNameCount != nameCount - || getRootLength() != otherRootLength - || !path.regionMatches(cli.IKVM.Runtime.RuntimeUtil.get_IsWindows(), 0, npath, 0, otherRootLength)) - { - return false; - } - } - - int skip = nameCount - otherNameCount; - for (int i = 0; i < otherNameCount; i++) - { - String s1 = getNameImpl(i + skip); - String s2 = nother.getNameImpl(i); - if (s1.length() != s2.length() || !s1.regionMatches(cli.IKVM.Runtime.RuntimeUtil.get_IsWindows(), 0, s2, 0, s1.length())) - { - return false; - } - } - - return true; - } - - public Path normalize() - { - int rootLength = getRootLength(); - ArrayList list = new ArrayList<>(); - for (int i = 0, count = getNameCount(); i < count; i++) - { - String s = getNameImpl(i); - if (s.equals("..")) - { - if (list.size() == 0) - { - if (rootLength == 0 || (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows() && rootLength == 2)) - { - list.add(".."); - } - } - else if (list.get(list.size() - 1).equals("..")) - { - list.add(".."); - } - else - { - list.remove(list.size() - 1); - } - } - else if (!s.equals(".")) - { - list.add(s); - } - } - StringBuilder sb = new StringBuilder(); - sb.append(path.substring(0, getRootLength())); - for (int i = 0; i < list.size(); i++) - { - if (i != 0) - { - sb.append(cli.System.IO.Path.DirectorySeparatorChar); - } - sb.append(list.get(i)); - } - return new DotNetPath(fs, sb.toString()); - } - - public Path resolve(Path other) - { - DotNetPath nother = DotNetPath.from(other); - String npath = nother.path; - if (nother.isAbsolute()) - { - return other; - } - if (npath.length() == 0) - { - return this; - } - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) - { - if (nother.getRootLength() == 2 && getRootLength() == 3 && (path.charAt(0) | 0x20) == (npath.charAt(0) | 0x20)) - { - // we're in the case where we have a root "x:\" and other "x:", so we have to chop off "x:" from other because - // otherwise Path.Combine will just return other - npath = npath.substring(2); - } - else if (nother.getRootLength() == 1 && getRootLength() > 3) - { - // we're in the case where we have a root "\\host\share\" and other "\", - // we have to manually handle this because Path.Combine doesn't do the right thing - return new DotNetPath(fs, path.substring(0, getRootLength()) + npath); - } - } - return new DotNetPath(fs, cli.System.IO.Path.Combine(path, npath)); - } - - public Path relativize(Path other) - { - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - DotNetPath nother = DotNetPath.from(other); - if (equals(nother)) - { - return new DotNetPath(fs, ""); - } - int rootLength = getRootLength(); - if (nother.getRootLength() != rootLength || !path.regionMatches(true, 0, nother.path, 0, rootLength)) - { - throw new IllegalArgumentException("'other' has different root"); - } - int nameCount = getNameCount(); - int otherNameCount = nother.getNameCount(); - int count = Math.min(nameCount, otherNameCount); - int i = 0; - // skip the common parts - for (; i < count && getNameImpl(i).equals(nother.getNameImpl(i)); i++) - { - } - // remove the unused parts of our path - StringBuilder sb = new StringBuilder(); - for (int j = i; j < nameCount; j++) - { - sb.append("..\\"); - } - // append the new parts of other - for (int j = i; j < otherNameCount; j++) - { - if (j != i) - { - sb.append("\\"); - } - sb.append(nother.getNameImpl(j)); - } - return new DotNetPath(fs, sb.toString()); - } else { - DotNetPath nother = DotNetPath.from(other); - if (other.equals(this)) - return emptyPath(); - - // can only relativize paths of the same type - if (this.isAbsolute() != other.isAbsolute()) - throw new IllegalArgumentException("'other' is different type of Path"); - - // this path is the empty path - if (this.isEmpty()) - return nother; - - int bn = this.getNameCount(); - int cn = other.getNameCount(); - - // skip matching names - int n = (bn > cn) ? cn : bn; - int i = 0; - while (i < n) { - if (!this.getName(i).equals(nother.getName(i))) - break; - i++; - } - - int dotdots = bn - i; - if (i < cn) { - // remaining name components in other - DotNetPath remainder = DotNetPath.from(nother.subpath(i, cn)); - if (dotdots == 0) - return remainder; - - // other is the empty path - boolean isOtherEmpty = nother.isEmpty(); - - // result is a "../" for each remaining name in base - // followed by the remaining names in other. If the remainder is - // the empty path then we don't add the final trailing slash. - int len = dotdots*3 + remainder.path.length(); - if (isOtherEmpty) { - assert remainder.isEmpty(); - len--; - } - char[] result = new char[len]; - int pos = 0; - while (dotdots > 0) { - result[pos++] = '.'; - result[pos++] = '.'; - if (isOtherEmpty) { - if (dotdots > 1) result[pos++] = '/'; - } else { - result[pos++] = '/'; - } - dotdots--; - } - System.arraycopy(remainder.path.toCharArray(), 0, result, pos, remainder.path.length()); - return new DotNetPath(fs, new String(result)); - } else { - // no remaining names in other so result is simply a sequence of ".." - char[] result = new char[dotdots*3 - 1]; - int pos = 0; - while (dotdots > 0) { - result[pos++] = '.'; - result[pos++] = '.'; - // no tailing slash at the end - if (dotdots > 1) - result[pos++] = '/'; - dotdots--; - } - return new DotNetPath(fs, new String(result)); - } - } - } - - private boolean isEmpty() { - return path.length() == 0; - } - - private DotNetPath emptyPath() { - return new DotNetPath(fs, ""); - } - - public URI toUri() { - if (cli.IKVM.Runtime.RuntimeUtil.get_IsWindows()) { - return DotNetWindowsUriSupport.toUri(this); - } else { - return DotNetUnixUriUtils.toUri(this); - } - } - - public DotNetPath toAbsolutePath() { - if (isAbsolute()) { - return this; - } - - // System.getProperty("user.dir") will trigger the specified security check - return new DotNetPath(fs, cli.System.IO.Path.GetFullPath(cli.System.IO.Path.Combine(System.getProperty("user.dir"), path))); - } - - public Path toRealPath(LinkOption... options) throws IOException { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkRead(path); - if (!isAbsolute()) { - sm.checkPropertyAccess("user.dir"); - } - } - - return new DotNetPath(fs, toRealPathImpl(path)); - } - - private static native String toRealPathImpl(String path); - - public WatchKey register(WatchService watcher, WatchEvent.Kind[] events, WatchEvent.Modifier... modifiers) throws IOException { - if (watcher instanceof DotNetFileSystem.NetWatchService) { - boolean create = false; - boolean delete = false; - boolean modify = false; - boolean overflow = false; - boolean subtree = false; - - for (WatchEvent.Kind kind : events) { - if (kind == StandardWatchEventKinds.ENTRY_CREATE) { - create = true; - } else if (kind == StandardWatchEventKinds.ENTRY_DELETE) { - delete = true; - } else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) { - modify = true; - } else if (kind == StandardWatchEventKinds.OVERFLOW) { - overflow = true; - } else { - // null check - kind.getClass(); - throw new UnsupportedOperationException(); - } - } - - if (!create && !delete && !modify) { - throw new IllegalArgumentException(); - } - - for (WatchEvent.Modifier modifier : modifiers) { - if (modifier == ExtendedWatchEventModifier.FILE_TREE) { - subtree = true; - } else if (modifier instanceof SensitivityWatchEventModifier) { - // ignore - } else { - // null check - modifier.getClass(); - throw new UnsupportedOperationException(); - } - } - - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkRead(path); - if (subtree) { - sm.checkRead(path + cli.System.IO.Path.DirectorySeparatorChar + '-'); - } - } - - return ((DotNetFileSystem.NetWatchService)watcher).register(this, create, delete, modify, overflow, subtree); - } else if (watcher instanceof PollingWatchService) { - boolean subtree = false; - - for (WatchEvent.Modifier modifier : modifiers) { - if (modifier == ExtendedWatchEventModifier.FILE_TREE) { - subtree = true; - } else if (modifier instanceof SensitivityWatchEventModifier) { - // ignore - } else { - // null check - modifier.getClass(); - throw new UnsupportedOperationException(); - } - } - - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkRead(path); - if (subtree) { - sm.checkRead(path + cli.System.IO.Path.DirectorySeparatorChar + '-'); - } - } - - return ((PollingWatchService)watcher).register(this, events, modifiers); - } else { - watcher.getClass(); // null check - throw new ProviderMismatchException(); - } - } - - public int compareTo(Path other) { - String path2 = ((DotNetPath)other).path; - int len1 = path.length(); - int len2 = path2.length(); - int min = Math.min(len1, len2); - for (int i = 0; i < min; i++) { - char c1 = path.charAt(i); - char c2 = path2.charAt(i); - if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) { - return c1 - c2; - } - } - - return len1 - len2; - } - - public boolean equals(Object other) { - if (!(other instanceof DotNetPath)) { - return false; - } - - return compareTo((DotNetPath)other) == 0; - } - - public int hashCode() { - int hash = 0; - for (int i = 0; i < path.length(); i++) { - hash = 97 * hash + Character.toUpperCase(path.charAt(i)); - } - - return hash; - } - - public String toString() { - return path; - } - - boolean isUnc() { - return cli.IKVM.Runtime.RuntimeUtil.get_IsWindows() && getRootLength() > 3; - } - - static DotNetPath from(Path path) { - if (!(path instanceof DotNetPath)) { - // null check - path.getClass(); - throw new ProviderMismatchException(); - } - - return (DotNetPath)path; - } - -} \ No newline at end of file diff --git a/src/IKVM.Java/local/sun/nio/fs/DotNetUnixUriUtils.java b/src/IKVM.Java/local/sun/nio/fs/DotNetUnixUriUtils.java deleted file mode 100644 index e05a86d9e4..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/DotNetUnixUriUtils.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.nio.fs; - -import java.nio.file.Path; -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Arrays; - -/** - * Unix specific Path <--> URI conversion - */ - -class DotNetUnixUriUtils { - private DotNetUnixUriUtils() { } - - /** - * Converts URI to Path - */ - static Path fromUri(DotNetFileSystem fs, URI uri) { - if (!uri.isAbsolute()) - throw new IllegalArgumentException("URI is not absolute"); - if (uri.isOpaque()) - throw new IllegalArgumentException("URI is not hierarchical"); - String scheme = uri.getScheme(); - if ((scheme == null) || !scheme.equalsIgnoreCase("file")) - throw new IllegalArgumentException("URI scheme is not \"file\""); - if (uri.getAuthority() != null) - throw new IllegalArgumentException("URI has an authority component"); - if (uri.getFragment() != null) - throw new IllegalArgumentException("URI has a fragment component"); - if (uri.getQuery() != null) - throw new IllegalArgumentException("URI has a query component"); - - // compatibility with java.io.File - if (!uri.toString().startsWith("file:///")) - return new File(uri).toPath(); - - // transformation use raw path - String p = uri.getRawPath(); - int len = p.length(); - if (len == 0) - throw new IllegalArgumentException("URI path component is empty"); - - // transform escaped octets and unescaped characters to bytes - if (p.endsWith("/") && len > 1) - len--; - byte[] result = new byte[len]; - int rlen = 0; - int pos = 0; - while (pos < len) { - char c = p.charAt(pos++); - byte b; - if (c == '%') { - assert (pos+2) <= len; - char c1 = p.charAt(pos++); - char c2 = p.charAt(pos++); - b = (byte)((decode(c1) << 4) | decode(c2)); - if (b == 0) - throw new IllegalArgumentException("Nul character not allowed"); - } else { - if (c == 0 || c >= 0x80) - throw new IllegalArgumentException("Bad escape"); - b = (byte)c; - } - if (b == '/' && rlen > 0 && result[rlen-1] == '/') { - // skip redundant slashes - continue; - } - result[rlen++] = b; - } - if (rlen != result.length) - result = Arrays.copyOf(result, rlen); - - return new DotNetPath(fs, p); - } - - /** - * Converts Path to URI - */ - static URI toUri(DotNetPath up) { - byte[] path = up.toAbsolutePath().toString().getBytes(); - StringBuilder sb = new StringBuilder("file:///"); - assert path[0] == '/'; - for (int i=1; i> 4) & 0x0f]); - sb.append(hexDigits[(c) & 0x0f]); - } - } - - // trailing slash if directory - if (sb.charAt(sb.length()-1) != '/') { - try { - if (cli.System.IO.Directory.Exists(up.toString()) || isVfsDirectory(up.toString())) - sb.append('/'); - } catch (Throwable x) { - // ignore - } - } - - try { - return new URI(sb.toString()); - } catch (URISyntaxException x) { - throw new AssertionError(x); // should not happen - } - } - - // The following is copied from java.net.URI - - // Compute the low-order mask for the characters in the given string - private static long lowMask(String chars) { - int n = chars.length(); - long m = 0; - for (int i = 0; i < n; i++) { - char c = chars.charAt(i); - if (c < 64) - m |= (1L << c); - } - return m; - } - - // Compute the high-order mask for the characters in the given string - private static long highMask(String chars) { - int n = chars.length(); - long m = 0; - for (int i = 0; i < n; i++) { - char c = chars.charAt(i); - if ((c >= 64) && (c < 128)) - m |= (1L << (c - 64)); - } - return m; - } - - // Compute a low-order mask for the characters - // between first and last, inclusive - private static long lowMask(char first, char last) { - long m = 0; - int f = Math.max(Math.min(first, 63), 0); - int l = Math.max(Math.min(last, 63), 0); - for (int i = f; i <= l; i++) - m |= 1L << i; - return m; - } - - // Compute a high-order mask for the characters - // between first and last, inclusive - private static long highMask(char first, char last) { - long m = 0; - int f = Math.max(Math.min(first, 127), 64) - 64; - int l = Math.max(Math.min(last, 127), 64) - 64; - for (int i = f; i <= l; i++) - m |= 1L << i; - return m; - } - - // Tell whether the given character is permitted by the given mask pair - private static boolean match(char c, long lowMask, long highMask) { - if (c < 64) - return ((1L << c) & lowMask) != 0; - if (c < 128) - return ((1L << (c - 64)) & highMask) != 0; - return false; - } - - // decode - private static int decode(char c) { - if ((c >= '0') && (c <= '9')) - return c - '0'; - if ((c >= 'a') && (c <= 'f')) - return c - 'a' + 10; - if ((c >= 'A') && (c <= 'F')) - return c - 'A' + 10; - throw new AssertionError(); - } - - // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | - // "8" | "9" - private static final long L_DIGIT = lowMask('0', '9'); - private static final long H_DIGIT = 0L; - - // upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | - // "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | - // "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" - private static final long L_UPALPHA = 0L; - private static final long H_UPALPHA = highMask('A', 'Z'); - - // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | - // "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | - // "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" - private static final long L_LOWALPHA = 0L; - private static final long H_LOWALPHA = highMask('a', 'z'); - - // alpha = lowalpha | upalpha - private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA; - private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA; - - // alphanum = alpha | digit - private static final long L_ALPHANUM = L_DIGIT | L_ALPHA; - private static final long H_ALPHANUM = H_DIGIT | H_ALPHA; - - // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | - // "(" | ")" - private static final long L_MARK = lowMask("-_.!~*'()"); - private static final long H_MARK = highMask("-_.!~*'()"); - - // unreserved = alphanum | mark - private static final long L_UNRESERVED = L_ALPHANUM | L_MARK; - private static final long H_UNRESERVED = H_ALPHANUM | H_MARK; - - // pchar = unreserved | escaped | - // ":" | "@" | "&" | "=" | "+" | "$" | "," - private static final long L_PCHAR - = L_UNRESERVED | lowMask(":@&=+$,"); - private static final long H_PCHAR - = H_UNRESERVED | highMask(":@&=+$,"); - - // All valid path characters - private static final long L_PATH = L_PCHAR | lowMask(";/"); - private static final long H_PATH = H_PCHAR | highMask(";/"); - - private final static char[] hexDigits = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' - }; - - static native boolean isVfsDirectory(String path); - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/DotNetWindowsUriSupport.java b/src/IKVM.Java/local/sun/nio/fs/DotNetWindowsUriSupport.java deleted file mode 100644 index 7c98fd3f5f..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/DotNetWindowsUriSupport.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.nio.fs; - -import java.net.URI; -import java.net.URISyntaxException; - -/** - * Utility methods to convert between Path and URIs. - */ - -class DotNetWindowsUriSupport { - private DotNetWindowsUriSupport() { - } - - // suffix for IPv6 literal address - private static final String IPV6_LITERAL_SUFFIX = ".ipv6-literal.net"; - - /** - * Returns URI to represent the given (absolute) path - */ - private static URI toUri(String path, boolean isUnc, boolean addSlash) { - String uriHost; - String uriPath; - - if (isUnc) { - int slash = path.indexOf('\\', 2); - uriHost = path.substring(2, slash); - uriPath = path.substring(slash).replace('\\', '/'); - - // handle IPv6 literal addresses - // 1. drop .ivp6-literal.net - // 2. replace "-" with ":" - // 3. replace "s" with "%" (zone/scopeID delimiter) - if (uriHost.endsWith(IPV6_LITERAL_SUFFIX)) { - uriHost = uriHost - .substring(0, uriHost.length() - IPV6_LITERAL_SUFFIX.length()) - .replace('-', ':') - .replace('s', '%'); - } - } else { - uriHost = ""; - uriPath = "/" + path.replace('\\', '/'); - } - - // append slash if known to be directory - if (addSlash) - uriPath += "/"; - - // return file:///C:/My%20Documents or file://server/share/foo - try { - return new URI("file", uriHost, uriPath, null); - } catch (URISyntaxException x) { - if (!isUnc) - throw new AssertionError(x); - } - - // if we get here it means we've got a UNC with reserved characters - // in the server name. The authority component cannot contain escaped - // octets so fallback to encoding the server name into the URI path - // component. - uriPath = "//" + path.replace('\\', '/'); - if (addSlash) - uriPath += "/"; - try { - return new URI("file", null, uriPath, null); - } catch (URISyntaxException x) { - throw new AssertionError(x); - } - } - - /** - * Converts given Path to a URI - */ - static URI toUri(DotNetPath path) { - path = path.toAbsolutePath(); - String s = path.toString(); - - // trailing slash will be added if file is a directory. Skip check if - // already have trailing space - boolean addSlash = false; - if (!s.endsWith("\\")) { - try { - addSlash = cli.System.IO.Directory.Exists(s) || isVfsDirectory(s); - } catch (Throwable x) { - } - } - - return toUri(s, path.isUnc(), addSlash); - } - - /** - * Converts given URI to a Path - */ - static DotNetPath fromUri(DotNetFileSystem fs, URI uri) { - if (!uri.isAbsolute()) - throw new IllegalArgumentException("URI is not absolute"); - if (uri.isOpaque()) - throw new IllegalArgumentException("URI is not hierarchical"); - String scheme = uri.getScheme(); - if ((scheme == null) || !scheme.equalsIgnoreCase("file")) - throw new IllegalArgumentException("URI scheme is not \"file\""); - if (uri.getFragment() != null) - throw new IllegalArgumentException("URI has a fragment component"); - if (uri.getQuery() != null) - throw new IllegalArgumentException("URI has a query component"); - String path = uri.getPath(); - if (path.equals("")) - throw new IllegalArgumentException("URI path component is empty"); - - // UNC - String auth = uri.getAuthority(); - if (auth != null && !auth.equals("")) { - String host = uri.getHost(); - if (host == null) - throw new IllegalArgumentException("URI authority component has undefined host"); - if (uri.getUserInfo() != null) - throw new IllegalArgumentException("URI authority component has user-info"); - if (uri.getPort() != -1) - throw new IllegalArgumentException("URI authority component has port number"); - - // IPv6 literal - // 1. drop enclosing brackets - // 2. replace ":" with "-" - // 3. replace "%" with "s" (zone/scopeID delimiter) - // 4. Append .ivp6-literal.net - if (host.startsWith("[")) { - host = host.substring(1, host.length()-1) - .replace(':', '-') - .replace('%', 's'); - host += IPV6_LITERAL_SUFFIX; - } - - // reconstitute the UNC - path = "\\\\" + host + path; - } else { - if ((path.length() > 2) && (path.charAt(2) == ':')) { - // "/c:/foo" --> "c:/foo" - path = path.substring(1); - } - } - return new DotNetPath(fs, path); - } - - static native boolean isVfsDirectory(String path); - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/UnixConstants.java b/src/IKVM.Java/local/sun/nio/fs/UnixConstants.java deleted file mode 100644 index bc9bcef8f2..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/UnixConstants.java +++ /dev/null @@ -1,216 +0,0 @@ -package sun.nio.fs; - -class UnixConstants { - static final int O_RDONLY; - static final int O_WRONLY; - static final int O_RDWR; - static final int O_APPEND; - static final int O_CREAT; - static final int O_EXCL; - static final int O_TRUNC; - static final int O_SYNC; - static final int O_DSYNC; - static final int O_NOFOLLOW; - static final int S_IAMB; - static final int S_IRUSR; - static final int S_IWUSR; - static final int S_IXUSR; - static final int S_IRGRP; - static final int S_IWGRP; - static final int S_IXGRP; - static final int S_IROTH; - static final int S_IWOTH; - static final int S_IXOTH; - static final int S_IFMT; - static final int S_IFREG; - static final int S_IFDIR; - static final int S_IFLNK; - static final int S_IFCHR; - static final int S_IFBLK; - static final int S_IFIFO; - static final int R_OK; - static final int W_OK; - static final int X_OK; - static final int F_OK; - static final int ENOENT; - static final int ENXIO; - static final int EACCES; - static final int EEXIST; - static final int ENOTDIR; - static final int EINVAL; - static final int EXDEV; - static final int EISDIR; - static final int ENOTEMPTY; - static final int ENOSPC; - static final int EAGAIN; - static final int ENOSYS; - static final int ELOOP; - static final int EROFS; - static final int ENODATA; - static final int ERANGE; - static final int EMFILE; - static final int AT_SYMLINK_NOFOLLOW; - static final int AT_REMOVEDIR; - - static { - if (cli.IKVM.Runtime.RuntimeUtil.get_IsLinux()) { - O_RDONLY = 0; - O_WRONLY = 1; - O_RDWR = 2; - O_APPEND = 0x400; - O_CREAT = 0x40; - O_EXCL = 0x80; - O_TRUNC = 0x200; - O_SYNC = 0x1000; - O_DSYNC = 0x1000; - O_NOFOLLOW = 0x20000; - S_IAMB = 0x1ff; - S_IRUSR = 256; - S_IWUSR = 128; - S_IXUSR = 64; - S_IRGRP = 32; - S_IWGRP = 16; - S_IXGRP = 8; - S_IROTH = 4; - S_IWOTH = 2; - S_IXOTH = 1; - S_IFMT = 0xf000; - S_IFREG = 0x8000; - S_IFDIR = 0x4000; - S_IFLNK = 0xa000; - S_IFCHR = 0x2000; - S_IFBLK = 0x6000; - S_IFIFO = 0x1000; - R_OK = 4; - W_OK = 2; - X_OK = 1; - F_OK = 0; - ENOENT = 2; - ENXIO = -1; - EACCES = 13; - EEXIST = 17; - ENOTDIR = 20; - EINVAL = 22; - EXDEV = 18; - EISDIR = 21; - ENOTEMPTY = 39; - ENOSPC = 28; - EAGAIN = 11; - ENOSYS = 38; - ELOOP = 40; - EROFS = 30; - ENODATA = 61; - ERANGE = 34; - EMFILE = 24; - AT_SYMLINK_NOFOLLOW = 0x100; - AT_REMOVEDIR = 0x200; - } else if (cli.IKVM.Runtime.RuntimeUtil.get_IsOSX()) { - O_RDONLY = 0x0000; - O_WRONLY = 0x0001; - O_RDWR = 0x0002; - O_APPEND = 0x0008; - O_CREAT = 0x0200; - O_EXCL = 0x0800; - O_TRUNC = 0x0400; - O_SYNC = 0x0080; - O_DSYNC = 0x400000; - O_NOFOLLOW = 0x0100; - S_IAMB = (0000400|0000200|0000100|0000040|0000020|0000010|0000004|0000002|0000001); - S_IRUSR = 0000400; - S_IWUSR = 0000200; - S_IXUSR = 0000100; - S_IRGRP = 0000040; - S_IWGRP = 0000020; - S_IXGRP = 0000010; - S_IROTH = 0000004; - S_IWOTH = 0000002; - S_IXOTH = 0000001; - S_IFMT = 0170000; - S_IFREG = 0100000; - S_IFDIR = 0040000; - S_IFLNK = 0120000; - S_IFCHR = 0020000; - S_IFBLK = 0060000; - S_IFIFO = 0010000; - R_OK = (1<<2); - W_OK = (1<<1); - X_OK = (1<<0); - F_OK = 0; - ENOENT = 2; - ENXIO = 6; - EACCES = 13; - EEXIST = 17; - ENOTDIR = 20; - EINVAL = 22; - EXDEV = 18; - EISDIR = 21; - ENOTEMPTY = 66; - ENOSPC = 28; - EAGAIN = 35; - ENOSYS = 78; - ELOOP = 62; - EROFS = 30; - ENODATA = 96; - ERANGE = 34; - EMFILE = 24; - AT_SYMLINK_NOFOLLOW = 0x0020; - AT_REMOVEDIR = 0x0080; - } else { - O_RDONLY = -1; - O_WRONLY = -1; - O_RDWR = -1; - O_APPEND = -1; - O_CREAT = -1; - O_EXCL = -1; - O_TRUNC = -1; - O_SYNC = -1; - O_DSYNC = -1; - O_NOFOLLOW = -1; - S_IAMB = -1; - S_IRUSR = -1; - S_IWUSR = -1; - S_IXUSR = -1; - S_IRGRP = -1; - S_IWGRP = -1; - S_IXGRP = -1; - S_IROTH = -1; - S_IWOTH = -1; - S_IXOTH = -1; - S_IFMT = -1; - S_IFREG = -1; - S_IFDIR = -1; - S_IFLNK = -1; - S_IFCHR = -1; - S_IFBLK = -1; - S_IFIFO = -1; - R_OK = -1; - W_OK = -1; - X_OK = -1; - F_OK = -1; - ENOENT = -1; - ENXIO = -1; - EACCES = -1; - EEXIST = -1; - ENOTDIR = -1; - EINVAL = -1; - EXDEV = -1; - EISDIR = -1; - ENOTEMPTY = -1; - ENOSPC = -1; - EAGAIN = -1; - ENOSYS = -1; - ELOOP = -1; - EROFS = -1; - ENODATA = -1; - ERANGE = -1; - EMFILE = -1; - AT_SYMLINK_NOFOLLOW = -1; - AT_REMOVEDIR = -1; - } - } - - private UnixConstants() { - - } - -} diff --git a/src/IKVM.Java/local/sun/nio/fs/UnixException.java b/src/IKVM.Java/local/sun/nio/fs/UnixException.java deleted file mode 100644 index c795d07c44..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/UnixException.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.nio.fs; - -import java.nio.file.*; -import java.io.IOException; - -/** - * Internal exception thrown by native methods when error detected. - */ - -class UnixException extends Exception { - static final long serialVersionUID = 7227016794320723218L; - - private int errno; - private String msg; - - UnixException(int errno) { - this.errno = errno; - this.msg = null; - } - - UnixException(String msg) { - this.errno = 0; - this.msg = msg; - } - - int errno() { - return errno; - } - - void setError(int errno) { - this.errno = errno; - this.msg = null; - } - - String errorString() { - if (msg != null) { - return msg; - } else { - return Util.toString(UnixNativeDispatcher.strerror(errno())); - } - } - - @Override - public String getMessage() { - return errorString(); - } - - /** - * Map well known errors to specific exceptions where possible; otherwise - * return more general FileSystemException. - */ - private IOException translateToIOException(String file, String other) { - // created with message rather than errno - if (msg != null) - return new IOException(msg); - - // handle specific cases - if (errno() == UnixConstants.EACCES) - return new AccessDeniedException(file, other, null); - if (errno() == UnixConstants.ENOENT) - return new NoSuchFileException(file, other, null); - if (errno() == UnixConstants.EEXIST) - return new FileAlreadyExistsException(file, other, null); - - // fallback to the more general exception - return new FileSystemException(file, other, errorString()); - } - - void rethrowAsIOException(String file) throws IOException { - IOException x = translateToIOException(file, null); - throw x; - } - - void rethrowAsIOException(String file, String other) throws IOException { - IOException x = translateToIOException(file, other); - throw x; - } - - IOException asIOException(String file) { - return translateToIOException(file, null); - } -} diff --git a/src/IKVM.Java/local/sun/nio/fs/UnixNativeDispatcher.java b/src/IKVM.Java/local/sun/nio/fs/UnixNativeDispatcher.java deleted file mode 100644 index e8c4ae10d0..0000000000 --- a/src/IKVM.Java/local/sun/nio/fs/UnixNativeDispatcher.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.nio.fs; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -/** - * Unix system and library calls. - */ - -class UnixNativeDispatcher { - protected UnixNativeDispatcher() { } - - /** - * char *getcwd(char *buf, size_t size); - */ - static native byte[] getcwd(); - - /** - * int dup(int filedes) - */ - static native int dup(int filedes) throws UnixException; - - private static native int open0(long pathAddress, int flags, int mode) - throws UnixException; - - /** - * int openat(int dfd, const char* path, int oflag, mode_t mode) - */ - static int openat(int dfd, byte[] path, int flags, int mode) throws UnixException { - NativeBuffer buffer = NativeBuffers.asNativeBuffer(path); - try { - return openat0(dfd, buffer.address(), flags, mode); - } finally { - buffer.release(); - } - } - private static native int openat0(int dfd, long pathAddress, int flags, int mode) - throws UnixException; - - /** - * close(int filedes) - */ - static native void close(int fd); - - private static native long fopen0(long pathAddress, long modeAddress) - throws UnixException; - - /** - * fclose(FILE* stream) - */ - static native void fclose(long stream) throws UnixException; - - private static native void link0(long existingAddress, long newAddress) - throws UnixException; - - private static native void unlink0(long pathAddress) throws UnixException; - - /** - * unlinkat(int dfd, const char* path, int flag) - */ - static void unlinkat(int dfd, byte[] path, int flag) throws UnixException { - NativeBuffer buffer = NativeBuffers.asNativeBuffer(path); - try { - unlinkat0(dfd, buffer.address(), flag); - } finally { - buffer.release(); - } - } - private static native void unlinkat0(int dfd, long pathAddress, int flag) - throws UnixException; - - private static native void mknod0(long pathAddress, int mode, long dev) - throws UnixException; - - private static native void rename0(long fromAddress, long toAddress) - throws UnixException; - - /** - * renameat(int fromfd, const char* old, int tofd, const char* new) - */ - static void renameat(int fromfd, byte[] from, int tofd, byte[] to) throws UnixException { - NativeBuffer fromBuffer = NativeBuffers.asNativeBuffer(from); - NativeBuffer toBuffer = NativeBuffers.asNativeBuffer(to); - try { - renameat0(fromfd, fromBuffer.address(), tofd, toBuffer.address()); - } finally { - toBuffer.release(); - fromBuffer.release(); - } - } - private static native void renameat0(int fromfd, long fromAddress, int tofd, long toAddress) - throws UnixException; - - private static native void mkdir0(long pathAddress, int mode) throws UnixException; - - private static native void rmdir0(long pathAddress) throws UnixException; - - private static native byte[] readlink0(long pathAddress) throws UnixException; - - private static native byte[] realpath0(long pathAddress) throws UnixException; - - private static native void symlink0(long name1, long name2) - throws UnixException; - - private static native void chown0(long pathAddress, int uid, int gid) - throws UnixException; - - private static native void lchown0(long pathAddress, int uid, int gid) - throws UnixException; - - /** - * fchown(int filedes, uid_t owner, gid_t group) - */ - static native void fchown(int fd, int uid, int gid) throws UnixException; - - private static native void chmod0(long pathAddress, int mode) - throws UnixException; - - /** - * fchmod(int fildes, mode_t mode) - */ - static native void fchmod(int fd, int mode) throws UnixException; - - private static native void utimes0(long pathAddress, long times0, long times1) - throws UnixException; - - /** - * futimes(int fildes,, const struct timeval times[2]) - */ - static native void futimes(int fd, long times0, long times1) throws UnixException; - - private static native long opendir0(long pathAddress) throws UnixException; - - /** - * DIR* fdopendir(int filedes) - */ - static native long fdopendir(int dfd) throws UnixException; - - - /** - * closedir(DIR* dirp) - */ - static native void closedir(long dir) throws UnixException; - - /** - * struct dirent* readdir(DIR *dirp) - * - * @return dirent->d_name - */ - static native byte[] readdir(long dir) throws UnixException; - - /** - * size_t read(int fildes, void* buf, size_t nbyte) - */ - static native int read(int fildes, long buf, int nbyte) throws UnixException; - - /** - * size_t writeint fildes, void* buf, size_t nbyte) - */ - static native int write(int fildes, long buf, int nbyte) throws UnixException; - - private static native void access0(long pathAddress, int amode) throws UnixException; - - /** - * struct passwd *getpwuid(uid_t uid); - * - * @return passwd->pw_name - */ - static native byte[] getpwuid(int uid) throws UnixException; - - /** - * struct group *getgrgid(gid_t gid); - * - * @return group->gr_name - */ - static native byte[] getgrgid(int gid) throws UnixException; - - /** - * struct passwd *getpwnam(const char *name); - * - * @return passwd->pw_uid - */ - static int getpwnam(String name) throws UnixException { - NativeBuffer buffer = NativeBuffers.asNativeBuffer(Util.toBytes(name)); - try { - return getpwnam0(buffer.address()); - } finally { - buffer.release(); - } - } - private static native int getpwnam0(long nameAddress) throws UnixException; - - /** - * struct group *getgrnam(const char *name); - * - * @return group->gr_name - */ - static int getgrnam(String name) throws UnixException { - NativeBuffer buffer = NativeBuffers.asNativeBuffer(Util.toBytes(name)); - try { - return getgrnam0(buffer.address()); - } finally { - buffer.release(); - } - } - private static native int getgrnam0(long nameAddress) throws UnixException; - - private static native long pathconf0(long pathAddress, int name) - throws UnixException; - - /** - * long fpathconf(int fildes, int name); - */ - static native long fpathconf(int filedes, int name) throws UnixException; - - /** - * char* strerror(int errnum) - */ - static native byte[] strerror(int errnum); - - /** - * Capabilities - */ - private static final int SUPPORTS_OPENAT = 1 << 1; // syscalls - private static final int SUPPORTS_FUTIMES = 1 << 2; - private static final int SUPPORTS_BIRTHTIME = 1 << 16; // other features - private static final int capabilities; - - /** - * Supports openat and other *at calls. - */ - static boolean openatSupported() { - return (capabilities & SUPPORTS_OPENAT) != 0; - } - - /** - * Supports futimes or futimesat - */ - static boolean futimesSupported() { - return (capabilities & SUPPORTS_FUTIMES) != 0; - } - - /** - * Supports file birth (creation) time attribute - */ - static boolean birthtimeSupported() { - return (capabilities & SUPPORTS_BIRTHTIME) != 0; - } - - private static native int init(); - static { - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - System.loadLibrary("nio"); - return null; - }}); - capabilities = init(); - } -} diff --git a/src/IKVM.Java/local/sun/security/jgss/wrapper/NativeGSSFactory.java b/src/IKVM.Java/local/sun/security/jgss/wrapper/NativeGSSFactory.java deleted file mode 100644 index 08ac04d2fd..0000000000 --- a/src/IKVM.Java/local/sun/security/jgss/wrapper/NativeGSSFactory.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright (C) 2007 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -package sun.security.jgss.wrapper; - -// this is a compilation stub only -public abstract class NativeGSSFactory implements sun.security.jgss.spi.MechanismFactory -{ - private NativeGSSFactory() { } - /* - public Oid getMechanismOid() - { - throw new UnsupportedOperationException(); - } - - public Provider getProvider() - { - throw new UnsupportedOperationException(); - } - - public Oid[] getNameTypes() - { - throw new UnsupportedOperationException(); - } - - public GSSCredentialSpi getCredentialElement(GSSNameSpi name, int initLifetime, int acceptLifetime, int usage) - { - throw new UnsupportedOperationException(); - } - - public GSSNameSpi getNameElement(String nameStr, Oid nameType) - { - throw new UnsupportedOperationException(); - } - - public GSSNameSpi getNameElement(byte[] name, Oid nameType) - { - throw new UnsupportedOperationException(); - } - - public GSSContextSpi getMechanismContext(GSSNameSpi peer, GSSCredentialSpi myInitiatorCred, int lifetime) - { - } - - public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred) - { - } - - public GSSContextSpi getMechanismContext(byte[] exportedContext) - { - } -*/ - public abstract void setMech(org.ietf.jgss.Oid mech); -} diff --git a/src/IKVM.Java/local/sun/security/jgss/wrapper/SunNativeProvider.java b/src/IKVM.Java/local/sun/security/jgss/wrapper/SunNativeProvider.java deleted file mode 100644 index 42e027dfc7..0000000000 --- a/src/IKVM.Java/local/sun/security/jgss/wrapper/SunNativeProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - Copyright (C) 2007 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -package sun.security.jgss.wrapper; - -// this is a compilation stub only -public final class SunNativeProvider extends java.security.Provider -{ - public static final SunNativeProvider INSTANCE = new SunNativeProvider(); - - public SunNativeProvider() - { - super(null, 0.0, null); - } - - static void debug(String message) - { - } -} diff --git a/src/IKVM.Java/map.xml b/src/IKVM.Java/map.xml index 035dd1480c..f4ea2a3c45 100644 --- a/src/IKVM.Java/map.xml +++ b/src/IKVM.Java/map.xml @@ -2731,8 +2731,6 @@ - - diff --git a/src/IKVM.MSBuild.Tasks.Tests/IKVM.MSBuild.Tasks.Tests.csproj b/src/IKVM.MSBuild.Tasks.Tests/IKVM.MSBuild.Tasks.Tests.csproj index 572c300da6..ba498fd122 100644 --- a/src/IKVM.MSBuild.Tasks.Tests/IKVM.MSBuild.Tasks.Tests.csproj +++ b/src/IKVM.MSBuild.Tasks.Tests/IKVM.MSBuild.Tasks.Tests.csproj @@ -21,8 +21,8 @@ - - + + diff --git a/src/IKVM.MSBuild.Tasks/IKVM.MSBuild.Tasks.csproj b/src/IKVM.MSBuild.Tasks/IKVM.MSBuild.Tasks.csproj index ae100a34d3..0d948e5079 100644 --- a/src/IKVM.MSBuild.Tasks/IKVM.MSBuild.Tasks.csproj +++ b/src/IKVM.MSBuild.Tasks/IKVM.MSBuild.Tasks.csproj @@ -1,4 +1,8 @@ - + + + + + net472;net6.0;net8.0 @@ -9,8 +13,8 @@ - - + + @@ -43,4 +47,8 @@ + + + + diff --git a/src/IKVM.MSBuild.Tests/Project/Exe/ProjectExe.csproj b/src/IKVM.MSBuild.Tests/Project/Exe/ProjectExe.csproj index a28eaf7921..0e9e0b8f99 100644 --- a/src/IKVM.MSBuild.Tests/Project/Exe/ProjectExe.csproj +++ b/src/IKVM.MSBuild.Tests/Project/Exe/ProjectExe.csproj @@ -8,7 +8,7 @@ Exe - net472;net48;net6.0;net7.0 + net472;net48;net6.0;net7.0;net8.0 win-x86;win-x64;win-arm64;linux-x64;linux-arm;linux-arm64;linux-musl-x64;linux-musl-arm;linux-musl-arm64;osx-x64;osx-arm64 AnyCPU diff --git a/src/IKVM.MSBuild.Tests/Project/Lib/ProjectLib.csproj b/src/IKVM.MSBuild.Tests/Project/Lib/ProjectLib.csproj index 2ba2315168..7f7d8c7838 100644 --- a/src/IKVM.MSBuild.Tests/Project/Lib/ProjectLib.csproj +++ b/src/IKVM.MSBuild.Tests/Project/Lib/ProjectLib.csproj @@ -7,7 +7,7 @@ - net472;net48;net6.0;net7.0 + net472;net48;net6.0;net7.0;net8.0 diff --git a/src/IKVM.MSBuild.Tests/Project/global.json b/src/IKVM.MSBuild.Tests/Project/global.json index 857e6681f3..52b1ec3002 100644 --- a/src/IKVM.MSBuild.Tests/Project/global.json +++ b/src/IKVM.MSBuild.Tests/Project/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.100", + "version": "8.0.0", "rollForward": "latestFeature" } } diff --git a/src/IKVM.MSBuild.Tests/ProjectTests.cs b/src/IKVM.MSBuild.Tests/ProjectTests.cs index de88fb3c90..05019ff0b1 100644 --- a/src/IKVM.MSBuild.Tests/ProjectTests.cs +++ b/src/IKVM.MSBuild.Tests/ProjectTests.cs @@ -134,7 +134,10 @@ public static void ClassInitialize(TestContext context) options.TargetsToBuild.Add("Clean"); options.TargetsToBuild.Add("Restore"); options.Arguments.Add("/v:d"); - analyzer.Build(options).OverallSuccess.Should().Be(true); + + var result = analyzer.Build(options); + context.AddResultFile(Path.Combine(WorkRoot, "msbuild.binlog")); + result.OverallSuccess.Should().Be(true); } [ClassCleanup] @@ -175,6 +178,17 @@ public static void ClassCleanup() [DataRow(EnvironmentPreference.Core, "net7.0", "linux-musl-arm64", "{0}", "lib{0}.so")] [DataRow(EnvironmentPreference.Core, "net7.0", "osx-x64", "{0}", "lib{0}.dylib")] [DataRow(EnvironmentPreference.Core, "net7.0", "osx-arm64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Core, "net8.0", "win-x86", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Core, "net8.0", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Core, "net8.0", "win-arm64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-musl-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-musl-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-musl-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "osx-x64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Core, "net8.0", "osx-arm64", "{0}", "lib{0}.dylib")] [DataRow(EnvironmentPreference.Framework, "net472", "win-x86", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Framework, "net472", "win-x64", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Framework, "net472", "win-arm64", "{0}.exe", "{0}.dll")] @@ -203,6 +217,17 @@ public static void ClassCleanup() [DataRow(EnvironmentPreference.Framework, "net7.0", "linux-musl-arm64", "{0}", "lib{0}.so")] [DataRow(EnvironmentPreference.Framework, "net7.0", "osx-x64", "{0}", "lib{0}.dylib")] [DataRow(EnvironmentPreference.Framework, "net7.0", "osx-arm64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "win-x86", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "win-arm64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-musl-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-musl-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-musl-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "osx-x64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "osx-arm64", "{0}", "lib{0}.dylib")] public void CanBuildTestProject(EnvironmentPreference env, string tfm, string rid, string exe, string lib) { // skip framework tests for non-Windows platforms @@ -239,7 +264,10 @@ public void CanBuildTestProject(EnvironmentPreference env, string tfm, string ri options.TargetsToBuild.Add("Build"); options.TargetsToBuild.Add("Publish"); options.Arguments.Add("/v:d"); - analyzer.Build(options).OverallSuccess.Should().Be(true); + + var result = analyzer.Build(options); + TestContext.AddResultFile(Path.Combine(WorkRoot, $"{tfm}-{rid}-msbuild.binlog")); + result.OverallSuccess.Should().Be(true); var binDir = Path.Combine("Project", "Exe", "bin", "Release", tfm, rid); @@ -273,11 +301,11 @@ public void CanBuildTestProject(EnvironmentPreference env, string tfm, string ri File.Exists(Path.Combine(outDir, "ikvm", rid, "lib", "security", "java.security")).Should().BeTrue(); // ikvm image bin exeecutables - foreach (var exeName in new[] { "jar", "jarsigner", "java", "javac", "javah", "javap", "jdeps", "keytool", "native2ascii", "orbd", "policytool", "rmic", "schemagen", "wsgen", "wsimport" }) + foreach (var exeName in new[] { "jar", "jarsigner", "java", "javac", "javah", "javap", "jdeps", "keytool", "native2ascii", "orbd", "policytool", "rmic", "schemagen", "wsgen", "wsimport", "xjc" }) File.Exists(Path.Combine(outDir, "ikvm", rid, "bin", string.Format(exe, exeName))).Should().BeTrue(); // ikvm image native libraries - foreach (var libName in new[] { "awt", "fdlibm", "iava", "jvm", "management", "net", "nio", "sunec", "unpack", "verify" }) + foreach (var libName in new[] { "awt", "iava", "jvm", "management", "net", "nio", "sunec", "unpack", "verify" }) File.Exists(Path.Combine(outDir, "ikvm", rid, "bin", string.Format(lib, libName))).Should().BeTrue(); } @@ -293,7 +321,7 @@ public void CanBuildTestProject(EnvironmentPreference env, string tfm, string ri File.Exists(Path.Combine(outDir, "ikvm", "win-x64", "bin", string.Format(lib, "iava"))).Should().BeTrue(); // ikvm image native libraries - foreach (var libName in new[] { "awt", "fdlibm", "iava", "jvm", "management", "net", "nio", "sunec", "unpack", "verify" }) + foreach (var libName in new[] { "awt", "iava", "jvm", "management", "net", "nio", "sunec", "unpack", "verify" }) File.Exists(Path.Combine(outDir, "ikvm", "win-x64", "bin", string.Format(lib, libName))).Should().BeTrue(); } else diff --git a/src/IKVM.NET.Sdk.Tests/IKVM.NET.Sdk.Tests.csproj b/src/IKVM.NET.Sdk.Tests/IKVM.NET.Sdk.Tests.csproj index 3ac52cde70..2d833d772e 100644 --- a/src/IKVM.NET.Sdk.Tests/IKVM.NET.Sdk.Tests.csproj +++ b/src/IKVM.NET.Sdk.Tests/IKVM.NET.Sdk.Tests.csproj @@ -3,6 +3,7 @@ net8.0 + true diff --git a/src/IKVM.NET.Sdk.Tests/Project/Exe/ProjectExe.msbuildproj b/src/IKVM.NET.Sdk.Tests/Project/Exe/ProjectExe.msbuildproj index 025091ab66..8913d5249d 100644 --- a/src/IKVM.NET.Sdk.Tests/Project/Exe/ProjectExe.msbuildproj +++ b/src/IKVM.NET.Sdk.Tests/Project/Exe/ProjectExe.msbuildproj @@ -3,7 +3,7 @@ Exe - net472;net48;net6.0;net7.0 + net472;net48;net6.0;net7.0;net8.0 win-x86;win-x64;win-arm64;linux-x64;linux-arm;linux-arm64;linux-musl-x64;linux-musl-arm;linux-musl-arm64;osx-x64;osx-arm64 project.exe project.exe.Main diff --git a/src/IKVM.NET.Sdk.Tests/Project/Lib/ProjectLib.msbuildproj b/src/IKVM.NET.Sdk.Tests/Project/Lib/ProjectLib.msbuildproj index ae91b5288c..ed74b873f9 100644 --- a/src/IKVM.NET.Sdk.Tests/Project/Lib/ProjectLib.msbuildproj +++ b/src/IKVM.NET.Sdk.Tests/Project/Lib/ProjectLib.msbuildproj @@ -2,7 +2,7 @@ - net472;net48;net6.0;net7.0 + net472;net48;net6.0;net7.0;net8.0 project.lib diff --git a/src/IKVM.NET.Sdk.Tests/Project/global.json b/src/IKVM.NET.Sdk.Tests/Project/global.json index 912bc7602d..52b1ec3002 100644 --- a/src/IKVM.NET.Sdk.Tests/Project/global.json +++ b/src/IKVM.NET.Sdk.Tests/Project/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.0", + "version": "8.0.0", "rollForward": "latestFeature" } } diff --git a/src/IKVM.NET.Sdk.Tests/ProjectTests.cs b/src/IKVM.NET.Sdk.Tests/ProjectTests.cs index 02af1a9de0..7c703cdb3c 100644 --- a/src/IKVM.NET.Sdk.Tests/ProjectTests.cs +++ b/src/IKVM.NET.Sdk.Tests/ProjectTests.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Security.Cryptography; using System.Xml.Linq; using Buildalyzer; @@ -126,8 +127,11 @@ public static void Init(TestContext context) options.Restore = true; options.TargetsToBuild.Clear(); options.TargetsToBuild.Add("Restore"); - options.Arguments.Add("/v:d"); - analyzer.Build(options).OverallSuccess.Should().Be(true); + options.Arguments.Add("/v:diag"); + + var result = analyzer.Build(options); + context.AddResultFile(Path.Combine(WorkRoot, "msbuild.binlog")); + result.OverallSuccess.Should().Be(true); } [ClassCleanup] @@ -168,32 +172,54 @@ public static void ClassCleanup() [DataRow(EnvironmentPreference.Core, "net7.0", "linux-musl-arm64", "{0}", "lib{0}.so")] [DataRow(EnvironmentPreference.Core, "net7.0", "osx-x64", "{0}", "lib{0}.dylib")] [DataRow(EnvironmentPreference.Core, "net7.0", "osx-arm64", "{0}", "lib{0}.dylib")] - //[DataRow(EnvironmentPreference.Framework, "net472", "win-x86", "{0}.exe", "{0}.dll")] - //[DataRow(EnvironmentPreference.Framework, "net472", "win-x64", "{0}.exe", "{0}.dll")] - //[DataRow(EnvironmentPreference.Framework, "net48", "win-x86", "{0}.exe", "{0}.dll")] - //[DataRow(EnvironmentPreference.Framework, "net48", "win-x64", "{0}.exe", "{0}.dll")] - //[DataRow(EnvironmentPreference.Framework, "net6.0", "win-x86", "{0}.exe", "{0}.dll")] - //[DataRow(EnvironmentPreference.Framework, "net6.0", "win-x64", "{0}.exe", "{0}.dll")] - //[DataRow(EnvironmentPreference.Framework, "net6.0", "win-arm64", "{0}.exe", "{0}.dll")] - //[DataRow(EnvironmentPreference.Framework, "net6.0", "linux-x64", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net6.0", "linux-arm", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net6.0", "linux-arm64", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net6.0", "linux-musl-x64", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net6.0", "linux-musl-arm", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net6.0", "linux-musl-arm64", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net6.0", "osx-x64", "{0}", "lib{0}.dylib")] - //[DataRow(EnvironmentPreference.Framework, "net6.0", "osx-arm64", "{0}", "lib{0}.dylib")] - //[DataRow(EnvironmentPreference.Framework, "net7.0", "win-x86", "{0}.exe", "{0}.dll")] - //[DataRow(EnvironmentPreference.Framework, "net7.0", "win-x64", "{0}.exe", "{0}.dll")] - //[DataRow(EnvironmentPreference.Framework, "net7.0", "win-arm64", "{0}.exe", "{0}.dll")] - //[DataRow(EnvironmentPreference.Framework, "net7.0", "linux-x64", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net7.0", "linux-arm", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net7.0", "linux-arm64", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net7.0", "linux-musl-x64", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net7.0", "linux-musl-arm", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net7.0", "linux-musl-arm64", "{0}", "lib{0}.so")] - //[DataRow(EnvironmentPreference.Framework, "net7.0", "osx-x64", "{0}", "lib{0}.dylib")] - //[DataRow(EnvironmentPreference.Framework, "net7.0", "osx-arm64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Core, "net8.0", "win-x86", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Core, "net8.0", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Core, "net8.0", "win-arm64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-musl-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-musl-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "linux-musl-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Core, "net8.0", "osx-x64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Core, "net8.0", "osx-arm64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Framework, "net472", "win-x86", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net472", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net48", "win-x86", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net48", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net6.0", "win-x86", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net6.0", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net6.0", "win-arm64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net6.0", "linux-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net6.0", "linux-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net6.0", "linux-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net6.0", "linux-musl-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net6.0", "linux-musl-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net6.0", "linux-musl-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net6.0", "osx-x64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Framework, "net6.0", "osx-arm64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Framework, "net7.0", "win-x86", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net7.0", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net7.0", "win-arm64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net7.0", "linux-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net7.0", "linux-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net7.0", "linux-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net7.0", "linux-musl-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net7.0", "linux-musl-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net7.0", "linux-musl-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net7.0", "osx-x64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Framework, "net7.0", "osx-arm64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "win-x86", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "win-arm64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-musl-x64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-musl-arm", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "linux-musl-arm64", "{0}", "lib{0}.so")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "osx-x64", "{0}", "lib{0}.dylib")] + [DataRow(EnvironmentPreference.Framework, "net8.0", "osx-arm64", "{0}", "lib{0}.dylib")] public void CanBuildTestProject(EnvironmentPreference env, string tfm, string rid, string exe, string lib) { // skip framework tests for non-Windows platforms @@ -230,7 +256,10 @@ public void CanBuildTestProject(EnvironmentPreference env, string tfm, string ri options.TargetsToBuild.Add("Build"); options.TargetsToBuild.Add("Publish"); options.Arguments.Add("/v:diag"); - analyzer.Build(options).OverallSuccess.Should().Be(true); + + var result = analyzer.Build(options); + TestContext.AddResultFile(Path.Combine(WorkRoot, $"{tfm}-{rid}-msbuild.binlog")); + result.OverallSuccess.Should().Be(true); var binDir = Path.Combine("Project", "Exe", "bin", "Release", tfm, rid); @@ -260,7 +289,7 @@ public void CanBuildTestProject(EnvironmentPreference env, string tfm, string ri File.Exists(Path.Combine(outDir, "ikvm", rid, "lib", "security", "java.security")).Should().BeTrue(); // ikvm image native libraries - foreach (var libName in new[] { "awt", "fdlibm", "iava", "jvm", "management", "net", "nio", "sunec", "unpack", "verify" }) + foreach (var libName in new[] { "awt", "iava", "jvm", "management", "net", "nio", "sunec", "unpack", "verify" }) File.Exists(Path.Combine(outDir, "ikvm", rid, "bin", string.Format(lib, libName))).Should().BeTrue(); } } diff --git a/src/IKVM.NET.Sdk/targets/IKVM.Java.Core.targets b/src/IKVM.NET.Sdk/targets/IKVM.Java.Core.targets index d11ee16f51..4ecd78d8f3 100644 --- a/src/IKVM.NET.Sdk/targets/IKVM.Java.Core.targets +++ b/src/IKVM.NET.Sdk/targets/IKVM.Java.Core.targets @@ -11,7 +11,7 @@ $(IntermediateOutputPath)classes\ $(IntermediateOutputPath)headers\ - + <_IkvmReferenceExportItemPrepareStateFile Condition=" '$(_IkvmReferenceExportItemPrepareStateFile)' == '' ">$(IntermediateOutputPath)$(MSBuildProjectFile).IkvmReferenceExportItemPrepare.cache @@ -26,9 +26,11 @@ - + - + + $([System.IO.Path]::GetFullPath('$(HeaderOutputPath)')) + @@ -41,11 +43,11 @@ true - + - + <__ReferenceExport Update="@(__ReferenceExport)"> $(IkvmExportStageDir)%(IkvmIdentity)\%(Filename).jar @@ -56,7 +58,7 @@ - + <_ReferenceExport Remove="@(_ReferenceExport)" /> <__ReferenceExport Remove="@(__ReferenceExport)" /> @@ -181,7 +183,7 @@ Files = files.ToArray(); - + @@ -222,4 +224,4 @@ Files = files.ToArray(); - + \ No newline at end of file diff --git a/src/IKVM.OpenJDK.Tests/IKVM.OpenJDK.Tests.csproj b/src/IKVM.OpenJDK.Tests/IKVM.OpenJDK.Tests.csproj index 3dfa9d8603..b9449edf0b 100644 --- a/src/IKVM.OpenJDK.Tests/IKVM.OpenJDK.Tests.csproj +++ b/src/IKVM.OpenJDK.Tests/IKVM.OpenJDK.Tests.csproj @@ -10,6 +10,8 @@ + + @@ -55,6 +57,12 @@ + + + + + + diff --git a/src/IKVM.OpenJDK.Tests/jdk/ExcludeList.net6.0.txt b/src/IKVM.OpenJDK.Tests/jdk/ExcludeList.net6.0.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/IKVM.OpenJDK.Tests/jdk/ExcludeList.txt b/src/IKVM.OpenJDK.Tests/jdk/ExcludeList.txt index 4048399a9e..03d7edecfe 100644 --- a/src/IKVM.OpenJDK.Tests/jdk/ExcludeList.txt +++ b/src/IKVM.OpenJDK.Tests/jdk/ExcludeList.txt @@ -3210,6 +3210,7 @@ java/net/URLConnection/6212146/test.sh java/nio/channels/AsynchronousChannelGroup/Unbounded.java linux-all java/nio/channels/AsynchronousServerSocketChannel/Basic.java linux-all,macosx-all +java/nio/channels/ServerSocketChannel/Basic.java macosx-all java/nio/channels/AsynchronousSocketChannel/DieBeforeComplete.java linux-all java/nio/channels/AsynchronousSocketChannel/StressLoopback.java linux-all java/nio/channels/Channels/Basic2.java linux-all diff --git a/src/IKVM.Runtime/Accessors/Java/Io/FileDescriptorAccessor.cs b/src/IKVM.Runtime/Accessors/Java/Io/FileDescriptorAccessor.cs index 4f161d4daa..6b16e7cb68 100644 --- a/src/IKVM.Runtime/Accessors/Java/Io/FileDescriptorAccessor.cs +++ b/src/IKVM.Runtime/Accessors/Java/Io/FileDescriptorAccessor.cs @@ -21,12 +21,10 @@ internal sealed class FileDescriptorAccessor : Accessor FieldAccessor @out; FieldAccessor @err; - FieldAccessor obj; + FieldAccessor stream; FieldAccessor ptr; PropertyAccessor fd; PropertyAccessor handle; - FieldAccessor task; - FieldAccessor semaphore; MethodAccessor> init; MethodAccessor> sync; @@ -64,12 +62,12 @@ public FileDescriptorAccessor(AccessorTypeResolver resolver) : /// /// Gets the value for the 'obj' field. /// - public object GetObj(object self) => GetField(ref obj, nameof(obj)).GetValue(self); + public Stream GetStream(object self) => GetField(ref stream, nameof(stream)).GetValue(self); /// /// Sets the value for the 'obj' field. /// - public void SetObj(object self, object value) => GetField(ref obj, nameof(obj)).SetValue(self, value); + public void SetStream(object self, Stream value) => GetField(ref stream, nameof(stream)).SetValue(self, value); /// /// Gets the value for the 'ptr' field. @@ -101,37 +99,6 @@ public FileDescriptorAccessor(AccessorTypeResolver resolver) : /// public void SetHandle(object self, long value) => GetProperty(ref handle, nameof(handle)).SetValue(self, value); - /// - /// Gets the value of the 'task' field. - /// - /// - /// - public Task GetTask(object self) => GetField(ref task, nameof(task)).GetValue(self); - - /// - /// Sets the value of the 'task' field. - /// - /// - /// - /// - public void SetTask(object self, Task value) => GetField(ref task, nameof(task)).SetValue(self, value); - - /// - /// Gets the value of the 'semaphore' field. - /// - /// - /// - public SemaphoreSlim GetSemaphore(object self) => GetField(ref semaphore, nameof(semaphore)).GetValue(self); - - /// - /// Compares and exchanges the value of the 'semaphore' field. - /// - /// - /// - /// - /// - public SemaphoreSlim CompareExchangeSemaphore(object self, SemaphoreSlim value, SemaphoreSlim comparand) => GetField(ref semaphore, nameof(semaphore)).CompareExchangeValue(self, value, comparand); - /// /// Invokes the 'sync' method. /// diff --git a/src/IKVM.Runtime/Accessors/Java/Io/FileDescriptorAccessorExtensions.cs b/src/IKVM.Runtime/Accessors/Java/Io/FileDescriptorAccessorExtensions.cs deleted file mode 100644 index 887cca5839..0000000000 --- a/src/IKVM.Runtime/Accessors/Java/Io/FileDescriptorAccessorExtensions.cs +++ /dev/null @@ -1,218 +0,0 @@ -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Net.Sockets; -using System.Runtime.InteropServices; - -using Microsoft.Win32.SafeHandles; - -namespace IKVM.Runtime.Accessors.Java.Io -{ - -#if FIRST_PASS == false && IMPORTER == false && EXPORTER == false - - internal static class FileDescriptorAccessorExtensions - { - - /// - /// Contains the native methods for Windows. - /// - static class NativeWindows - { - - /// - /// Invokes the Win32 method 'GetStdHandle'. - /// - /// - /// - [DllImport("kernel32")] - public static extern IntPtr GetStdHandle(int nStdHandle); - - /// - /// Invokes the Win32 method 'WSADuplicateSocket'. - /// - /// - /// - /// - /// - [DllImport("ws2_32", SetLastError = true)] - public unsafe static extern int WSADuplicateSocket(IntPtr s, int dwProcessId, WSAPROTOCOL_INFOW* lpProtocolInfo); - - /// - /// Invokes the Win32 method 'closesocket'. - /// - /// - /// - [DllImport("ws2_32", SetLastError = true)] - public static extern int closesocket(IntPtr s); - - /// - /// Invokes teh Win32 method 'WSAGetLastError'. - /// - [DllImport("ws2_32", SetLastError = true)] - public static extern int WSAGetLastError(); - - public const int SO_PROTOCOL_INFOW = 0x2005; - - /// - /// Implementation of the Win32 'WSAPROTOCOL_INFOW' structure. - /// - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public unsafe struct WSAPROTOCOL_INFOW - { - - public const int WSAPROTOCOL_LEN = 255; - - public uint dwServiceFlags1; - public uint dwServiceFlags2; - public uint dwServiceFlags3; - public uint dwServiceFlags4; - public uint dwProviderFlags; - public Guid ProviderId; - public uint dwCatalogEntryId; - public WSAPROTOCOLCHAIN ProtocolChain; - public int iVersion; - public AddressFamily iAddressFamily; - public int iMaxSockAddr; - public int iMinSockAddr; - public SocketType iSocketType; - public ProtocolType iProtocol; - public int iProtocolMaxOffset; - public int iNetworkByteOrder; - public int iSecurityScheme; - public uint dwMessageSize; - public uint dwProviderReserved; - public fixed char szProtocol[WSAPROTOCOL_LEN + 1]; - - } - - /// - /// Implementation of the Win32 'WSAPROTOCOLCHAIN' structure. - /// - [StructLayout(LayoutKind.Sequential)] - public unsafe struct WSAPROTOCOLCHAIN - { - - internal const int MAX_PROTOCOL_CHAIN = 7; - - internal int ChainLen; - internal fixed uint ChainEntries[MAX_PROTOCOL_CHAIN]; - - } - - } - - /// - /// Configures the FileDescriptor with the given .NET stream. - /// - /// - /// - /// - public static void SetStream(this FileDescriptorAccessor self, object fdo, Stream stream) - { - lock (fdo) - { - self.SetPtr(fdo, stream is FileStream fs ? LibIkvm.Instance.io_duplicate_file((long)fs.SafeFileHandle.DangerousGetHandle()) : -1); - self.SetObj(fdo, stream); - } - } - - /// - /// Gets or creates a .NET stream for the FileDescriptor. - /// - /// - /// - /// - /// - public static Stream GetStream(this FileDescriptorAccessor self, object fdo) - { - lock (fdo) - { - // socket is already cached - if (self.GetObj(fdo) is Stream s) - return s; - - var handle = self.GetPtr(fdo); - if (handle == -1) - return null; - - if (LibIkvm.Instance.io_is_file(handle)) - { - self.SetObj(fdo, s = new FileStream(new SafeFileHandle((IntPtr)handle, false), FileAccess.ReadWrite, 1, false)); - return s; - } - - throw new InvalidOperationException(); - } - } - - /// - /// Configures the FileDescriptor with the given .NET socket. - /// - /// - /// - /// - public static void SetSocket(this FileDescriptorAccessor self, object fdo, Socket socket) - { - lock (fdo) - { - self.SetPtr(fdo, LibIkvm.Instance.io_duplicate_socket((long)socket.Handle)); - self.SetObj(fdo, socket); - } - } - - /// - /// Gets or creates a .NET socket for the FileDescriptor. - /// - /// - /// - /// - /// - public static unsafe Socket GetSocket(this FileDescriptorAccessor self, object fdo) - { - lock (fdo) - { - // socket is already cached - if (self.GetObj(fdo) is Socket s) - return s; - - var handle = self.GetPtr(fdo); - if (handle == -1) - return null; - - if (LibIkvm.Instance.io_is_socket(handle)) - { -#if NETFRAMEWORK - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var protocolInfo = new byte[sizeof(NativeWindows.WSAPROTOCOL_INFOW)]; - fixed (byte* protocolInfoPtr = protocolInfo) - { - var result = NativeWindows.WSADuplicateSocket((IntPtr)handle, Process.GetCurrentProcess().Id, (NativeWindows.WSAPROTOCOL_INFOW*)protocolInfoPtr); - if (result != 0) - throw new Win32Exception(NativeWindows.WSAGetLastError()); - } - - self.SetObj(fdo, s = new Socket(new SocketInformation() { ProtocolInformation = protocolInfo })); - return s; - } - else - { - throw new PlatformNotSupportedException(); - } -#else - self.SetObj(fdo, s = new Socket(new SafeSocketHandle((IntPtr)LibIkvm.Instance.io_duplicate_socket(handle), true))); - return s; -#endif - } - - throw new InvalidOperationException(); - } - } - - } - -#endif - -} diff --git a/src/IKVM.Runtime/Accessors/Java/Io/UnixFileSystemAccessor.cs b/src/IKVM.Runtime/Accessors/Java/Io/UnixFileSystemAccessor.cs new file mode 100644 index 0000000000..c56b22cfc2 --- /dev/null +++ b/src/IKVM.Runtime/Accessors/Java/Io/UnixFileSystemAccessor.cs @@ -0,0 +1,28 @@ +using System; + +namespace IKVM.Runtime.Accessors.Java.Io +{ + +#if FIRST_PASS == false && EXPORTER == false && IMPORTER == false + + /// + /// Provides runtime access to the 'java.io.UnixFileSystem' type. + /// + internal sealed class UnixFileSystemAccessor : Accessor + { + + /// + /// Initializes a new instance. + /// + /// + public UnixFileSystemAccessor(AccessorTypeResolver resolver) : + base(resolver, "java.io.UnixFileSystem") + { + + } + + } + +#endif + +} diff --git a/src/IKVM.Runtime/Accessors/Java/Io/WinNTFileSystemAccessor.cs b/src/IKVM.Runtime/Accessors/Java/Io/WinNTFileSystemAccessor.cs new file mode 100644 index 0000000000..69c7494352 --- /dev/null +++ b/src/IKVM.Runtime/Accessors/Java/Io/WinNTFileSystemAccessor.cs @@ -0,0 +1,28 @@ +using System; + +namespace IKVM.Runtime.Accessors.Java.Io +{ + +#if FIRST_PASS == false && EXPORTER == false && IMPORTER == false + + /// + /// Provides runtime access to the 'java.io.WinNTFileSystem' type. + /// + internal sealed class WinNTFileSystemAccessor : Accessor + { + + /// + /// Initializes a new instance. + /// + /// + public WinNTFileSystemAccessor(AccessorTypeResolver resolver) : + base(resolver, "java.io.WinNTFileSystem") + { + + } + + } + +#endif + +} diff --git a/src/IKVM.Runtime/Accessors/Java/Lang/UNIXProcessAccessor.cs b/src/IKVM.Runtime/Accessors/Java/Lang/UNIXProcessAccessor.cs new file mode 100644 index 0000000000..a3599dc721 --- /dev/null +++ b/src/IKVM.Runtime/Accessors/Java/Lang/UNIXProcessAccessor.cs @@ -0,0 +1,26 @@ +namespace IKVM.Runtime.Accessors.Java.Lang +{ + +#if FIRST_PASS == false && EXPORTER == false && IMPORTER == false + + /// + /// Provides runtime access to the 'java.lang.UNIXProcess' type. + /// + internal sealed class UNIXProcessAccessor : Accessor + { + + /// + /// Initializes a new instance. + /// + /// + public UNIXProcessAccessor(AccessorTypeResolver resolver) : + base(resolver, "java.lang.UNIXProcess") + { + + } + + } + +#endif + +} diff --git a/src/IKVM.Runtime/Annotation.cs b/src/IKVM.Runtime/Annotation.cs index 19751b2062..90edf7634a 100644 --- a/src/IKVM.Runtime/Annotation.cs +++ b/src/IKVM.Runtime/Annotation.cs @@ -25,6 +25,8 @@ Jeroen Frijters using System.Diagnostics; using IKVM.Attributes; +using System.Linq; + #if IMPORTER || EXPORTER using IKVM.Reflection; @@ -34,6 +36,8 @@ Jeroen Frijters using System.Collections; using System.Collections.Generic; +using System.Linq; + #else using System.Reflection; using System.Reflection.Emit; @@ -58,7 +62,8 @@ internal static Annotation LoadAssemblyCustomAttribute(RuntimeClassLoader loader if (object.Equals(def[0], AnnotationDefaultAttribute.TAG_ANNOTATION) == false) throw new InternalException("LoadAssemblyCustomAttribute did not receive AnnotationDefaultAttribute.TAG_ANNOTATION."); - string annotationClass = (string)def[1]; + var annotationClass = (string)def[1]; + if (ClassFile.IsValidFieldSig(annotationClass)) { try @@ -70,6 +75,7 @@ internal static Annotation LoadAssemblyCustomAttribute(RuntimeClassLoader loader } } + return null; } @@ -208,6 +214,7 @@ internal static bool HasRetentionPolicyRuntime(object[] annotations) } } } + return false; } @@ -223,6 +230,7 @@ internal static bool HasObsoleteAttribute(object[] annotations) } } } + return false; } diff --git a/src/IKVM.Runtime/AttributeHelper.cs b/src/IKVM.Runtime/AttributeHelper.cs index 1f6f46ce65..c5d102f561 100644 --- a/src/IKVM.Runtime/AttributeHelper.cs +++ b/src/IKVM.Runtime/AttributeHelper.cs @@ -420,6 +420,12 @@ internal void SetCompilerGenerated(TypeBuilder tb) tb.SetCustomAttribute(compilerGeneratedAttribute); } + internal void SetCompilerGenerated(MethodBuilder mb) + { + compilerGeneratedAttribute ??= new CustomAttributeBuilder(context.Resolver.ResolveCoreType(typeof(CompilerGeneratedAttribute).FullName).GetConstructor(Type.EmptyTypes), Array.Empty()); + mb.SetCustomAttribute(compilerGeneratedAttribute); + } + internal void SetEditorBrowsableNever(TypeBuilder tb) { tb.SetCustomAttribute(GetEditorBrowsableNever()); diff --git a/src/IKVM.Runtime/ClassFile.FieldOrMethod.cs b/src/IKVM.Runtime/ClassFile.FieldOrMethod.cs index 718ab0a715..f780a9f4f2 100644 --- a/src/IKVM.Runtime/ClassFile.FieldOrMethod.cs +++ b/src/IKVM.Runtime/ClassFile.FieldOrMethod.cs @@ -44,6 +44,7 @@ internal abstract class FieldOrMethod : IEquatable protected string signature; protected object[] annotations; protected IReadOnlyList runtimeVisibleTypeAnnotations; + protected IReadOnlyList runtimeInvisibleTypeAnnotations; /// /// Initializes a new instance. @@ -101,6 +102,8 @@ internal FieldOrMethod(ClassFile classFile, string[] utf8_cp, AccessFlag accessF internal bool IsInternal => (flags & FLAG_MASK_INTERNAL) != 0; + internal bool IsModuleInitializer => (flags & FLAG_MODULE_INITIALIZER) != 0; + internal IReadOnlyList RuntimeVisibleTypeAnnotations => runtimeVisibleTypeAnnotations; public sealed override int GetHashCode() => name.GetHashCode() ^ descriptor.GetHashCode(); diff --git a/src/IKVM.Runtime/ClassFile.Method.cs b/src/IKVM.Runtime/ClassFile.Method.cs index 42d4a91af4..84f19e9fb9 100644 --- a/src/IKVM.Runtime/ClassFile.Method.cs +++ b/src/IKVM.Runtime/ClassFile.Method.cs @@ -215,6 +215,17 @@ internal Method(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions opt low ??= new LowFreqData(); low.InterlockedCompareAndSetField = field; } + } + else if (annot[1].Equals("Likvm/lang/ModuleInitializer;")) + { + if (classFile.IsInterface || IsConstructor || IsClassInitializer || IsPrivate || IsStatic == false) + { + classFile.context.StaticCompiler.IssueMessage(Message.ModuleInitializerMethodRequirements, classFile.Name, Name, Signature); + } + else + { + flags |= FLAG_MODULE_INITIALIZER; + } } } diff --git a/src/IKVM.Runtime/ClassFile.cs b/src/IKVM.Runtime/ClassFile.cs index 6d723acd90..e57506c789 100644 --- a/src/IKVM.Runtime/ClassFile.cs +++ b/src/IKVM.Runtime/ClassFile.cs @@ -43,6 +43,7 @@ sealed partial class ClassFile const ushort FLAG_LAMBDAFORM_HIDDEN = 0x1000; const ushort FLAG_FORCEINLINE = 0x2000; const ushort FLAG_HAS_ASSERTIONS = 0x4000; + const ushort FLAG_MODULE_INITIALIZER = 0x8000; readonly RuntimeContext context; readonly ClassReader reader; diff --git a/src/IKVM.Runtime/Extensions/ModuleInitializerAttribute.cs b/src/IKVM.Runtime/Extensions/ModuleInitializerAttribute.cs index ddc25391ea..7245e78508 100644 --- a/src/IKVM.Runtime/Extensions/ModuleInitializerAttribute.cs +++ b/src/IKVM.Runtime/Extensions/ModuleInitializerAttribute.cs @@ -4,7 +4,7 @@ namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - public sealed class ModuleInitializerAttribute : Attribute + sealed class ModuleInitializerAttribute : Attribute { diff --git a/src/IKVM.Runtime/JNI/JNIEnv.cs b/src/IKVM.Runtime/JNI/JNIEnv.cs index 8ebe07bb0a..abd2c0165d 100644 --- a/src/IKVM.Runtime/JNI/JNIEnv.cs +++ b/src/IKVM.Runtime/JNI/JNIEnv.cs @@ -1474,16 +1474,13 @@ internal static jobjectArray NewObjectArray(JNIEnv* pEnv, jsize len, jclass claz try { // we want to support (non-primitive) value types so we can't cast to object[] - Array array = Array.CreateInstance(RuntimeJavaType.FromClass((java.lang.Class)pEnv->UnwrapRef(clazz)).TypeAsArrayType, len); - object o = pEnv->UnwrapRef(init); + var a = Array.CreateInstance(RuntimeJavaType.FromClass((java.lang.Class)pEnv->UnwrapRef(clazz)).TypeAsArrayType, len); + var o = pEnv->UnwrapRef(init); if (o != null) - { - for (int i = 0; i < array.Length; i++) - { - array.SetValue(o, i); - } - } - return pEnv->MakeLocalRef(array); + for (int i = 0; i < a.Length; i++) + a.SetValue(o, i); + + return pEnv->MakeLocalRef(a); } catch (ArgumentOutOfRangeException) { diff --git a/src/IKVM.Runtime/JNI/JNIVM.cs b/src/IKVM.Runtime/JNI/JNIVM.cs index a3864ed982..fb3fd0ed58 100644 --- a/src/IKVM.Runtime/JNI/JNIVM.cs +++ b/src/IKVM.Runtime/JNI/JNIVM.cs @@ -35,7 +35,7 @@ namespace IKVM.Runtime.JNI using jsize = System.Int32; - public sealed unsafe partial class JNIVM + sealed unsafe partial class JNIVM { static readonly MUTF8Encoding MUTF8 = MUTF8Encoding.GetMUTF8(52); @@ -49,20 +49,6 @@ public sealed unsafe partial class JNIVM static readonly Encoding platformEncoding = CodePagesEncodingProvider.Instance.GetEncoding(0); #endif - static readonly LibJvm.JNI_GetDefaultJavaVMInitArgsFunc JNI_GetDefaultJavaVMInitArgs = GetDefaultJavaVMInitArgs; - static readonly LibJvm.JNI_GetCreatedJavaVMsFunc JNI_GetCreatedJavaVMs = GetCreatedJavaVMs; - static readonly LibJvm.JNI_CreateJavaVMFunc JNI_CreateJavaVM = CreateJavaVM; - - /// - /// Initializes the static instance. - /// - static JNIVM() - { - LibJvm.Instance.Set_JNI_GetDefaultJavaVMInitArgs(JNI_GetDefaultJavaVMInitArgs); - LibJvm.Instance.Set_JNI_GetCreatedJavaVMs(JNI_GetCreatedJavaVMs); - LibJvm.Instance.Set_JNI_CreateJavaVM(JNI_CreateJavaVM); - } - internal static bool IsSupportedJNIVersion(int version) { return version == JNIEnv.JNI_VERSION_1_1 @@ -91,7 +77,7 @@ static string DecodePlatformString(byte* psz) /// /// /// - static int CreateJavaVM(JavaVM** p_vm, void** p_env, void* vm_args) + public static int CreateJavaVM(JavaVM** p_vm, void** p_env, void* vm_args) { var pInitArgs = (JavaVMInitArgs*)vm_args; @@ -144,7 +130,7 @@ static int CreateJavaVM(JavaVM** p_vm, void** p_env, void* vm_args) /// /// /// - static int GetDefaultJavaVMInitArgs(void* vm_args) + public static int GetDefaultJavaVMInitArgs(void* vm_args) { // This is only used for JDK 1.1 JavaVMInitArgs, and we don't support those. return JNIEnv.JNI_ERR; @@ -157,7 +143,7 @@ static int GetDefaultJavaVMInitArgs(void* vm_args) /// /// /// - static int GetCreatedJavaVMs(JavaVM** ppvmBuf, jsize bufLen, jsize* nVMs) + public static int GetCreatedJavaVMs(JavaVM** ppvmBuf, jsize bufLen, jsize* nVMs) { if (jvmCreated) { diff --git a/src/IKVM.Runtime/JVM.Properties.cs b/src/IKVM.Runtime/JVM.Properties.cs index 95f2f278c7..93f5451753 100644 --- a/src/IKVM.Runtime/JVM.Properties.cs +++ b/src/IKVM.Runtime/JVM.Properties.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; -using System.Reflection; +using System.Linq; using System.Runtime.InteropServices; using System.Security; using System.Text; @@ -51,21 +51,36 @@ public static class Properties internal static string HomePath => homePath.Value; /// - /// Gets the set of properties loaded from any companion 'ikvm.properties' file. + /// Gets the search paths to examine for ikvm.properties. + /// + /// + static IEnumerable GetIkvmSearchDirs() + { + if (AppContext.BaseDirectory is string baseDir && !string.IsNullOrEmpty(baseDir)) + yield return baseDir; + if (typeof(Properties).Assembly.Location is string runtimePath && !string.IsNullOrEmpty(runtimePath)) + yield return Path.GetDirectoryName(runtimePath); + } + + /// + /// Gets the set of properties loaded from any companion 'ikvm.properties' file. /// /// static Dictionary GetIkvmProperties() { var props = new Dictionary(); - // the runtime assembly will set the root of various relative paths - var runtimePath = Path.GetDirectoryName(typeof(JVM).Assembly.Location); - try { - var ikvmPropertiesPath = Path.Combine(runtimePath, "ikvm.properties"); - if (File.Exists(ikvmPropertiesPath)) - LoadProperties(File.ReadAllLines(ikvmPropertiesPath), props); + foreach (var searchDir in GetIkvmSearchDirs()) + { + var ikvmPropertiesPath = Path.Combine(searchDir, "ikvm.properties"); + if (File.Exists(ikvmPropertiesPath)) + { + LoadProperties(File.ReadAllLines(ikvmPropertiesPath), props); + break; + } + } } catch (Exception) { @@ -81,45 +96,52 @@ static Dictionary GetIkvmProperties() /// static string GetHomePath() { - var rootPath = Path.GetDirectoryName(typeof(JVM).Assembly.Location); - -#if NETFRAMEWORK - // attempt to find settings in legacy app.config - try - { - // specified home directory - if (ConfigurationManager.AppSettings["ikvm:ikvm.home"] is string confHome) - return Path.GetFullPath(Path.Combine(rootPath, confHome)); - - // specified home root directory - if (ConfigurationManager.AppSettings["ikvm:ikvm.home.root"] is string confHomeRoot) - if (ResolveHomePathFromRoot(Path.Combine(rootPath, confHomeRoot)) is string confHomePath) - return confHomePath; - } - catch (ConfigurationException) + foreach (var searchDir in GetIkvmSearchDirs()) { - // app.config is invalid, ignore - } +#if NETFRAMEWORK + // attempt to find settings in legacy app.config + try + { + // specified home directory + if (ConfigurationManager.AppSettings["ikvm:ikvm.home"] is string confHome) + if (Directory.Exists(Path.GetFullPath(Path.Combine(searchDir, confHome)))) + return Path.GetFullPath(Path.Combine(searchDir, confHome)); + + // specified home root directory + if (ConfigurationManager.AppSettings["ikvm:ikvm.home.root"] is string confHomeRoot) + if (ResolveHomePathFromRoot(Path.Combine(searchDir, confHomeRoot)) is string confHomePath) + return confHomePath; + } + catch (ConfigurationException) + { + // app.config is invalid, ignore + } #endif - // user value takes priority - if (User.TryGetValue("ikvm.home", out var homePath1)) - return Path.GetFullPath(Path.Combine(rootPath, homePath1)); + // user value takes priority + if (User.TryGetValue("ikvm.home", out var homePath1)) + if (Directory.Exists(Path.GetFullPath(Path.Combine(searchDir, homePath1)))) + return Path.GetFullPath(Path.Combine(searchDir, homePath1)); + + // ikvm properties value comes next + if (Ikvm.TryGetValue("ikvm.home", out var homePath2)) + if (Directory.Exists(Path.GetFullPath(Path.Combine(searchDir, homePath2)))) + return Path.GetFullPath(Path.Combine(searchDir, homePath2)); - // ikvm properties value comes next - if (Ikvm.TryGetValue("ikvm.home", out var homePath2)) - return Path.GetFullPath(Path.Combine(rootPath, homePath2)); + // find first occurance of home root + if (User.TryGetValue("ikvm.home.root", out var homePathRoot) == false) + Ikvm.TryGetValue("ikvm.home.root", out homePathRoot); - // find first occurance of home root - if (User.TryGetValue("ikvm.home.root", out var homePathRoot) == false) - Ikvm.TryGetValue("ikvm.home.root", out homePathRoot); + // attempt to resolve the path from the given root + if (ResolveHomePathFromRoot(Path.GetFullPath(Path.Combine(searchDir, homePathRoot ?? "ikvm"))) is string resolvedHomePath) + return resolvedHomePath; - // attempt to resolve the path from the given root - if (ResolveHomePathFromRoot(Path.GetFullPath(Path.Combine(rootPath, homePathRoot ?? "ikvm"))) is string resolvedHomePath) - return resolvedHomePath; + // fallback to local 'ikvm' directory + if (Directory.Exists(Path.GetFullPath(Path.Combine(searchDir, "ikvm")))) + return Path.GetFullPath(Path.Combine(searchDir, "ikvm")); + } - // fallback to local 'ikvm' directory next to IKVM.Runtime - return Path.GetFullPath(Path.Combine(rootPath, "ikvm")); + throw new InternalException("Could not locate ikvm home path."); } /// @@ -266,6 +288,10 @@ static Dictionary GetInitProperties() p["java.awt.headless"] = "true"; p["sun.nio.MaxDirectMemorySize"] = "-1"; + // default to FORK on OSX, instead of posix_spawn with jspawnhelper + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + p["jdk.lang.Process.launchMechanism"] = "FORK"; + // cacerts is mounted by the VFS into ikvmHome p.Add("javax.net.ssl.trustStore", Path.Combine(HomePath, "lib", "security", "cacerts")); @@ -628,7 +654,8 @@ static string GetLibraryPath() var path = SafeGetEnvironmentVariable("PATH"); if (path != null) - libraryPath.Add(path); + foreach (var i in path.Split(Path.PathSeparator)) + libraryPath.Add(i); } if (RuntimeUtil.IsLinux) @@ -642,7 +669,8 @@ static string GetLibraryPath() // prefix with LD_LIBRARY_PATH var ld_library_path = SafeGetEnvironmentVariable("LD_LIBRARY_PATH"); if (ld_library_path != null) - libraryPath.Insert(0, ld_library_path); + foreach (var i in ld_library_path.Split(Path.PathSeparator).Reverse()) + libraryPath.Insert(0, i); } if (RuntimeUtil.IsOSX) @@ -659,12 +687,14 @@ static string GetLibraryPath() // prefix with JAVA_LIBRARY_PATH var javaLibraryPath = SafeGetEnvironmentVariable("JAVA_LIBRARY_PATH"); if (javaLibraryPath != null) - libraryPath.Add(javaLibraryPath); + foreach (var i in javaLibraryPath.Split(Path.PathSeparator)) + libraryPath.Add(i); // prefix with DYLD_LIBRARY_PATH var dyldLibraryPath = SafeGetEnvironmentVariable("DYLD_LIBRARY_PATH"); if (dyldLibraryPath != null) - libraryPath.Add(dyldLibraryPath); + foreach (var i in dyldLibraryPath.Split(Path.PathSeparator)) + libraryPath.Add(i); if (home != null) libraryPath.Add(home); @@ -674,12 +704,14 @@ static string GetLibraryPath() try { - // append relative .NET search paths from IKVM.Java assembly - var s = Path.GetDirectoryName(Context.Resolver.ResolveBaseAssembly().Location); - var l = new List() { s }; + var l = new List(); - foreach (var rid in RuntimeUtil.SupportedRuntimeIdentifiers) - l.Add(Path.Combine(s, "runtimes", rid, "native")); + foreach (var d in GetIkvmSearchDirs()) + { + l.Add(d); + foreach (var rid in RuntimeUtil.SupportedRuntimeIdentifiers) + l.Add(Path.Combine(d, "runtimes", rid, "native")); + } libraryPath.InsertRange(0, l); } @@ -691,7 +723,7 @@ static string GetLibraryPath() if (RuntimeUtil.IsWindows) libraryPath.Add("."); - return string.Join(Path.PathSeparator.ToString(), libraryPath); + return string.Join(Path.PathSeparator.ToString(), libraryPath.Distinct()); #endif } diff --git a/src/IKVM.Runtime/JVM.Resolver.cs b/src/IKVM.Runtime/JVM.Resolver.cs index 2f0b427fc9..f8134e9748 100644 --- a/src/IKVM.Runtime/JVM.Resolver.cs +++ b/src/IKVM.Runtime/JVM.Resolver.cs @@ -71,7 +71,7 @@ Type ResolveCoreTypeImpl(string typeName) /// public Type ResolveRuntimeType(string typeName) { - return typeof(JVM).Assembly.GetType(typeName); + return typeof(Resolver).Assembly.GetType(typeName); } } diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/media/sound/JDK13Services.cs b/src/IKVM.Runtime/Java/Externs/com/sun/media/sound/JDK13Services.cs deleted file mode 100644 index 808a756cef..0000000000 --- a/src/IKVM.Runtime/Java/Externs/com/sun/media/sound/JDK13Services.cs +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright (C) 2007-2015 Jeroen Frijters - Copyright (C) 2009 Volker Berlin (i-net software) - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -namespace IKVM.Java.Externs.com.sun.media.sound -{ - - static class JDK13Services - { - - public static string getDefaultProviderClassName(object deviceClass) - { - return null; - } - - public static string getDefaultInstanceName(object deviceClass) - { - return null; - } - - public static object getProviders(object providerClass) - { -#if FIRST_PASS - return null; -#else - return new global::java.util.ArrayList(); -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/security/auth/module/NTSystem.cs b/src/IKVM.Runtime/Java/Externs/com/sun/security/auth/module/NTSystem.cs deleted file mode 100644 index 343e2d7319..0000000000 --- a/src/IKVM.Runtime/Java/Externs/com/sun/security/auth/module/NTSystem.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright (C) 2007-2015 Jeroen Frijters - Copyright (C) 2009 Volker Berlin (i-net software) - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System.Security.Principal; - -namespace IKVM.Java.Externs.com.sun.security.auth.module -{ - - static class NTSystem - { - - public static void getCurrent(object thisObj, bool debug, ref string userName, ref string domain, ref string domainSID, ref string userSID, ref string[] groupIDs, ref string primaryGroupID) - { - WindowsIdentity id = WindowsIdentity.GetCurrent(); - string[] name = id.Name.Split('\\'); - userName = name[1]; - domain = name[0]; - domainSID = id.User.AccountDomainSid.Value; - userSID = id.User.Value; - string[] groups = new string[id.Groups.Count]; - for (int i = 0; i < groups.Length; i++) - { - groups[i] = id.Groups[i].Value; - } - groupIDs = groups; - // HACK it turns out that Groups[0] is the primary group, but AFAIK this is not documented anywhere - primaryGroupID = groups[0]; - } - - public static long getImpersonationToken0(object thisObj) - { - return WindowsIdentity.GetCurrent().Token.ToInt64(); - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/java/io/FileDescriptor.cs b/src/IKVM.Runtime/Java/Externs/java/io/FileDescriptor.cs index f404913b63..f05001e304 100644 --- a/src/IKVM.Runtime/Java/Externs/java/io/FileDescriptor.cs +++ b/src/IKVM.Runtime/Java/Externs/java/io/FileDescriptor.cs @@ -1,6 +1,5 @@ using System; -using System.IO; -using System.Net.Sockets; +using System.Runtime.InteropServices; using IKVM.Runtime; using IKVM.Runtime.Accessors.Java.Io; @@ -23,35 +22,7 @@ static class FileDescriptor #endif /// - /// Implements the native method 'getStream'. - /// - /// - /// - public static Stream getStream(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return FileDescriptorAccessor.GetStream(self); -#endif - } - - /// - /// Implements the native method 'getSocket'. - /// - /// - /// - public static Socket getSocket(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return FileDescriptorAccessor.GetSocket(self); -#endif - } - - /// - /// Sets the underlying pointer object. If the pointer value changes, any existing cached object is removed. + /// Sets the underlying pointer object. Disposes any associated stream. /// /// /// @@ -65,11 +36,11 @@ static void SetPtr(object self, long ptr) var p = FileDescriptorAccessor.GetPtr(self); if (p != ptr || ptr == -1) { - var obj = (IDisposable)FileDescriptorAccessor.GetObj(self); - if (obj != null) + var stream = (IDisposable)FileDescriptorAccessor.GetStream(self); + if (stream != null) { - obj.Dispose(); - FileDescriptorAccessor.SetObj(self, null); + stream.Dispose(); + FileDescriptorAccessor.SetStream(self, null); } } @@ -138,21 +109,34 @@ public static object standardStream(int fd) #if FIRST_PASS throw new NotImplementedException(); #else - var stream = fd switch - { - 0 => System.Console.OpenStandardInput(), - 1 => System.Console.OpenStandardOutput(), - 2 => System.Console.OpenStandardError(), - _ => throw new NotImplementedException(), - }; - var fdo = FileDescriptorAccessor.Init(); - FileDescriptorAccessor.SetPtr(fdo, fd); - FileDescriptorAccessor.SetObj(fdo, stream); + FileDescriptorAccessor.SetPtr(fdo, GetStandardHandle(fd)); return fdo; #endif } - } + [DllImport("Kernel32")] + static extern IntPtr GetStdHandle(int nStdHandle); + + /// + /// Gets the standard handle for the given fd index. + /// + /// + /// + static long GetStandardHandle(int fd) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (fd == 0) + return (long)GetStdHandle(-10); + else if (fd == 1) + return (long)GetStdHandle(-11); + else if (fd == 2) + return (long)GetStdHandle(-12); + } + + return fd; + } -} + } +} \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/java/io/FileInputStream.cs b/src/IKVM.Runtime/Java/Externs/java/io/FileInputStream.cs index 65133f02ef..61d1566a46 100644 --- a/src/IKVM.Runtime/Java/Externs/java/io/FileInputStream.cs +++ b/src/IKVM.Runtime/Java/Externs/java/io/FileInputStream.cs @@ -44,9 +44,9 @@ static class FileInputStream /// /// Implements the native method 'open0'. /// - /// + /// /// - public static void open0(object this_, string path) + public static void open0(object self, string path) { #if FIRST_PASS throw new NotImplementedException(); @@ -55,10 +55,11 @@ public static void open0(object this_, string path) { try { - var fd = FileInputStreamAccessor.GetFd(this_); + var fd = FileInputStreamAccessor.GetFd(self); if (fd == null) throw new global::java.io.IOException("The handle is invalid."); + FileDescriptorAccessor.SetPtr(fd, -1); FileDescriptorAccessor.SetStream(fd, JVM.Vfs.Open(path, FileMode.Open, FileAccess.Read)); } catch (ObjectDisposedException e) @@ -94,7 +95,7 @@ public static void open0(object this_, string path) var jniEnv = jniFrm.Enter(__callerID); try { - __jniPtr__open0(jniEnv, jniFrm.MakeLocalRef(this_), jniFrm.MakeLocalRef(path)); + __jniPtr__open0(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(path)); } catch (Exception ex) { @@ -113,22 +114,18 @@ public static void open0(object this_, string path) /// /// Implements the native method 'read0'. /// - /// + /// /// - public static int read0(object this_) + public static int read0(object self) { #if FIRST_PASS throw new NotImplementedException(); #else - var fd = FileInputStreamAccessor.GetFd(this_); + var fd = FileInputStreamAccessor.GetFd(self); if (fd == null) throw new global::java.io.IOException("The handle is invalid."); - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - - if (stream is not FileStream fs) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { if (stream.CanRead == false) throw new global::java.io.IOException("Read failed."); @@ -158,7 +155,7 @@ public static int read0(object this_) var jniEnv = jniFrm.Enter(__callerID); try { - return __jniPtr__read0(jniEnv, jniFrm.MakeLocalRef(this_)); + return __jniPtr__read0(jniEnv, jniFrm.MakeLocalRef(self)); } catch (Exception ex) { @@ -177,25 +174,21 @@ public static int read0(object this_) /// /// Implements the native method 'readBytes'. /// - /// + /// /// /// /// /// - public static int readBytes(object this_, byte[] bytes, int off, int len) + public static int readBytes(object self, byte[] bytes, int off, int len) { #if FIRST_PASS throw new NotImplementedException(); #else - var fd = FileInputStreamAccessor.GetFd(this_); + var fd = FileInputStreamAccessor.GetFd(self); if (fd == null) throw new global::java.io.IOException("The handle is invalid."); - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - - if (stream is not FileStream fs) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { if (len == 0) return 0; @@ -232,7 +225,7 @@ public static int readBytes(object this_, byte[] bytes, int off, int len) var jniEnv = jniFrm.Enter(__callerID); try { - return __jniPtr__readBytes(jniEnv, jniFrm.MakeLocalRef(this_), jniFrm.MakeLocalRef(bytes), off, len); + return __jniPtr__readBytes(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(bytes), off, len); } catch (Exception ex) { @@ -251,23 +244,19 @@ public static int readBytes(object this_, byte[] bytes, int off, int len) /// /// Implements the native method 'skip0'. /// - /// + /// /// /// - public static long skip0(object this_, long n) + public static long skip0(object self, long n) { #if FIRST_PASS throw new NotImplementedException(); #else - var fd = FileInputStreamAccessor.GetFd(this_); + var fd = FileInputStreamAccessor.GetFd(self); if (fd == null) throw new global::java.io.IOException("The handle is invalid."); - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - - if (stream is not FileStream fs) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { if (stream.CanSeek == false) throw new global::java.io.IOException("The handle is invalid."); @@ -299,7 +288,7 @@ public static long skip0(object this_, long n) var jniEnv = jniFrm.Enter(__callerID); try { - return __jniPtr__skip0(jniEnv, jniFrm.MakeLocalRef(this_), n); + return __jniPtr__skip0(jniEnv, jniFrm.MakeLocalRef(self), n); } catch (Exception ex) { @@ -318,22 +307,18 @@ public static long skip0(object this_, long n) /// /// Implements the native method 'available0'. /// - /// + /// /// - public static int available0(object this_) + public static int available0(object self) { #if FIRST_PASS throw new NotImplementedException(); #else - var fd = FileInputStreamAccessor.GetFd(this_); + var fd = FileInputStreamAccessor.GetFd(self); if (fd == null) throw new global::java.io.IOException("The handle is invalid."); - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - - if (stream is not FileStream fs) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { if (stream.CanSeek == false) return 0; @@ -363,7 +348,7 @@ public static int available0(object this_) var jniEnv = jniFrm.Enter(__callerID); try { - return __jniPtr__available0(jniEnv, jniFrm.MakeLocalRef(this_)); + return __jniPtr__available0(jniEnv, jniFrm.MakeLocalRef(self)); } catch (Exception ex) { @@ -382,23 +367,22 @@ public static int available0(object this_) /// /// Implements the native method 'close0'. /// - /// - public static void close0(object this_) + /// + public static void close0(object self) { #if FIRST_PASS throw new NotImplementedException(); #else - var fd = FileInputStreamAccessor.GetFd(this_); + var fd = FileInputStreamAccessor.GetFd(self); if (fd == null) throw new global::java.io.IOException("The handle is invalid."); - - if (FileDescriptorAccessor.GetObj(fd) is not null and not FileStream) + + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { try { - var h = FileDescriptorAccessor.GetHandle(fd); - FileDescriptorAccessor.SetHandle(fd, -1); - LibIkvm.Instance.io_close_file(h); + stream.Close(); + FileDescriptorAccessor.SetPtr(fd, -1); } catch { @@ -413,7 +397,7 @@ public static void close0(object this_) var jniEnv = jniFrm.Enter(__callerID); try { - __jniPtr__close0(jniEnv, jniFrm.MakeLocalRef(this_)); + __jniPtr__close0(jniEnv, jniFrm.MakeLocalRef(self)); } catch (Exception ex) { diff --git a/src/IKVM.Runtime/Java/Externs/java/io/FileOutputStream.cs b/src/IKVM.Runtime/Java/Externs/java/io/FileOutputStream.cs index 78a7e83c83..29cb30a013 100644 --- a/src/IKVM.Runtime/Java/Externs/java/io/FileOutputStream.cs +++ b/src/IKVM.Runtime/Java/Externs/java/io/FileOutputStream.cs @@ -54,7 +54,8 @@ public static void open0(object this_, string path, bool append) if (fd == null) throw new global::java.io.IOException("The handle is invalid."); - FileDescriptorAccessor.SetObj(fd, JVM.Vfs.Open(path, append ? FileMode.Append : FileMode.Create, FileAccess.Write)); + FileDescriptorAccessor.SetPtr(fd, -1); + FileDescriptorAccessor.SetStream(fd, JVM.Vfs.Open(path, append ? FileMode.Append : FileMode.Create, FileAccess.Write)); } catch (ObjectDisposedException e) { @@ -110,23 +111,19 @@ public static void open0(object this_, string path, bool append) /// /// Implements the native method 'write'. /// - /// + /// /// /// - public static void write(object this_, int byte_, bool append) + public static void write(object self, int byte_, bool append) { #if FIRST_PASS throw new NotImplementedException(); #else - var fd = FileOutputStreamAccessor.GetFd(this_); + var fd = FileOutputStreamAccessor.GetFd(self); if (fd == null) throw new global::java.io.IOException("The handle is invalid."); - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - - if (stream is not FileStream fs) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { if (stream.CanWrite == false) throw new global::java.io.IOException("The handle is invalid."); @@ -157,7 +154,7 @@ public static void write(object this_, int byte_, bool append) var jniEnv = jniFrm.Enter(__callerID); try { - var selfRef = jniFrm.MakeLocalRef(this_); + var selfRef = jniFrm.MakeLocalRef(self); __jniPtr__write(jniEnv, selfRef, byte_, append ? JNIEnv.JNI_TRUE : JNIEnv.JNI_FALSE); } catch (Exception ex) @@ -177,25 +174,21 @@ public static void write(object this_, int byte_, bool append) /// /// Implements the native method 'writeBytes'. /// - /// + /// /// /// /// /// - public static void writeBytes(object this_, byte[] bytes, int off, int len, bool append) + public static void writeBytes(object self, byte[] bytes, int off, int len, bool append) { #if FIRST_PASS throw new NotImplementedException(); #else - var fd = FileOutputStreamAccessor.GetFd(this_); + var fd = FileOutputStreamAccessor.GetFd(self); if (fd == null) throw new global::java.io.IOException("The handle is invalid."); - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - - if (stream is not FileStream fs) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { if ((off < 0) || (off > bytes.Length) || (len < 0) || (len > (bytes.Length - off))) throw new global::java.lang.IndexOutOfBoundsException(); @@ -229,7 +222,7 @@ public static void writeBytes(object this_, byte[] bytes, int off, int len, bool var jniEnv = jniFrm.Enter(__callerID); try { - __jniPtr__writeBytes(jniEnv, jniFrm.MakeLocalRef(this_), jniFrm.MakeLocalRef(bytes), off, len, append ? JNIEnv.JNI_TRUE : JNIEnv.JNI_FALSE); + __jniPtr__writeBytes(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(bytes), off, len, append ? JNIEnv.JNI_TRUE : JNIEnv.JNI_FALSE); } catch (Exception ex) { @@ -257,14 +250,13 @@ public static void close0(object this_) var fd = FileOutputStreamAccessor.GetFd(this_); if (fd == null) throw new global::java.io.IOException("The handle is invalid."); - - if (FileDescriptorAccessor.GetObj(fd) is not null and not FileStream) + + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { try { - var h = FileDescriptorAccessor.GetHandle(fd); - FileDescriptorAccessor.SetHandle(fd, -1); - LibIkvm.Instance.io_close_file(h); + stream.Close(); + FileDescriptorAccessor.SetPtr(fd, -1); } catch { diff --git a/src/IKVM.Runtime/Java/Externs/java/io/RandomAccessFile.cs b/src/IKVM.Runtime/Java/Externs/java/io/RandomFileAccess.cs similarity index 91% rename from src/IKVM.Runtime/Java/Externs/java/io/RandomAccessFile.cs rename to src/IKVM.Runtime/Java/Externs/java/io/RandomFileAccess.cs index bb4f0c98b3..d97d5e47b8 100644 --- a/src/IKVM.Runtime/Java/Externs/java/io/RandomAccessFile.cs +++ b/src/IKVM.Runtime/Java/Externs/java/io/RandomFileAccess.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Runtime.InteropServices; using System.Security; @@ -23,10 +23,10 @@ static unsafe class RandomAccessFile #if FIRST_PASS == false static FileDescriptorAccessor fileDescriptorAccessor; - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); + static RandomAccessFileAccessor randomAccessFileAccessor; + static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - static RandomAccessFileAccessor randomAccessFileAccessor; static RandomAccessFileAccessor RandomAccessFileAccessor => JVM.Internal.BaseAccessors.Get(ref randomAccessFileAccessor); static global::ikvm.@internal.CallerID __callerID; @@ -89,6 +89,7 @@ public static void open0(object self, string name, int mode) if ((mode & O_RDWR) == O_RDWR) fileAccess |= FileAccess.ReadWrite; + FileDescriptorAccessor.SetPtr(fd, -1); FileDescriptorAccessor.SetStream(fd, JVM.Vfs.Open(name, fileMode, fileAccess)); return; } @@ -155,11 +156,8 @@ public static int read0(object self) if (fd == null) throw new global::java.io.IOException("Invalid file handle."); - if (FileDescriptorAccessor.GetObj(fd) is not null and not FileStream) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); if (stream.CanRead == false) throw new global::java.io.IOException("Read failed."); @@ -222,7 +220,7 @@ public static int readBytes(object self, byte[] bytes, int off, int len) if (fd == null) throw new global::java.io.IOException("Invalid file handle."); - if (FileDescriptorAccessor.GetObj(fd) is not null and not FileStream) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { if (bytes == null) throw new global::java.lang.NullPointerException(); @@ -233,9 +231,6 @@ public static int readBytes(object self, byte[] bytes, int off, int len) if (len == 0) return 0; - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); if (stream.CanRead == false) throw new global::java.io.IOException("Read failed."); @@ -295,11 +290,8 @@ public static void write0(object self, int @byte) if (fd == null) throw new global::java.io.IOException("Invalid file handle."); - if (FileDescriptorAccessor.GetObj(fd) is not null and not FileStream) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); if (stream.CanWrite == false) throw new global::java.io.IOException("Write failed."); @@ -360,14 +352,10 @@ public static void writeBytes(object self, byte[] bytes, int off, int len) if (fd == null) throw new global::java.io.IOException("Invalid file handle."); - if (FileDescriptorAccessor.GetObj(fd) is not null and not FileStream) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { if ((off < 0) || (off > bytes.Length) || (len < 0) || (len > (bytes.Length - off))) throw new global::java.lang.IndexOutOfBoundsException(); - - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); if (stream.CanWrite == false) throw new global::java.io.IOException("Write failed."); @@ -426,12 +414,8 @@ public static long getFilePointer(object self) if (fd == null) throw new global::java.io.IOException("Invalid file handle."); - if (FileDescriptorAccessor.GetObj(fd) is not null and not FileStream) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - try { return stream.Position; @@ -487,12 +471,8 @@ public static void seek0(object self, long pos) if (fd == null) throw new global::java.io.IOException("Invalid file handle."); - if (FileDescriptorAccessor.GetObj(fd) is not null and not FileStream) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - try { stream.Position = pos; @@ -552,12 +532,8 @@ public static long length(object self) if (fd == null) throw new global::java.io.IOException("Invalid file handle."); - if (FileDescriptorAccessor.GetObj(fd) is not null and not FileStream) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - try { return stream.Length; @@ -613,12 +589,8 @@ public static void setLength(object self, long newLength) if (fd == null) throw new global::java.io.IOException("Invalid file handle."); - if (FileDescriptorAccessor.GetObj(fd) is not null and not FileStream) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { - var stream = FileDescriptorAccessor.GetStream(fd); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - var p = stream.Position; try @@ -684,13 +656,12 @@ public static void close0(object self) if (fd == null) return; - if (FileDescriptorAccessor.GetObj(fd) is not null and not FileStream) + if (FileDescriptorAccessor.GetStream(fd) is Stream stream) { try { - var h = FileDescriptorAccessor.GetHandle(fd); - FileDescriptorAccessor.SetHandle(fd, -1); - LibIkvm.Instance.io_close_file(h); + stream.Close(); + FileDescriptorAccessor.SetPtr(fd, -1); } catch { @@ -723,4 +694,4 @@ public static void close0(object self) } -} +} \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/java/io/UnixFileSystem.cs b/src/IKVM.Runtime/Java/Externs/java/io/UnixFileSystem.cs index 73b44cd99b..288ef9e306 100644 --- a/src/IKVM.Runtime/Java/Externs/java/io/UnixFileSystem.cs +++ b/src/IKVM.Runtime/Java/Externs/java/io/UnixFileSystem.cs @@ -1,28 +1,13 @@ -/* - Copyright (C) 2007-2014 Jeroen Frijters +using System; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Security; - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -using System; +using IKVM.Runtime; +using IKVM.Runtime.Accessors.Java.Io; +using IKVM.Runtime.JNI; +using IKVM.Runtime.Vfs; namespace IKVM.Java.Externs.java.io { @@ -30,128 +15,635 @@ namespace IKVM.Java.Externs.java.io static class UnixFileSystem { - public static int getBooleanAttributes0(object _this, object f) +#if FIRST_PASS == false + + static UnixFileSystemAccessor unixFileSystemAccessor; + + static UnixFileSystemAccessor UnixFileSystemAccessor => JVM.Internal.BaseAccessors.Get(ref unixFileSystemAccessor); + + static global::ikvm.@internal.CallerID __callerID; + delegate IntPtr __jniDelegate__canonicalize0(IntPtr jniEnv, IntPtr self, IntPtr pathname); + static __jniDelegate__canonicalize0 __jniPtr__canonicalize0; + delegate byte __jniDelegate__delete0(IntPtr jniEnv, IntPtr self, IntPtr file); + static __jniDelegate__delete0 __jniPtr__delete0; + delegate byte __jniDelegate__rename0(IntPtr jniEnv, IntPtr self, IntPtr f1, IntPtr f2); + static __jniDelegate__rename0 __jniPtr__rename0; + delegate int __jniDelegate__getBooleanAttributes0(IntPtr jniEnv, IntPtr self, IntPtr file); + static __jniDelegate__getBooleanAttributes0 __jniPtr__getBooleanAttributes0; + delegate byte __jniDelegate__checkAccess(IntPtr jniEnv, IntPtr self, IntPtr file, int a); + static __jniDelegate__checkAccess __jniPtr__checkAccess; + delegate long __jniDelegate__getLastModifiedTime(IntPtr jniEnv, IntPtr self, IntPtr file); + static __jniDelegate__getLastModifiedTime __jniPtr__getLastModifiedTime; + delegate long __jniDelegate__getLength(IntPtr jniEnv, IntPtr self, IntPtr file); + static __jniDelegate__getLength __jniPtr__getLength; + delegate byte __jniDelegate__setPermission(IntPtr jniEnv, IntPtr self, IntPtr file, int access, byte enable, byte owneronly); + static __jniDelegate__setPermission __jniPtr__setPermission; + delegate byte __jniDelegate__createFileExclusively(IntPtr jniEnv, IntPtr self, IntPtr pathname); + static __jniDelegate__createFileExclusively __jniPtr__createFileExclusively; + delegate IntPtr __jniDelegate__list(IntPtr jniEnv, IntPtr self, IntPtr file); + static __jniDelegate__list __jniPtr__list; + delegate byte __jniDelegate__createDirectory(IntPtr jniEnv, IntPtr self, IntPtr file); + static __jniDelegate__createDirectory __jniPtr__createDirectory; + delegate byte __jniDelegate__setLastModifiedTime(IntPtr jniEnv, IntPtr self, IntPtr file, long time); + static __jniDelegate__setLastModifiedTime __jniPtr__setLastModifiedTime; + delegate byte __jniDelegate__setReadOnly(IntPtr jniEnv, IntPtr self, IntPtr f); + static __jniDelegate__setReadOnly __jniPtr__setReadOnly; + +#endif + + /// + /// Attempts to canonicalize the given path. + /// + /// + /// + static string CanonicalizePath(string path) { #if FIRST_PASS throw new NotImplementedException(); #else - return WinNTFileSystem.getBooleanAttributes(_this, (global::java.io.File)f); + try + { + // begin by processing parent element + var parent = Path.GetDirectoryName(path); + + // root paths with drive letter should have driver letter upper cased + if (parent == null) + return path.Length > 1 && path[1] == ':' ? $"{char.ToUpper(path[0])}:{Path.DirectorySeparatorChar}" : path; + else + parent = CanonicalizePath(parent); + + // trailing slash would result in a last path element of empty string + var name = Path.GetFileName(path); + if (name == "" || name == ".") + return parent; + if (name == "..") + return Path.GetDirectoryName(parent); + + try + { + if (JVM.Vfs.IsPath(path) == false) + { + // consult the file system for an actual node with the appropriate name + var all = Directory.EnumerateFileSystemEntries(parent, name); + if (all.FirstOrDefault() is string one) + name = Path.GetFileName(one); + } + } + catch (UnauthorizedAccessException) + { + + } + catch (IOException) + { + + } + + return Path.Combine(parent, name); + } + catch (UnauthorizedAccessException) + { + + } + catch (IOException) + { + + } + catch (SecurityException) + { + + } + catch (NotSupportedException) + { + + } + + return path; #endif } - public static long getSpace(object _this, object f, int t) + /// + /// Implements the native method 'canonicalize0'. + /// + /// + /// + /// + /// + public static string canonicalize0(object self, string pathname) { #if FIRST_PASS throw new NotImplementedException(); #else - return 0; + if (JVM.Vfs.IsPath(pathname)) + { + return CanonicalizePath(Path.IsPathRooted(pathname) == false ? Path.GetFullPath(pathname) : pathname); + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__canonicalize0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__canonicalize0>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(canonicalize0), "(Ljava/lang/String;)Ljava/lang/String;")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return (string)jniFrm.UnwrapLocalRef(__jniPtr__canonicalize0(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(pathname))); + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static string canonicalize0(object _this, string path) - { - return WinNTFileSystem.canonicalize0(_this, path); - } - - public static bool checkAccess(object _this, object f, int access) + /// + /// Implements the native method 'getBooleanAttributes0'. + /// + /// + /// + /// + public static int getBooleanAttributes0(object self, object file) { #if FIRST_PASS throw new NotImplementedException(); #else - return WinNTFileSystem.checkAccess(_this, (global::java.io.File)f, access); + if (JVM.Vfs.IsPath(((global::java.io.File)file).getPath())) + { + return JVM.Vfs.GetBooleanAttributes(((global::java.io.File)file).getPath()); + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__getBooleanAttributes0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__getBooleanAttributes0>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(getBooleanAttributes0), "(Ljava/io/File;)I")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__getBooleanAttributes0(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(file)); + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static long getLastModifiedTime(object _this, object f) + /// + /// Implements the native method 'checkAccess'. + /// + /// + /// + /// + /// + public static bool checkAccess(object self, object file, int a) { #if FIRST_PASS throw new NotImplementedException(); #else - return WinNTFileSystem.getLastModifiedTime(_this, (global::java.io.File)f); + if (JVM.Vfs.IsPath(((global::java.io.File)file).getPath())) + { + const int ACCESS_READ = 0x04; + return JVM.Vfs.GetEntry(((global::java.io.File)file).getPath()) switch + { + VfsFile f => a == ACCESS_READ && f.CanOpen(FileMode.Open, FileAccess.Read), + VfsDirectory => true, + _ => false, + }; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__checkAccess ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__checkAccess>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(checkAccess), "(Ljava/io/File;I)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__checkAccess(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(file), a) != 0; + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static long getLength(object _this, object f) + /// + /// Implements the native method 'setPermission'. + /// + /// + /// + /// + /// + /// + /// + public static bool setPermission(object self, object file, int access, bool enable, bool owneronly) { #if FIRST_PASS throw new NotImplementedException(); #else - return WinNTFileSystem.getLength(_this, (global::java.io.File)f); + if (JVM.Vfs.IsPath(((global::java.io.File)file).getPath())) + { + return false; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__setPermission ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__setPermission>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(setPermission), "(Ljava/io/File;IZZ)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__setPermission(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(file), access, enable ? (byte)1 : (byte)0, owneronly ? (byte)1 : (byte)0) != 0; + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static bool setPermission(object _this, object f, int access, bool enable, bool owneronly) + /// + /// Implements the native method 'getLastModifiedTime'. + /// + /// + /// + /// + public static long getLastModifiedTime(object self, object file) { #if FIRST_PASS throw new NotImplementedException(); #else - // TODO consider using Mono.Posix - return WinNTFileSystem.setPermission(_this, (global::java.io.File)f, access, enable, owneronly); + if (JVM.Vfs.IsPath(((global::java.io.File)file).getPath())) + { + return 0; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__getLastModifiedTime ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__getLastModifiedTime>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(getLastModifiedTime), "(Ljava/io/File;)J")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__getLastModifiedTime(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(file)); + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static bool createFileExclusively(object _this, string path) + /// + /// Implements the native method 'getLength'. + /// + /// + /// + /// + public static long getLength(object self, object file) { - return WinNTFileSystem.createFileExclusively(_this, path); +#if FIRST_PASS + throw new NotImplementedException(); +#else + if (JVM.Vfs.IsPath(((global::java.io.File)file).getPath())) + { + return JVM.Vfs.GetEntry(((global::java.io.File)file).getPath()) is VfsFile f ? f.Size : 0; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__getLength ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__getLength>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(getLength), "(Ljava/io/File;)J")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__getLength(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(file)); + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } +#endif } - public static bool delete0(object _this, object f) + /// + /// Implements the native method 'createFileExclusively'. + /// + /// + /// + /// + public static bool createFileExclusively(object self, string pathname) { #if FIRST_PASS throw new NotImplementedException(); #else - return WinNTFileSystem.delete0(_this, (global::java.io.File)f); + if (JVM.Vfs.IsPath(pathname)) + { + return false; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__createFileExclusively ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__createFileExclusively>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(createFileExclusively), "(Ljava/lang/String;)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__createFileExclusively(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(pathname)) != 0; + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static string[] list(object _this, object f) + /// + /// Implements the native method 'delete0'. + /// + /// + /// + /// + /// + public static bool delete0(object self, object file) { #if FIRST_PASS throw new NotImplementedException(); #else - return WinNTFileSystem.list(_this, (global::java.io.File)f); + if (JVM.Vfs.IsPath(((global::java.io.File)file).getPath())) + { + throw new NotImplementedException(); + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__delete0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__delete0>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(delete0), "(Ljava/io/File;)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__delete0(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(file)) != 0; + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static bool createDirectory(object _this, object f) + /// + /// Implements the native method 'list'. + /// + /// + /// + /// + public static string[] list(object self, object file) { #if FIRST_PASS throw new NotImplementedException(); #else - return WinNTFileSystem.createDirectory(_this, (global::java.io.File)f); + if (JVM.Vfs.IsPath(((global::java.io.File)file).getPath())) + { + if (JVM.Vfs.GetEntry(((global::java.io.File)file).getPath()) is VfsDirectory vfs) + return vfs.List(); + + return null; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__list ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__list>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(list), "(Ljava/io/File;)[Ljava/lang/String;")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return (string[])jniFrm.UnwrapLocalRef(__jniPtr__list(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(file))); + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static bool rename0(object _this, object f1, object f2) + /// + /// Implements the native method 'createDirectory'. + /// + /// + /// + /// + public static bool createDirectory(object self, object file) { #if FIRST_PASS throw new NotImplementedException(); #else - return WinNTFileSystem.rename0(_this, (global::java.io.File)f1, (global::java.io.File)f2); + if (JVM.Vfs.IsPath(((global::java.io.File)file).getPath())) + { + return false; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__createDirectory ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__createDirectory>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(createDirectory), "(Ljava/io/File;)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__createDirectory(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(file)) != 0; + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static bool setLastModifiedTime(object _this, object f, long time) + /// + /// Implements the native method 'rename0'. + /// + /// + /// + /// + /// + /// + public static bool rename0(object self, object from, object to) { #if FIRST_PASS throw new NotImplementedException(); #else - return WinNTFileSystem.setLastModifiedTime(_this, (global::java.io.File)f, time); + if (JVM.Vfs.IsPath(((global::java.io.File)from).getPath()) || JVM.Vfs.IsPath(((global::java.io.File)to).getPath())) + { + return false; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__rename0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__rename0>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(rename0), "(Ljava/io/File;Ljava/io/File;)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__rename0(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(from), jniFrm.MakeLocalRef(to)) != 0; + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static bool setReadOnly(object _this, object f) + /// + /// Implements the native method 'setLastModifiedTime'. + /// + /// + /// + /// + /// + public static bool setLastModifiedTime(object self, object file, long time) { #if FIRST_PASS throw new NotImplementedException(); #else - return WinNTFileSystem.setReadOnly(_this, (global::java.io.File)f); + if (JVM.Vfs.IsPath(((global::java.io.File)file).getPath())) + { + return false; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__setLastModifiedTime ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__setLastModifiedTime>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(setLastModifiedTime), "(Ljava/io/File;J)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__setLastModifiedTime(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(file), time) != 0; + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static void initIDs() + /// + /// Implements the native method 'setReadOnly'. + /// + /// + /// + /// + public static bool setReadOnly(object self, object file) { - +#if FIRST_PASS + throw new NotImplementedException(); +#else + if (JVM.Vfs.IsPath(((global::java.io.File)file).getPath())) + { + return false; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(UnixFileSystemAccessor.Type.TypeHandle); + __jniPtr__setReadOnly ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__setReadOnly>(JNIFrame.GetFuncPtr(__callerID, "java/io/UnixFileSystem", nameof(setReadOnly), "(Ljava/io/File;)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__setReadOnly(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(file)) != 0; + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } +#endif } } diff --git a/src/IKVM.Runtime/Java/Externs/java/io/WinNTFileSystem.cs b/src/IKVM.Runtime/Java/Externs/java/io/WinNTFileSystem.cs index bd0a8a9c5a..d84a9d7d1d 100644 --- a/src/IKVM.Runtime/Java/Externs/java/io/WinNTFileSystem.cs +++ b/src/IKVM.Runtime/Java/Externs/java/io/WinNTFileSystem.cs @@ -1,34 +1,12 @@ -/* - Copyright (C) 2007-2014 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -using System; +using System; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Security; using IKVM.Runtime; +using IKVM.Runtime.Accessors.Java.Io; +using IKVM.Runtime.JNI; using IKVM.Runtime.Vfs; namespace IKVM.Java.Externs.java.io @@ -37,32 +15,43 @@ namespace IKVM.Java.Externs.java.io static class WinNTFileSystem { - internal const int ACCESS_READ = 0x04; - const int ACCESS_WRITE = 0x02; - const int ACCESS_EXECUTE = 0x01; +#if FIRST_PASS == false + + static WinNTFileSystemAccessor winNTFileSystemAccessor; + + static WinNTFileSystemAccessor WinNTFileSystemAccessor => JVM.Internal.BaseAccessors.Get(ref winNTFileSystemAccessor); + + static global::ikvm.@internal.CallerID __callerID; + delegate IntPtr __jniDelegate__canonicalize0(IntPtr jniEnv, IntPtr self, IntPtr path); + static __jniDelegate__canonicalize0 __jniPtr__canonicalize0; + delegate IntPtr __jniDelegate__canonicalizeWithPrefix0(IntPtr jniEnv, IntPtr self, IntPtr canonicalPrefix, IntPtr pathWithCanonicalPrefix); + static __jniDelegate__canonicalizeWithPrefix0 __jniPtr__canonicalizeWithPrefix0; + delegate byte __jniDelegate__delete0(IntPtr jniEnv, IntPtr self, IntPtr f); + static __jniDelegate__delete0 __jniPtr__delete0; + delegate byte __jniDelegate__rename0(IntPtr jniEnv, IntPtr self, IntPtr f1, IntPtr f2); + static __jniDelegate__rename0 __jniPtr__rename0; + delegate int __jniDelegate__getBooleanAttributes(IntPtr jniEnv, IntPtr self, IntPtr f); + static __jniDelegate__getBooleanAttributes __jniPtr__getBooleanAttributes; + delegate byte __jniDelegate__checkAccess(IntPtr jniEnv, IntPtr self, IntPtr f, int access); + static __jniDelegate__checkAccess __jniPtr__checkAccess; + delegate long __jniDelegate__getLastModifiedTime(IntPtr jniEnv, IntPtr self, IntPtr f); + static __jniDelegate__getLastModifiedTime __jniPtr__getLastModifiedTime; + delegate long __jniDelegate__getLength(IntPtr jniEnv, IntPtr self, IntPtr f); + static __jniDelegate__getLength __jniPtr__getLength; + delegate byte __jniDelegate__setPermission(IntPtr jniEnv, IntPtr self, IntPtr f, int access, byte enable, byte owneronly); + static __jniDelegate__setPermission __jniPtr__setPermission; + delegate byte __jniDelegate__createFileExclusively(IntPtr jniEnv, IntPtr self, IntPtr path); + static __jniDelegate__createFileExclusively __jniPtr__createFileExclusively; + delegate IntPtr __jniDelegate__list(IntPtr jniEnv, IntPtr self, IntPtr f); + static __jniDelegate__list __jniPtr__list; + delegate byte __jniDelegate__createDirectory(IntPtr jniEnv, IntPtr self, IntPtr f); + static __jniDelegate__createDirectory __jniPtr__createDirectory; + delegate byte __jniDelegate__setLastModifiedTime(IntPtr jniEnv, IntPtr self, IntPtr f, long time); + static __jniDelegate__setLastModifiedTime __jniPtr__setLastModifiedTime; + delegate byte __jniDelegate__setReadOnly(IntPtr jniEnv, IntPtr self, IntPtr f); + static __jniDelegate__setReadOnly __jniPtr__setReadOnly; - public static string getDriveDirectory(object _this, int drive) - { - try - { - string path = ((char)('A' + (drive - 1))) + ":"; - return Path.GetFullPath(path).Substring(2); - } - catch (ArgumentException) - { - - } - catch (SecurityException) - { - - } - catch (PathTooLongException) - { - - } - - return "\\"; - } +#endif /// /// Attempts to canonicalize the given path. @@ -134,621 +123,570 @@ static string CanonicalizePath(string path) #endif } + /// + /// Implements the native method 'canonicalize0'. + /// + /// + /// + /// + /// public static string canonicalize0(object self, string path) { #if FIRST_PASS throw new NotImplementedException(); #else - try + if (JVM.Vfs.IsPath(path)) { return CanonicalizePath(Path.IsPathRooted(path) == false ? Path.GetFullPath(path) : path); } - catch (Exception e) + else { - throw new global::java.io.IOException(e); + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__canonicalize0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__canonicalize0>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(canonicalize0), "(Ljava/lang/String;)Ljava/lang/String;")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return (string)jniFrm.UnwrapLocalRef(__jniPtr__canonicalize0(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(path))); + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } } #endif } - public static string canonicalizeWithPrefix0(object _this, string canonicalPrefix, string pathWithCanonicalPrefix) - { - return canonicalize0(_this, pathWithCanonicalPrefix); - } - - private static string GetPathFromFile(global::java.io.File file) + /// + /// Implements the native method 'canonicalizeWithPrefix0'. + /// + /// + /// + /// + /// + /// + public static string canonicalizeWithPrefix0(object self, string canonicalPrefix, string pathWithCanonicalPrefix) { #if FIRST_PASS throw new NotImplementedException(); #else - return file.getPath(); + if (JVM.Vfs.IsPath(pathWithCanonicalPrefix)) + { + return CanonicalizePath(Path.IsPathRooted(pathWithCanonicalPrefix) == false ? Path.GetFullPath(pathWithCanonicalPrefix) : pathWithCanonicalPrefix); + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__canonicalizeWithPrefix0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__canonicalizeWithPrefix0>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(canonicalizeWithPrefix0), "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return (string)jniFrm.UnwrapLocalRef(__jniPtr__canonicalizeWithPrefix0(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(canonicalPrefix), jniFrm.MakeLocalRef(pathWithCanonicalPrefix))); + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } + } #endif } - public static int getBooleanAttributes(object _this, global::java.io.File f) + /// + /// Implements the native method 'delete0'. + /// + /// + /// + /// + /// + public static bool delete0(object self, object f) { #if FIRST_PASS throw new NotImplementedException(); #else - try + if (JVM.Vfs.IsPath(((global::java.io.File)f).getPath())) { - var path = GetPathFromFile(f); - if (JVM.Vfs.IsPath(path)) - return JVM.Vfs.GetBooleanAttributes(path); - - FileAttributes attr = File.GetAttributes(path); - const int BA_EXISTS = 0x01; - const int BA_REGULAR = 0x02; - const int BA_DIRECTORY = 0x04; - const int BA_HIDDEN = 0x08; - int rv = BA_EXISTS; - if ((attr & FileAttributes.Directory) != 0) + throw new NotImplementedException(); + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__delete0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__delete0>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(delete0), "(Ljava/io/File;)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try { - rv |= BA_DIRECTORY; + return __jniPtr__delete0(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(f)) != 0; } - else + catch (Exception ex) { - rv |= BA_REGULAR; + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; } - if ((attr & FileAttributes.Hidden) != 0) + finally { - rv |= BA_HIDDEN; + jniFrm.Leave(); } - return rv; } - catch (ArgumentException) - { +#endif + } - } - catch (UnauthorizedAccessException) + /// + /// Implements the native method 'rename0'. + /// + /// + /// + /// + /// + /// + public static bool rename0(object self, object f1, object f2) + { +#if FIRST_PASS + throw new NotImplementedException(); +#else + if (JVM.Vfs.IsPath(((global::java.io.File)f1).getPath()) || JVM.Vfs.IsPath(((global::java.io.File)f2).getPath())) { - + throw new NotImplementedException(); } - catch (SecurityException) + else { - + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__rename0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__rename0>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(rename0), "(Ljava/io/File;Ljava/io/File;)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__rename0(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(f1), jniFrm.MakeLocalRef(f2)) != 0; + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } } - catch (NotSupportedException) - { +#endif + } + /// + /// Implements the native method 'getBooleanAttributes'. + /// + /// + /// + /// + public static int getBooleanAttributes(object self, object f) + { +#if FIRST_PASS + throw new NotImplementedException(); +#else + if (JVM.Vfs.IsPath(((global::java.io.File)f).getPath())) + { + return JVM.Vfs.GetBooleanAttributes(((global::java.io.File)f).getPath()); } - catch (IOException) + else { - + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__getBooleanAttributes ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__getBooleanAttributes>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(getBooleanAttributes), "(Ljava/io/File;)I")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__getBooleanAttributes(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(f)); + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } } - - return 0; #endif } /// - /// Checks if the given access bits are allowed on the given file. + /// Implements the native method 'checkAccess'. /// - /// + /// /// /// /// - public static bool checkAccess(object _this, global::java.io.File f, int access) + public static bool checkAccess(object self, object f, int access) { #if FIRST_PASS throw new NotImplementedException(); #else - var path = GetPathFromFile(f); - - // check the VFS for the file - if (JVM.Vfs.IsPath(path)) + if (JVM.Vfs.IsPath(((global::java.io.File)f).getPath())) { - return JVM.Vfs.GetEntry(path) switch + const int ACCESS_READ = 0x04; + return JVM.Vfs.GetEntry(((global::java.io.File)f).getPath()) switch { VfsFile file => access == ACCESS_READ && file.CanOpen(FileMode.Open, FileAccess.Read), VfsDirectory => true, _ => false, }; } - - var ok = true; - if ((access & (ACCESS_READ | ACCESS_EXECUTE)) != 0) + else { - ok = false; - + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__checkAccess ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__checkAccess>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(checkAccess), "(Ljava/io/File;I)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); try { - // HACK if path refers to a directory, we always return true - if (!Directory.Exists(path)) - { - new FileInfo(path).Open( - FileMode.Open, - FileAccess.Read, - FileShare.ReadWrite).Close(); - } - - ok = true; + return __jniPtr__checkAccess(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(f), access) != 0; } - catch (SecurityException) + catch (Exception ex) { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; } - catch (ArgumentException) - { - } - catch (UnauthorizedAccessException) - { - } - catch (IOException) - { - } - catch (NotSupportedException) + finally { + jniFrm.Leave(); } } - if (ok && ((access & ACCESS_WRITE) != 0)) +#endif + } + + /// + /// Implements the native method 'getLastModifiedTime'. + /// + /// + /// + /// + public static long getLastModifiedTime(object self, object f) + { +#if FIRST_PASS + throw new NotImplementedException(); +#else + if (JVM.Vfs.IsPath(((global::java.io.File)f).getPath())) + { + return 0; + } + else { - ok = false; + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__getLastModifiedTime ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__getLastModifiedTime>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(getLastModifiedTime), "(Ljava/io/File;)J")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); try { - // HACK if path refers to a directory, we always return true - if (Directory.Exists(path)) - { - ok = true; - } - else - { - FileInfo fileInfo = new FileInfo(path); - // Like the JDK we'll only look at the read-only attribute and not - // the security permissions associated with the file or directory. - ok = (fileInfo.Attributes & FileAttributes.ReadOnly) == 0; - } + return __jniPtr__getLastModifiedTime(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(f)); } - catch (SecurityException) + catch (Exception ex) { - + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; } - catch (ArgumentException) + finally { - - } - catch (UnauthorizedAccessException) - { - - } - catch (IOException) - { - - } - catch (NotSupportedException) - { - + jniFrm.Leave(); } } - - return ok; #endif } /// - /// The .NET ticks representing January 1, 1970 0:00:00, also known as the "epoch". + /// Implements the native method 'getLength'. /// - private const long UnixEpochTicks = 621355968000000000L; - - private const long UnixEpochMilliseconds = UnixEpochTicks / TimeSpan.TicksPerMillisecond; // 62,135,596,800,000 - - private static long DateTimeToJavaLongTime(DateTime datetime) - { - long milliseconds = datetime.ToUniversalTime().Ticks / TimeSpan.TicksPerMillisecond; - return milliseconds - UnixEpochMilliseconds; - } - - private static DateTime JavaLongTimeToDateTime(long datetime) - { - return DateTimeOffset.FromUnixTimeMilliseconds(datetime).LocalDateTime; - } - - public static long getLastModifiedTime(object _this, global::java.io.File f) + /// + /// + /// + public static long getLength(object self, object f) { - try +#if FIRST_PASS + throw new NotImplementedException(); +#else + if (JVM.Vfs.IsPath(((global::java.io.File)f).getPath())) { - DateTime dt = File.GetLastWriteTime(GetPathFromFile(f)); - if (dt.ToFileTime() == 0) + return JVM.Vfs.GetEntry(((global::java.io.File)f).getPath()) is VfsFile file ? file.Size : 0; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__getLength ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__getLength>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(getLength), "(Ljava/io/File;)J")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try { - return 0; + return __jniPtr__getLength(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(f)); } - else + catch (Exception ex) { - return DateTimeToJavaLongTime(dt); + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); } } - catch (UnauthorizedAccessException) - { - } - catch (ArgumentException) - { - } - catch (IOException) - { - } - catch (NotSupportedException) - { - } - return 0; +#endif } - public static long getLength(object _this, global::java.io.File f) + /// + /// Implements the native method 'setPermission'. + /// + /// + /// + /// + /// + /// + /// + public static bool setPermission(object self, object f, int access, bool enable, bool owneronly) { #if FIRST_PASS throw new NotImplementedException(); #else - try - { - var path = GetPathFromFile(f); - if (JVM.Vfs.IsPath(path)) - return JVM.Vfs.GetEntry(path) is VfsFile file ? file.Size : 0; - - return new FileInfo(path).Length; - } - catch (SecurityException) - { - - } - catch (ArgumentException) - { - - } - catch (UnauthorizedAccessException) - { - - } - catch (IOException) + if (JVM.Vfs.IsPath(((global::java.io.File)f).getPath())) { - - } - catch (NotSupportedException) - { - + return false; } - - return 0; -#endif - } - - public static bool setPermission(object _this, global::java.io.File f, int access, bool enable, bool owneronly) - { - if ((access & ACCESS_WRITE) != 0) + else { + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__setPermission ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__setPermission>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(setPermission), "(Ljava/io/File;IZZ)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); try { - FileInfo file = new FileInfo(GetPathFromFile(f)); - if (enable) - { - file.Attributes &= ~FileAttributes.ReadOnly; - } - else - { - file.Attributes |= FileAttributes.ReadOnly; - } - return true; + return __jniPtr__setPermission(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(f), access, enable ? (byte)1 : (byte)0, owneronly ? (byte)1 : (byte)0) != 0; } - catch (SecurityException) + catch (Exception ex) { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; } - catch (ArgumentException) - { - } - catch (UnauthorizedAccessException) + finally { + jniFrm.Leave(); } - catch (IOException) - { - } - catch (NotSupportedException) - { - } - return false; } - return enable; +#endif } - public static bool createFileExclusively(object _this, string path) + /// + /// Implements the native method 'createFileExclusively'. + /// + /// + /// + /// + public static bool createFileExclusively(object self, string path) { -#if !FIRST_PASS - try - { - File.Open(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None).Close(); - return true; - } - catch (ArgumentException x) +#if FIRST_PASS + throw new NotImplementedException(); +#else + if (JVM.Vfs.IsPath(path)) { - throw new global::java.io.IOException(x.Message); + return false; } - catch (IOException x) + else { - if (!File.Exists(path) && !Directory.Exists(path)) + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__createFileExclusively ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__createFileExclusively>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(createFileExclusively), "(Ljava/lang/String;)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try { - throw new global::java.io.IOException(x.Message); + return __jniPtr__createFileExclusively(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(path)) != 0; } - } - catch (UnauthorizedAccessException x) - { - if (!File.Exists(path) && !Directory.Exists(path)) + catch (Exception ex) { - throw new global::java.io.IOException(x.Message); + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); } - } - catch (NotSupportedException x) - { - throw new global::java.io.IOException(x.Message); } #endif - return false; } - public static bool delete0(object _this, global::java.io.File f) + /// + /// Implements the native method 'list'. + /// + /// + /// + /// + public static string[] list(object self, object f) { - FileSystemInfo fileInfo = null; - try +#if FIRST_PASS + throw new NotImplementedException(); +#else + if (JVM.Vfs.IsPath(((global::java.io.File)f).getPath())) { - string path = GetPathFromFile(f); - if (Directory.Exists(path)) - { - fileInfo = new DirectoryInfo(path); - } - else if (File.Exists(path)) + if (JVM.Vfs.GetEntry(((global::java.io.File)f).getPath()) is VfsDirectory vfs) + return vfs.List(); + + return null; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__list ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__list>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(list), "(Ljava/io/File;)[Ljava/lang/String;")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try { - fileInfo = new FileInfo(path); + return (string[])jniFrm.UnwrapLocalRef(__jniPtr__list(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(f))); } - else + catch (Exception ex) { - return false; + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; } - // We need to be able to delete read-only files/dirs too, so we clear - // the read-only attribute, if set. - if ((fileInfo.Attributes & FileAttributes.ReadOnly) != 0) + finally { - fileInfo.Attributes &= ~FileAttributes.ReadOnly; + jniFrm.Leave(); } - fileInfo.Delete(); - return true; } - catch (SecurityException) - { - - } - catch (ArgumentException) - { - - } - catch (UnauthorizedAccessException) - { - - } - catch (IOException) - { - - } - catch (NotSupportedException) - { - - } - - return false; +#endif } - public static string[] list(object _this, global::java.io.File f) + /// + /// Implements the native method 'createDirectory'. + /// + /// + /// + /// + public static bool createDirectory(object self, object f) { #if FIRST_PASS throw new NotImplementedException(); #else - try + if (JVM.Vfs.IsPath(((global::java.io.File)f).getPath())) { - var path = GetPathFromFile(f); - if (JVM.Vfs.IsPath(path)) + return false; + } + else + { + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__createDirectory ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__createDirectory>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(createDirectory), "(Ljava/io/File;)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try { - if (JVM.Vfs.GetEntry(path) is VfsDirectory vfs) - return vfs.List(); - - throw new DirectoryNotFoundException(); + return __jniPtr__createDirectory(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(f)) != 0; } - - string[] l = Directory.GetFileSystemEntries(path); - for (int i = 0; i < l.Length; i++) + catch (Exception ex) { - int pos = l[i].LastIndexOf(Path.DirectorySeparatorChar); - if (pos >= 0) - l[i] = l[i].Substring(pos + 1); + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; } - - return l; - } - catch (ArgumentException) - { - - } - catch (IOException) - { - - } - catch (UnauthorizedAccessException) - { - - } - catch (NotSupportedException) - { - - } - - return null; -#endif - } - - public static bool createDirectory(object _this, global::java.io.File f) - { - try - { - string path = GetPathFromFile(f); - DirectoryInfo parent = Directory.GetParent(path); - if (parent == null || - !Directory.Exists(parent.FullName) || - Directory.Exists(path)) + finally { - return false; + jniFrm.Leave(); } - return Directory.CreateDirectory(path) != null; - } - catch (SecurityException) - { - - } - catch (ArgumentException) - { - - } - catch (UnauthorizedAccessException) - { - - } - catch (IOException) - { - - } - catch (NotSupportedException) - { - - } - - return false; - } - - public static bool rename0(object _this, global::java.io.File f1, global::java.io.File f2) - { - try - { - new FileInfo(GetPathFromFile(f1)).MoveTo(GetPathFromFile(f2)); - return true; - } - catch (SecurityException) - { - } - catch (ArgumentException) - { - } - catch (UnauthorizedAccessException) - { - } - catch (IOException) - { - } - catch (NotSupportedException) - { } - return false; +#endif } - public static bool setLastModifiedTime(object _this, global::java.io.File f, long time) + /// + /// Implements the native method 'setLastModifiedTime'. + /// + /// + /// + /// + /// + public static bool setLastModifiedTime(object self, object f, long time) { - try - { - new FileInfo(GetPathFromFile(f)).LastWriteTime = JavaLongTimeToDateTime(time); - return true; - } - catch (SecurityException) - { - } - catch (ArgumentException) - { - } - catch (UnauthorizedAccessException) +#if FIRST_PASS + throw new NotImplementedException(); +#else + if (JVM.Vfs.IsPath(((global::java.io.File)f).getPath())) { + return false; } - catch (IOException) - { - } - catch (NotSupportedException) + else { + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__setLastModifiedTime ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__setLastModifiedTime>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(setLastModifiedTime), "(Ljava/io/File;J)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try + { + return __jniPtr__setLastModifiedTime(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(f), time) != 0; + } + catch (Exception ex) + { + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); + } } - return false; +#endif } - public static bool setReadOnly(object _this, global::java.io.File f) + /// + /// Implements the native method 'setReadOnly'. + /// + /// + /// + /// + public static bool setReadOnly(object self, object f) { - try - { - FileInfo fileInfo = new FileInfo(GetPathFromFile(f)); - fileInfo.Attributes |= FileAttributes.ReadOnly; - return true; - } - catch (SecurityException) - { - } - catch (ArgumentException) - { - } - catch (UnauthorizedAccessException) - { - } - catch (IOException) - { - } - catch (NotSupportedException) +#if FIRST_PASS + throw new NotImplementedException(); +#else + if (JVM.Vfs.IsPath(((global::java.io.File)f).getPath())) { + return false; } - return false; - } - - public static int listRoots0() - { - try + else { - int drives = 0; - foreach (string drive in Environment.GetLogicalDrives()) + __callerID ??= global::ikvm.@internal.CallerID.create(WinNTFileSystemAccessor.Type.TypeHandle); + __jniPtr__setReadOnly ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__setReadOnly>(JNIFrame.GetFuncPtr(__callerID, "java/io/WinNTFileSystem", nameof(setReadOnly), "(Ljava/io/File;)Z")); + var jniFrm = new JNIFrame(); + var jniEnv = jniFrm.Enter(__callerID); + try { - char c = Char.ToUpper(drive[0]); - drives |= 1 << (c - 'A'); + return __jniPtr__setReadOnly(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(f)) != 0; } - return drives; - } - catch (IOException) - { - } - catch (UnauthorizedAccessException) - { - } - catch (SecurityException) - { - } - return 0; - } - - [SecuritySafeCritical] - public static long getSpace0(object _this, global::java.io.File f, int t) - { -#if !FIRST_PASS - long freeAvailable; - long total; - long totalFree; - var volname = new System.Text.StringBuilder(256); - if (GetVolumePathName(GetPathFromFile(f), volname, volname.Capacity) != 0 && GetDiskFreeSpaceEx(volname.ToString(), out freeAvailable, out total, out totalFree) != 0) - { - switch (t) + catch (Exception ex) { - case global::java.io.FileSystem.SPACE_TOTAL: - return total; - case global::java.io.FileSystem.SPACE_FREE: - return totalFree; - case global::java.io.FileSystem.SPACE_USABLE: - return freeAvailable; + System.Console.WriteLine("*** exception in native code ***"); + System.Console.WriteLine(ex); + throw; + } + finally + { + jniFrm.Leave(); } } #endif - - return 0; - } - - [DllImport("kernel32")] - private static extern int GetDiskFreeSpaceEx(string directory, out long freeAvailable, out long total, out long totalFree); - - [DllImport("kernel32")] - private static extern int GetVolumePathName(string lpszFileName, [In, Out] System.Text.StringBuilder lpszVolumePathName, int cchBufferLength); - - public static void initIDs() - { - } } diff --git a/src/IKVM.Runtime/Java/Externs/java/lang/ProcessEnvironment.cs b/src/IKVM.Runtime/Java/Externs/java/lang/ProcessEnvironment.cs deleted file mode 100644 index 55490c4410..0000000000 --- a/src/IKVM.Runtime/Java/Externs/java/lang/ProcessEnvironment.cs +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright (C) 2007-2014 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; -using System.Text; - -namespace IKVM.Java.Externs.java.lang -{ - - static class ProcessEnvironment - { - - public static string environmentBlock() - { - StringBuilder sb = new StringBuilder(); - foreach (global::System.Collections.DictionaryEntry de in Environment.GetEnvironmentVariables()) - { - sb.Append(de.Key).Append('=').Append(de.Value).Append('\u0000'); - } - if (sb.Length == 0) - { - sb.Append('\u0000'); - } - sb.Append('\u0000'); - return sb.ToString(); - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/java/lang/UNIXProcess.cs b/src/IKVM.Runtime/Java/Externs/java/lang/UNIXProcess.cs index 725f3285d8..37fcacfab0 100644 --- a/src/IKVM.Runtime/Java/Externs/java/lang/UNIXProcess.cs +++ b/src/IKVM.Runtime/Java/Externs/java/lang/UNIXProcess.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using IKVM.Runtime; +using IKVM.Runtime.Accessors.Java.Lang; using IKVM.Runtime.JNI; namespace IKVM.Java.Externs.java.lang @@ -13,6 +14,10 @@ static class UNIXProcess #if FIRST_PASS == false + static UNIXProcessAccessor unixProcessAccessor; + + static UNIXProcessAccessor UNIXProcessAccessor => JVM.Internal.BaseAccessors.Get(ref unixProcessAccessor); + static global::ikvm.@internal.CallerID __callerID; delegate void __jniDelegate__init(IntPtr jniEnv, IntPtr clazz); static __jniDelegate__init __jniPtr__init; @@ -23,7 +28,8 @@ static class UNIXProcess /// Implements the native method 'init'. /// /// - /// We save and load the old SIGCHLD handler between calls to prevent Java from overwriting the .NET handler. This isn't thread safe but should suffice since it's limited to static initialization. + /// We save and load the old SIGCHLD handler between calls to prevent Java from overwriting the .NET handler. + /// This isn't thread safe but should suffice since it's limited to static initialization. /// /// public static unsafe void init() @@ -45,13 +51,13 @@ public static unsafe void init() try { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.lang.UNIXProcess).TypeHandle); + __callerID ??= global::ikvm.@internal.CallerID.create(UNIXProcessAccessor.Type.TypeHandle); __jniPtr__init ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__init>(JNIFrame.GetFuncPtr(__callerID, "java/lang/UNIXProcess", nameof(init), "()V")); var jniFrm = new JNIFrame(); var jniEnv = jniFrm.Enter(__callerID); try { - __jniPtr__init(jniEnv, jniFrm.MakeLocalRef(ClassLiteral.Value)); + __jniPtr__init(jniEnv, jniFrm.MakeLocalRef(typeof(ClassLiteral<>).MakeGenericType(UNIXProcessAccessor.Type))); } catch (Exception ex) { @@ -75,4 +81,4 @@ public static unsafe void init() } -} +} \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/java/lang/UNIXProcessEnvironment.cs b/src/IKVM.Runtime/Java/Externs/java/lang/UNIXProcessEnvironment.cs deleted file mode 100644 index 8ff1cdad6b..0000000000 --- a/src/IKVM.Runtime/Java/Externs/java/lang/UNIXProcessEnvironment.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -using IKVM.Runtime; -using IKVM.Runtime.JNI; - -namespace IKVM.Java.Externs.java.lang -{ - - static class UNIXProcessEnvironment - { - -#if FIRST_PASS == false - - static global::ikvm.@internal.CallerID __callerID; - delegate IntPtr __jniDelegate__environ(IntPtr jniEnv, IntPtr clazz); - static __jniDelegate__environ __jniPtr__environ; - -#endif - - /// - /// Implements the native method 'environ'. - /// - /// - public static object environ() - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.lang.UNIXProcessEnvironment).TypeHandle); - __jniPtr__environ ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__environ>(JNIFrame.GetFuncPtr(__callerID, "java/lang/ProcessEnvironment", nameof(environ), "()[[B")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - return jniFrm.UnwrapLocalRef(__jniPtr__environ(jniEnv, jniFrm.MakeLocalRef(ClassLiteral.Value))); - } - catch (Exception ex) - { - global::System.Console.WriteLine("*** exception in native code ***"); - global::System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/java/lang/Win32Process.cs b/src/IKVM.Runtime/Java/Externs/java/lang/Win32Process.cs deleted file mode 100644 index 816a96b821..0000000000 --- a/src/IKVM.Runtime/Java/Externs/java/lang/Win32Process.cs +++ /dev/null @@ -1,994 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Security.AccessControl; -using System.Text.RegularExpressions; -using System.Threading; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Ikvm.Internal; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.Accessors.Java.Lang; -using IKVM.Runtime.Accessors.Java.Util; -using IKVM.Runtime.Util.Java.Security; - -namespace IKVM.Java.Externs.java.lang -{ - - /// - /// Implements the native methods for 'Win32Process'. - /// - static class Win32Process - { - -#if FIRST_PASS == false - - static CallerIDAccessor callerIDAccessor; - static SystemAccessor systemAccessor; - static SecurityManagerAccessor securityManagerAccessor; - static ThreadAccessor threadAccessor; - static ProcessBuilderRedirectAccessor processBuilderRedirectAccessor; - static ProcessBuilderNullInputStreamAccessor processBuilderNullInputStreamAccessor; - static ProcessBuilderNullOutputStreamAccessor processBuilderNullOutputStreamAccessor; - static FileAccessor fileAccessor; - static FileDescriptorAccessor fileDescriptorAccessor; - static InputStreamAccessor inputStreamAccessor; - static OutputStreamAccessor outputStreamAccessor; - static FileInputStreamAccessor fileInputStreamAccessor; - static FileOutputStreamAccessor fileOutputStreamAccessor; - static BufferedInputStreamAccessor bufferedInputStreamAccessor; - static BufferedOutputStreamAccessor bufferedOutputStreamAccessor; - static AccessControllerAccessor accessControllerAccessor; - static MapAccessor mapAccessor; - static MapEntryAccessor mapEntryAccessor; - static SetAccessor setAccessor; - static IteratorAccessor iteratorAccessor; - static Win32ProcessAccessor win32ProcessAccessor; - - static CallerIDAccessor CallerIDAccessor => JVM.Internal.BaseAccessors.Get(ref callerIDAccessor); - - static SystemAccessor SystemAccessor => JVM.Internal.BaseAccessors.Get(ref systemAccessor); - - static SecurityManagerAccessor SecurityManagerAccessor => JVM.Internal.BaseAccessors.Get(ref securityManagerAccessor); - - static ThreadAccessor ThreadAccessor => JVM.Internal.BaseAccessors.Get(ref threadAccessor); - - static ProcessBuilderRedirectAccessor ProcessBuilderRedirectAccessor => JVM.Internal.BaseAccessors.Get(ref processBuilderRedirectAccessor); - - static ProcessBuilderNullInputStreamAccessor ProcessBuilderNullInputStreamAccessor => JVM.Internal.BaseAccessors.Get(ref processBuilderNullInputStreamAccessor); - - static ProcessBuilderNullOutputStreamAccessor ProcessBuilderNullOutputStreamAccessor => JVM.Internal.BaseAccessors.Get(ref processBuilderNullOutputStreamAccessor); - - static FileAccessor FileAccessor => JVM.Internal.BaseAccessors.Get(ref fileAccessor); - - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - - static InputStreamAccessor InputStreamAccessor => JVM.Internal.BaseAccessors.Get(ref inputStreamAccessor); - - static OutputStreamAccessor OutputStreamAccessor => JVM.Internal.BaseAccessors.Get(ref outputStreamAccessor); - - static FileInputStreamAccessor FileInputStreamAccessor => JVM.Internal.BaseAccessors.Get(ref fileInputStreamAccessor); - - static FileOutputStreamAccessor FileOutputStreamAccessor => JVM.Internal.BaseAccessors.Get(ref fileOutputStreamAccessor); - - static BufferedInputStreamAccessor BufferedInputStreamAccessor => JVM.Internal.BaseAccessors.Get(ref bufferedInputStreamAccessor); - - static BufferedOutputStreamAccessor BufferedOutputStreamAccessor => JVM.Internal.BaseAccessors.Get(ref bufferedOutputStreamAccessor); - - static AccessControllerAccessor AccessControllerAccessor => JVM.Internal.BaseAccessors.Get(ref accessControllerAccessor); - - static MapAccessor MapAccessor => JVM.Internal.BaseAccessors.Get(ref mapAccessor); - - static MapEntryAccessor MapEntryAccessor => JVM.Internal.BaseAccessors.Get(ref mapEntryAccessor); - - static SetAccessor SetAccessor => JVM.Internal.BaseAccessors.Get(ref setAccessor); - - static IteratorAccessor IteratorAccessor => JVM.Internal.BaseAccessors.Get(ref iteratorAccessor); - - static Win32ProcessAccessor Win32ProcessAccessor => JVM.Internal.BaseAccessors.Get(ref win32ProcessAccessor); - -#endif - - enum WindowsVerificationMode - { - - CmdOrBat = 0, - Win32 = 1, - Legacy = 2, - - } - - static readonly char[][] WindowsInvalidChars = - { - // We guarantee the only command file execution for implicit [cmd.exe] run. - // http://technet.microsoft.com/en-us/library/bb490954.aspx - new [] {' ', '\t', '<', '>', '&', '|', '^'}, - new [] {' ', '\t', '<', '>'}, - new [] {' ', '\t'} - }; - - /// - /// Implements the native method 'start'. - /// - /// - /// - /// - /// - /// - public static object start(string[] cmdarray, object environment, string dir, object[] redirects, bool redirectErrorStream) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - // close these specifically upon exception - FileStream f0 = null; - FileStream f1 = null; - FileStream f2 = null; - - try - { - Stream h0 = null; - Stream h1 = null; - Stream h2 = null; - - // transform redirect specifications into Streams - if (redirects != null) - { - var PIPE = ProcessBuilderRedirectAccessor.GetPipe(); - var INHERIT = ProcessBuilderRedirectAccessor.GetInherit(); - - if (redirects[0] == PIPE) - h0 = null; - else if (redirects[0] == INHERIT) - h0 = FileDescriptorAccessor.GetStream(FileDescriptorAccessor.GetIn()); - else - { - f0 = File.OpenRead(FileAccessor.InvokeGetPath(ProcessBuilderRedirectAccessor.InvokeFile(redirects[0]))); - h0 = f0; - } - - if (redirects[1] == PIPE) - h1 = null; - else if (redirects[1] == INHERIT) - h1 = FileDescriptorAccessor.GetStream(FileDescriptorAccessor.GetOut()); - else - { - f1 = NewFileOutputStream(ProcessBuilderRedirectAccessor.InvokeFile(redirects[1]), ProcessBuilderRedirectAccessor.InvokeAppend(redirects[1])); - h1 = f1; - } - - if (redirects[2] == PIPE) - h2 = null; - else if (redirects[2] == INHERIT) - h2 = FileDescriptorAccessor.GetStream(FileDescriptorAccessor.GetErr()); - else - { - f2 = NewFileOutputStream(ProcessBuilderRedirectAccessor.InvokeFile(redirects[2]), ProcessBuilderRedirectAccessor.InvokeAppend(redirects[2])); - h2 = f2; - } - } - - return Create(cmdarray, MapToDictionary(environment), dir, h0, h1, h2, redirectErrorStream); - } - catch (Exception e) - { - f0?.Dispose(); - f1?.Dispose(); - f2?.Dispose(); - - if (e is global::java.lang.Throwable) - throw; - else - throw new global::java.io.IOException(e.Message, e); - } -#endif - } - - /// - /// Converts a map of string key and string values to a dictionary of the same. - /// - /// - /// - static Dictionary MapToDictionary(object map) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (map == null) - return null; - - var d = new Dictionary(); - var i = SetAccessor.InvokeIterator(MapAccessor.InvokeEntrySet(map)); - while (IteratorAccessor.InvokeHasNext(i)) - { - var e = IteratorAccessor.InvokeNext(i); - var k = (string)MapEntryAccessor.InvokeGetKey(e); - var v = (string)MapEntryAccessor.InvokeGetValue(e); - d[k] = v; - } - - return d; -#endif - } - - /// - /// Creates a new 'ProcessImpl' given the specified input. - /// - /// - /// - /// - /// - /// - /// - /// - /// - static object Create(string[] cmd, Dictionary env, string dir, Stream s0, Stream s1, Stream s2, bool redirectErrorStream) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return CreateWindows(cmd, env, dir, s0, s1, s2, redirectErrorStream); -#endif - } - - /// - /// Returns whether the argument has already been quoted. - /// - /// - /// - /// - /// - /// - static bool IsQuoted(bool noQuotesInside, string arg, string errorMessage) - { - int lastPos = arg.Length - 1; - if (lastPos >= 1 && arg[0] == '"' && arg[lastPos] == '"') - { - // the argument has already been quoted - if (noQuotesInside) - { - if (arg.IndexOf('"', 1) != lastPos) - { - // there is ["] inside - throw new ArgumentException(errorMessage); - } - } - return true; - } - - if (noQuotesInside) - { - if (arg.IndexOf('"') >= 0) - { - // there is ["] inside - throw new ArgumentException(errorMessage); - } - } - - return false; - } - - /// - /// Returns whether the argument needs escaping, based on the given verification type. - /// - /// - /// - /// - static bool NeedsEscapingOnWindows(WindowsVerificationMode verificationType, string arg) - { - // Switch off MS heuristic for internal ["]. - // Please, use the explicit [cmd.exe] call - // if you need the internal ["]. - // Example: "cmd.exe", "/C", "Extended_MS_Syntax" - - // For [.exe] or [.com] file the unpaired/internal ["] - // in the argument is not a problem. - var argIsQuoted = IsQuoted(verificationType == WindowsVerificationMode.CmdOrBat, arg, "Argument has embedded quote, use the explicit CMD.EXE call."); - if (argIsQuoted == false) - { - var testEscape = WindowsInvalidChars[(int)verificationType]; - for (int i = 0; i < testEscape.Length; ++i) - { - if (arg.IndexOf(testEscape[i]) >= 0) - { - return true; - } - } - } - - return false; - } - - /// - /// Returns whether the specified file ends with a shell executable extension. - /// - /// - /// - static bool IsWindowsShellFile(string executablePath) - { - return executablePath.EndsWith(".CMD", StringComparison.OrdinalIgnoreCase) || executablePath.EndsWith(".BAT", StringComparison.OrdinalIgnoreCase); - } - - /// - /// Surrounds the specified string with quotes. - /// - /// - /// - static string QuoteString(string arg) - { - return '"' + arg + '"'; - } - - /// - /// Merges the arguments into a single command line suitable for Windows. - /// - /// - /// - /// - static string CreateWindowsCommandLine(WindowsVerificationMode verificationType, String executablePath, string[] cmd) - { - var cmdbuf = new global::System.Text.StringBuilder(80); - cmdbuf.Append(executablePath); - - for (int i = 1; i < cmd.Length; ++i) - { - cmdbuf.Append(' '); - var s = cmd[i]; - - if (NeedsEscapingOnWindows(verificationType, s)) - { - cmdbuf.Append('"').Append(s); - - // The code protects the [java.exe] and console command line - // parser, that interprets the [\"] combination as an escape - // sequence for the ["] char. - // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx - // - // If the argument is an FS path, doubling of the tail [\] - // char is not a problem for non-console applications. - // - // The [\"] sequence is not an escape sequence for the [cmd.exe] - // command line parser. The case of the [""] tail escape - // sequence could not be realized due to the argument validation - // procedure. - if ((verificationType != WindowsVerificationMode.CmdOrBat) && s.EndsWith("\\")) - cmdbuf.Append('\\'); - - cmdbuf.Append('"'); - } - else - { - cmdbuf.Append(s); - } - } - - return cmdbuf.ToString(); - } - - /// - /// Returns the proper path to the executable. - /// - /// - /// - static string GetWindowsExecutablePath(string path) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var pathIsQuoted = IsQuoted(true, path, "Executable name has embedded quote, split the arguments"); - - // Win32 CreateProcess requires path to be normalized - var fileToRun = FileAccessor.Init(pathIsQuoted ? path.Substring(1, path.Length - 2) : path); - - // From the [CreateProcess] function documentation: - // - // "If the file name does not contain an extension, .exe is appended. - // Therefore, if the file name extension is .com, this parameter - // must include the .com extension. If the file name ends in - // a period (.) with no extension, or if the file name contains a path, - // .exe is not appended." - // - // "If the file name !does not contain a directory path!, - // the system searches for the executable file in the following - // sequence:..." - // - // In practice ANY non-existent path is extended by [.exe] extension - // in the [CreateProcess] funcion with the only exception: - // the path ends by (.) - - return FileAccessor.InvokeGetPath(fileToRun); -#endif - } - - /// - /// Extracts individual tokens from a command. - /// - /// - /// - static string[] GetTokensFromWindowsCommand(string command) - { - var matchList = new List(8); - foreach (Match m in Regex.Matches(command, "[^\\s\"]+|\"[^\"]*\"")) - matchList.Add(m.Value); - - return matchList.ToArray(); - } - - /// - /// Initializes the ProcessImpl object for a Windows platform. - /// - /// - /// - /// - /// - /// - /// - /// - /// - static object CreateWindows(string[] cmd, Dictionary env, string dir, Stream h0, Stream h1, Stream h2, bool redirectErrorStream) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - string cmdstr; - - var sm = SystemAccessor.InvokeGetSecurityManager(); - var allowAmbiguousCommands = false; - if (sm == null) - { - allowAmbiguousCommands = true; - var value = SystemAccessor.InvokeGetProperty("jdk.lang.Process.allowAmbiguousCommands"); - if (value != null) - allowAmbiguousCommands = string.Equals(value, "false", StringComparison.OrdinalIgnoreCase) == false; - } - - if (allowAmbiguousCommands) - { - // Legacy mode. - - // Normalize path if possible. - var executablePath = FileAccessor.InvokeGetPath(FileAccessor.Init(cmd[0])); - - // No worry about internal, unpaired ["], and redirection/piping. - if (NeedsEscapingOnWindows(WindowsVerificationMode.Legacy, executablePath)) - executablePath = QuoteString(executablePath); - - // legacy mode doesn't worry about extended verification - cmdstr = CreateWindowsCommandLine(WindowsVerificationMode.Legacy, executablePath, cmd); - } - else - { - string executablePath; - - try - { - // might be able to obtain it from the first argument - executablePath = GetWindowsExecutablePath(cmd[0]); - } - catch (ArgumentException) - { - // Workaround for the calls like - // Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar") - - // No chance to avoid CMD/BAT injection, except to do the work - // right from the beginning. Otherwise we have too many corner - // cases from - // Runtime.getRuntime().exec(String[] cmd [, ...]) - // calls with internal ["] and escape sequences. - - // gets the executable path - cmd = GetTokensFromWindowsCommand(string.Join(" ", cmd)); - executablePath = GetWindowsExecutablePath(cmd[0]); - - // Check new executable name once more - if (sm != null) - SecurityManagerAccessor.InvokeCheckExec(sm, executablePath); - } - - // Quotation protects from interpretation of the [path] argument as - // start of longer path with spaces. Quotation has no influence to - // [.exe] extension heuristic. - cmdstr = CreateWindowsCommandLine(IsWindowsShellFile(executablePath) ? WindowsVerificationMode.CmdOrBat : WindowsVerificationMode.Win32, QuoteString(executablePath), cmd); - } - - // even though we just combined the string, escaped, etc, we need to split it again for S.D.Process - int exeEnd = IndexOfArguments(cmdstr); - int argBeg = exeEnd; - if (cmdstr.Length > argBeg && cmdstr[argBeg] == ' ') - argBeg++; - - var psi = new ProcessStartInfo(); - psi.FileName = cmdstr.Substring(0, exeEnd).Trim('\"'); - psi.Arguments = cmdstr.Substring(argBeg); - return Create(psi, env, dir, h0, h1, h2, redirectErrorStream); -#endif - } - - /// - /// Returns the character position of the arguments without the command path. - /// - /// - /// - static int IndexOfArguments(string cmdstr) - { - int pos = cmdstr.IndexOf(' '); - if (pos == -1) - return cmdstr.Length; - - if (cmdstr[0] == '"') - { - var close = cmdstr.IndexOf('"', 1); - return close == -1 ? cmdstr.Length : close + 1; - } - - if (RuntimeUtil.IsWindows == false) - return pos; - - IList searchPaths = null; - while (true) - { - var str = cmdstr.Substring(0, pos); - if (IsPathRooted(str)) - { - if (WindowsExecutableExists(str)) - return pos; - } - else - { - foreach (var p in searchPaths ??= GetWindowsSearchPath()) - if (WindowsExecutableExists(Path.Combine(p, str))) - return pos; - } - - if (pos == cmdstr.Length) - return cmdstr.IndexOf(' '); - - pos = cmdstr.IndexOf(' ', pos + 1); - if (pos == -1) - pos = cmdstr.Length; - } - } - - /// - /// Returns the set of paths to search for Windows executables. - /// - /// - static List GetWindowsSearchPath() - { - var list = new List(); - list.Add(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)); - list.Add(Environment.CurrentDirectory); - list.Add(Environment.SystemDirectory); - - var windir = Path.GetDirectoryName(Environment.SystemDirectory); - list.Add(Path.Combine(windir, "System")); - list.Add(windir); - - var path = Environment.GetEnvironmentVariable("PATH"); - if (path != null) - foreach (var p in path.Split(Path.PathSeparator)) - list.Add(p); - - return list; - } - - /// - /// Returns true if the path is rooted. - /// - /// - /// - static bool IsPathRooted(string path) - { - try - { - return Path.IsPathRooted(path); - } - catch (ArgumentException) - { - return false; - } - } - - /// - /// Returns true if the specified file can be considered a valid executable. - /// - /// - /// - static bool WindowsExecutableExists(string file) - { - try - { - if (File.Exists(file)) - return true; - else if (Directory.Exists(file)) - return false; - if (Path.GetFileName(file) is not string filename) - return false; - if (filename.IndexOf('.') != -1) - return false; - return File.Exists(file + ".exe"); - } - catch - { - return false; - } - } - - /// - /// Creates a new 'ProcessImpl' based on the filename and arguments configured on the . - /// - /// - /// - /// - /// - /// - /// - /// - /// - static object Create(ProcessStartInfo psi, Dictionary env, string dir, Stream h0, Stream h1, Stream h2, bool redirectErrorStream) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - psi.UseShellExecute = false; - psi.CreateNoWindow = true; - psi.RedirectStandardInput = true; - psi.RedirectStandardOutput = true; - psi.RedirectStandardError = true; - psi.WorkingDirectory = dir; - - if (env != null) - foreach (var kvp in env) - psi.Environment[kvp.Key] = kvp.Value; - - // begin new process - var process = Process.Start(psi); - - // if any of the handles are files, close files when process exits - var f0 = h0 as FileStream; - var f1 = h1 as FileStream; - var f2 = h2 as FileStream; - if (f0 != null || f1 != null || f2 != null) - { - process.EnableRaisingEvents = true; - process.Exited += (s, a) => - { - f0?.Close(); - f1?.Close(); - f2?.Close(); - }; - } - - // base streams from process - var b0 = process.StandardInput.BaseStream; - var b1 = process.StandardOutput.BaseStream; - var b2 = process.StandardError.BaseStream; - - // pipe input data into process standard input - if (h0 != null) - { - ConnectPipe(h0, b0); - h0 = null; - } - else - { - h0 = b0; - } - - Stream stdoutDrain = null; - - if (h1 != null) - { - stdoutDrain = h1; - ConnectPipe(b1, stdoutDrain); - h1 = null; - } - else if (redirectErrorStream) - { - var pipe = new PipeStream(); - ConnectPipe(b1, pipe); - ConnectPipe(b2, pipe); - h1 = pipe; - } - else - { - h1 = b1; - } - - if (redirectErrorStream) - { - if (stdoutDrain != null) - ConnectPipe(b2, stdoutDrain); - h2 = null; - } - else if (h2 != null) - { - ConnectPipe(b2, h2); - h2 = null; - } - else - { - h2 = b2; - } - - // wrap CLR streams in Java streams - object s0 = null; - object s1 = null; - object s2 = null; - AccessControllerAccessor.InvokeDoPrivileged(new ActionPrivilegedAction(() => - { - s0 = h0 == null ? ProcessBuilderNullOutputStreamAccessor.GetInstance() : BufferedOutputStreamAccessor.Init(FileOutputStreamAccessor.Init2(CreateFileDescriptor(h0))); - s1 = h1 == null ? ProcessBuilderNullInputStreamAccessor.GetInstance() : BufferedInputStreamAccessor.Init(FileInputStreamAccessor.Init2(CreateFileDescriptor(h1))); - s2 = h2 == null ? ProcessBuilderNullInputStreamAccessor.GetInstance() : FileInputStreamAccessor.Init2(CreateFileDescriptor(h2)); - }), null, CallerIDAccessor.InvokeCreate(Win32ProcessAccessor.Type.TypeHandle)); - - // return new process - return Win32ProcessAccessor.Init(process, s0, s1, s2); -#endif - } - - /// - /// Creates a new FileDescriptor from the specified stream. - /// - /// - /// - static object CreateFileDescriptor(Stream stream) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var fdo = FileDescriptorAccessor.Init(); - FileDescriptorAccessor.SetStream(fdo, stream); - return fdo; -#endif - } - - class PipeStream : Stream - { - - readonly byte[] buf = new byte[4096]; - int pos; - int users = 2; - - public override bool CanRead => true; - - public override bool CanWrite => true; - - public override bool CanSeek => false; - - public override long Length => throw new NotImplementedException(); - - public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - - public override int Read(byte[] buffer, int offset, int count) - { - lock (this) - { - if (count == 0) - return 0; - - while (pos == 0) - { - try - { - Monitor.Wait(this); - } - catch (ThreadInterruptedException) - { - - } - } - - if (pos == -1) - return 0; - - count = Math.Min(count, pos); - Array.Copy(buf, 0, buffer, offset, count); - pos -= count; - - Array.Copy(buf, count, buf, 0, pos); - Monitor.PulseAll(this); - return count; - } - } - - public override void Write(byte[] buffer, int offset, int count) - { - lock (this) - { - while (buf.Length - pos < count) - { - try - { - Monitor.Wait(this); - } - catch (ThreadInterruptedException) - { - - } - } - - Array.Copy(buffer, offset, buf, pos, count); - pos += count; - Monitor.PulseAll(this); - } - } - - public override void Close() - { - lock (this) - { - if (--users == 0) - { - pos = -1; - Monitor.PulseAll(this); - } - } - } - - public override void Flush() - { - - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotImplementedException(); - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - } - - /// - /// Begins reading from and writing to . - /// - /// - /// - static void ConnectPipe(Stream src, Stream dst) - { - var buf = new byte[4096]; - - void cb(IAsyncResult ar) - { - try - { - int count = src.EndRead(ar); - if (count > 0) - { - dst.Write(buf, 0, count); - dst.Flush(); - src.BeginRead(buf, 0, buf.Length, cb, null); - } - else - { - dst.Close(); - } - } - catch - { - - } - }; - - try - { - src.BeginRead(buf, 0, buf.Length, cb, null); - } - catch - { - - } - } - - static void WaitForWithInterrupt(Process pid) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var current = ThreadAccessor.InvokeCurrentThread(); - - // spin until thread is interrupted, or process exits - while (!ThreadAccessor.InvokeIsInterrupted(current) && !pid.WaitForExit(100)) - continue; -#endif - } - - public static int waitFor(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var pid = Win32ProcessAccessor.GetProcess(self); - if (pid.HasExited) - return pid.ExitCode; - - // wait for the thread to be interrupted, or for the process to exit - WaitForWithInterrupt(pid); - - // check if we were interrupted and throw - if (ThreadAccessor.InvokeInterrupted()) - throw new global::java.lang.InterruptedException(); - - return pid.ExitCode; -#endif - } - - public static int exitValue(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var pid = Win32ProcessAccessor.GetProcess(self); - if (pid.HasExited == false) - throw new global::java.lang.IllegalThreadStateException("process has not exited"); - - return pid.ExitCode; -#endif - } - - public static void destroy(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var pid = Win32ProcessAccessor.GetProcess(self); - if (pid.HasExited) - return; - - try - { - pid.Kill(); - } - catch - { - // ignore - } -#endif - } - - static FileStream OpenForAtomicAppend(string path) - { -#if NETFRAMEWORK - return new FileStream(path, FileMode.Append, FileSystemRights.AppendData, FileShare.ReadWrite, 1, FileOptions.None); -#else - return new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, 1, FileOptions.None); -#endif - } - - /// - /// Open a file for writing. If is true then the file is opened for atomic - /// append directly and a FileOutputStream constructed with the resulting handle. This is because a - /// FileOutputStream created to append to a file does not open the file in a manner that guarantees that writes - /// by the child process will be atomic. - /// - /// - /// - /// - static FileStream NewFileOutputStream(object f, bool append) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var path = FileAccessor.InvokeGetPath(f); - var sm = SystemAccessor.InvokeGetSecurityManager(); - if (sm != null) - SecurityManagerAccessor.InvokeCheckWrite(sm, path); - - if (append) - { - return OpenForAtomicAppend(path); - } - else - { - return File.OpenWrite(path); - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/java/net/PlainDatagramSocketImpl.cs b/src/IKVM.Runtime/Java/Externs/java/net/PlainDatagramSocketImpl.cs deleted file mode 100644 index e374e5bd5c..0000000000 --- a/src/IKVM.Runtime/Java/Externs/java/net/PlainDatagramSocketImpl.cs +++ /dev/null @@ -1,1424 +0,0 @@ -using System; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Net; -using System.Net.Sockets; -using System.Reflection; -using System.Runtime.InteropServices; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.JNI; -using IKVM.Runtime.Util.Java.Net; - -using static IKVM.Java.Externs.java.net.SocketImplUtil; - -namespace IKVM.Java.Externs.java.net -{ - - /// - /// Implements the external methods for . - /// - static class PlainDatagramSocketImpl - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - - /// - /// Compiles a fast getter for a . - /// - /// - /// - /// - /// - static Func MakeFieldGetter(FieldInfo field) - { - var p = Expression.Parameter(typeof(T)); - var e = Expression.Lambda>(Expression.Field(Expression.ConvertChecked(p, field.DeclaringType), field), p); - return e.Compile(); - } - - /// - /// Compiles a fast setter for a . - /// - /// - /// - /// - /// - static Action MakeFieldSetter(FieldInfo field) - { - var p = Expression.Parameter(typeof(T)); - var v = Expression.Parameter(typeof(V)); - var e = Expression.Lambda>(Expression.Assign(Expression.Field(field.DeclaringType.IsValueType ? Expression.Unbox(p, field.DeclaringType) : Expression.ConvertChecked(p, field.DeclaringType), field), v), p, v); - return e.Compile(); - } - - /// - /// Compiles a fast method invoker for a . - /// - /// - /// - /// - /// - static Action MakeAnonymousTypeDelegate(MethodInfo method) - { - var p = Expression.Parameter(typeof(T)); - var arg = Expression.Parameter(typeof(TArg)); - var e = Expression.Lambda>(Expression.Call(Expression.ConvertChecked(p, method.DeclaringType), method, arg), p, arg); - return e.Compile(); - } - - static readonly MethodInfo InetAddressHolderMethod = typeof(global::java.net.InetAddress).GetMethod("holder", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Func InetAddressHolderDelegate = (Func)InetAddressHolderMethod.CreateDelegate(typeof(Func)); - static readonly FieldInfo InetAddressHolderAddressField = typeof(global::java.net.InetAddress).GetNestedType("InetAddressHolder", BindingFlags.NonPublic).GetField("address", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Action InetAddressHolderAddressSetter = MakeFieldSetter(InetAddressHolderAddressField); - static readonly FieldInfo Inet6AddressHolderField = typeof(global::java.net.Inet6Address).GetField("holder6", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Func Inet6AddressHolderGetter = MakeFieldGetter(Inet6AddressHolderField); - static readonly MethodInfo Inet6AddressHolderSetIpAddressMethod = typeof(global::java.net.Inet6Address).GetNestedType("Inet6AddressHolder", BindingFlags.NonPublic).GetMethod("setAddr", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Action Inet6AddressHolderSetIpAddressDelegate = MakeAnonymousTypeDelegate(Inet6AddressHolderSetIpAddressMethod); - static readonly FieldInfo NetworkInterfaceIndexField = typeof(global::java.net.NetworkInterface).GetField("index", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Action NetworkInterfaceIndexSetter = MakeFieldSetter(NetworkInterfaceIndexField); - static readonly FieldInfo NetworkInterfaceAddrsField = typeof(global::java.net.NetworkInterface).GetField("addrs", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Action NetworkInterfaceAddrsSetter = MakeFieldSetter(NetworkInterfaceAddrsField); - static readonly FieldInfo NetworkInterfaceNameField = typeof(global::java.net.NetworkInterface).GetField("name", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Action NetworkInterfaceNameSetter = MakeFieldSetter(NetworkInterfaceNameField); - static readonly FieldInfo AbstractPlainDatagramSocketImplTrafficClassField = typeof(global::java.net.AbstractPlainDatagramSocketImpl).GetField("trafficClass", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Func AbstractPlainDatagramSocketImplTrafficClassGetter = MakeFieldGetter(AbstractPlainDatagramSocketImplTrafficClassField); - static readonly FieldInfo Inet6AddressCachedScopeIdField = typeof(global::java.net.Inet6Address).GetField("cached_scope_id", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Action Inet6AddressCachedScopeIdSetter = MakeFieldSetter(Inet6AddressCachedScopeIdField); - static readonly Func Inet6AddressCachedScopeIdGetter = MakeFieldGetter(Inet6AddressCachedScopeIdField); - - static global::ikvm.@internal.CallerID __callerID; - delegate void __jniDelegate__init(IntPtr jniEnv, IntPtr self); - static __jniDelegate__init __jniPtr__init; - delegate void __jniDelegate__disconnect0(IntPtr jniEnv, IntPtr self, int family); - static __jniDelegate__disconnect0 __jniPtr__disconnect0; - -#if NETCOREAPP3_1_OR_GREATER - - // HACK .NET Core has an explicit check for _isConnected https://github.com/dotnet/runtime/issues/77962 - static readonly FieldInfo SocketIsConnectedField = typeof(Socket).GetField("_isConnected", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Action SocketIsConnectedFieldSetter = MakeFieldSetter(SocketIsConnectedField); - - [DllImport("libc", SetLastError = true)] - static unsafe extern int setsockopt(SafeHandle sockfd, int level, int optname, void* optval, int optlen); - - [DllImport("libc", SetLastError = true)] - static unsafe extern int getsockopt(SafeHandle sockfd, int level, int optname, void* optval, int* optlen); - - const int IPPROTO_IP = 0; - const int IPPROTO_IPV6 = 41; - const int IP_MULTICAST_LOOP = 34; - const int IPV6_MULTICAST_LOOP = 19; - -#endif - - const IOControlCode SIO_UDP_CONNRESET = (IOControlCode)(-1744830452); - static readonly byte[] IOControlTrueBuffer = BitConverter.GetBytes(1); - static readonly byte[] IOControlFalseBuffer = BitConverter.GetBytes(0); - static readonly byte[] TempBuffer = new byte[1]; - - /// - /// Converts the given into an appropriate endpoint address. - /// - /// - /// - static IPAddress GetEndPointAddress(global::java.net.InetAddress address) - { - var a = address.ToIPAddress(); - if (address is global::java.net.Inet6Address ip6 && a.IsIPv6LinkLocal && a.ScopeId == 0) - a.ScopeId = GetDefaultScopeId(ip6); - return a; - } - - /// - /// Attempts to get the scope ID of a link-local . - /// - /// - /// - static int GetDefaultScopeId(global::java.net.Inet6Address address) - { - if (Inet6AddressCachedScopeIdGetter(address) is int s2 and not 0) - return s2; - - // for Linux we need to obtain the default scope ID by effectively doing a route lookup - if (RuntimeUtil.IsLinux && FindScopeId(address) is int s3 and not 0) - { - Inet6AddressCachedScopeIdSetter(address, s3); - return s3; - } - - return 0; - } - - /// - /// Attempts to lookup the scope id from a non-scoped address. - /// - /// - /// - static int FindScopeId(global::java.net.Inet6Address address) - { - var l = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces() - .SelectMany(i => i.GetIPProperties().UnicastAddresses) - .Where(i => i.Address.IsIPv6LinkLocal && i.Address.ScopeId != 0) - .Where(i => MemoryExtensions.SequenceEqual(i.Address.GetAddressBytes().AsSpan(), address.getAddress().AsSpan())) - .Take(2) - .ToList(); - - if (l.Count > 1) - throw new global::java.net.SocketException("Duplicate link local addresses: must specify scope-id"); - if (l.Count > 0) - return (int)l[0].Address.ScopeId; - - return 0; - } - -#endif - - /// - /// Implements the native method for 'initProto'. - /// - public static void init() - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainDatagramSocketImpl).TypeHandle); - __jniPtr__init ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__init>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainDatagramSocketImpl", nameof(init), "()V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__init(jniEnv, jniFrm.MakeLocalRef(ClassLiteral.Value)); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'datagramSocketCreate'. - /// - /// - /// - public static void datagramSocketCreate(object this_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(this_, impl => - { - var socket = new Socket(SocketType.Dgram, ProtocolType.Udp); - - // default socket options - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); - - // SIO_UDP_CONNRESET fixes a "bug" introduced in Windows 2000, which - // returns connection reset errors on unconnected UDP sockets (as well - // as connected sockets). The solution is to only enable this feature - // when the socket is connected. - if (RuntimeUtil.IsWindows) - socket.IOControl(SIO_UDP_CONNRESET, IOControlFalseBuffer, null); - - FileDescriptorAccessor.SetSocket(impl.fd, socket); - }); -#endif - } - - /// - /// Implements the native method for 'datagramSocketClose'. - /// - /// - /// - /// - public static void datagramSocketClose(object this_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var impl = (global::java.net.PlainDatagramSocketImpl)this_; - if (impl == null || impl.fd == null) - return; - - try - { - var h = FileDescriptorAccessor.GetHandle(impl.fd); - FileDescriptorAccessor.SetHandle(impl.fd, -1); - LibIkvm.Instance.io_close_socket(h); - } - catch - { - // ignore - } -#endif - } - - /// - /// Implements the native method for 'connect0'. - /// - /// - /// - /// - /// - /// - public static void connect0(object this_, object address_, int port) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(this_, address_, (impl, address) => - { - InvokeWithSocket(impl, socket => - { - if (address == null) - throw new global::java.lang.NullPointerException(nameof(address)); - -#if NETCOREAPP3_1_OR_GREATER - // HACK .NET Core has an explicit check for _isConnected https://github.com/dotnet/runtime/issues/77962 - SocketIsConnectedFieldSetter(socket, false); -#endif - socket.EndConnect(socket.BeginConnect(GetEndPointAddress(address), port, null, null)); - - // see comment in in socketCreate - if (RuntimeUtil.IsWindows) - socket.IOControl(SIO_UDP_CONNRESET, IOControlTrueBuffer, null); - }); - }); -#endif - } - - /// - /// Implements the native method for 'disconnect0'. - /// - /// - /// - /// - /// - public static void disconnect0(object this_, int family) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - InvokeAction(this_, (Action)(impl => - { - if (impl.fd == null || impl.fd.getSocket() == null) - return; - - InvokeWithSocket(impl, socket => - { - // NOTE we use async connect to work around the issue that the .NET Socket class disallows sync Connect after the socket has received WSAECONNRESET -#if NETCOREAPP3_1_OR_GREATER - // HACK .NET Core has an explicit check for _isConnected https://github.com/dotnet/runtime/issues/77962 - SocketIsConnectedFieldSetter(socket, false); -#endif - socket.EndConnect(socket.BeginConnect(new IPEndPoint(IPAddress.IPv6Any, 0), null, null)); - - // see comment in in socketCreate - if (RuntimeUtil.IsWindows) - socket.IOControl(SIO_UDP_CONNRESET, IOControlFalseBuffer, null); - }); - })); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainDatagramSocketImpl).TypeHandle); - __jniPtr__disconnect0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__disconnect0>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainDatagramSocketImpl", nameof(disconnect0), "(I)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__disconnect0(jniEnv, jniFrm.MakeLocalRef(ClassLiteral.Value), family); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'bind0'. - /// - /// - /// - /// - /// - /// - public static void bind0(object this_, int localPort, object localAddress_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(this_, localAddress_, (impl, localAddress) => - { - InvokeWithSocket(impl, socket => - { - if (localAddress == null) - throw new global::java.lang.NullPointerException(nameof(localAddress)); - - // bind to appropriate address - socket.Bind(new IPEndPoint(localAddress.isAnyLocalAddress() ? IPAddress.IPv6Any : GetEndPointAddress(localAddress), localPort)); - - // check that we bound to an IP endpoint - var localEndpoint = socket.LocalEndPoint; - if (localEndpoint is not IPEndPoint ipLocalEndpoint) - throw new global::java.net.SocketException("Unexpected resulting endpoint type."); - - // set localport - impl.localPort = ipLocalEndpoint.Port; - }); - }); -#endif - } - - /// - /// Implements the native method for 'send'. - /// - /// - /// - /// - /// - public static void send(object this_, object packet_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(this_, packet_, (impl, packet) => - { - InvokeWithSocket(impl, socket => - { - if (packet == null) - throw new global::java.lang.NullPointerException(nameof(packet)); - - if (Socket.OSSupportsIPv6) - { - var trafficClass = AbstractPlainDatagramSocketImplTrafficClassGetter(impl); - if (trafficClass != 0) - socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.TypeOfService, trafficClass); - } - - var prevBlocking = socket.Blocking; - var prevSendTimeout = socket.SendTimeout; - - try - { - socket.Blocking = true; - socket.SendTimeout = 0; - socket.SendTo(packet.buf, packet.offset, packet.length, SocketFlags.None, new IPEndPoint(GetEndPointAddress(packet.getAddress()), packet.getPort())); - } - finally - { - socket.Blocking = prevBlocking; - socket.SendTimeout = prevSendTimeout; - } - }); - }); -#endif - } - - /// - /// Implements the native method for 'dataAvailable'. - /// - /// - /// - /// - public static int dataAvailable(object this_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(this_, impl => - { - return InvokeWithSocket(impl, socket => - { - return socket.Available; - }); - }); -#endif - } - - /// - /// Implements the native method for 'peek'. - /// - /// - /// - /// - /// - /// - public static int peek(object this_, object address_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(this_, address_, (impl, address) => - { - return InvokeWithSocket(impl, socket => - { - if (address == null) - throw new global::java.lang.NullPointerException(nameof(address)); - - try - { - // wait for data to be available - if (impl.timeout > 0) - if (socket.Poll((int)Math.Min(impl.timeout * 1000L, int.MaxValue), SelectMode.SelectRead) == false) - throw new global::java.net.SocketTimeoutException("Peek timed out."); - - var remoteEndpoint = (EndPoint)new IPEndPoint(IPAddress.IPv6Any, 0); - var length = socket.EndReceiveFrom(socket.BeginReceiveFrom(TempBuffer, 0, 1, SocketFlags.Peek, ref remoteEndpoint, null, null), ref remoteEndpoint); - - // check that we received an IP endpoint - if (remoteEndpoint is not IPEndPoint ipRemoteEndpoint) - throw new global::java.net.SocketException("Unexpected resulting endpoint type."); - - if (ipRemoteEndpoint.AddressFamily == AddressFamily.InterNetworkV6) - { - if (address is global::java.net.Inet6Address address6) - { - // InetAddress stores its data on a nested 'holder' instance - var holder = Inet6AddressHolderGetter(address6); - if (holder == null) - throw new global::java.net.SocketException("Could not get Inet6Address holder."); - - // set the address directly onto the holder - var bytes = ipRemoteEndpoint.Address.GetAddressBytes(); - Inet6AddressHolderSetIpAddressDelegate(holder, bytes); - } - else if (ipRemoteEndpoint.Address.IsIPv4MappedToIPv6) - { - // InetAddress stores its data on a nested 'holder' instance - var holder = InetAddressHolderDelegate(address); - if (holder == null) - throw new global::java.net.SocketException("Could not get InetAddress holder."); - - // set the address directly onto the holder - var bytes = BinaryPrimitives.ReadInt32BigEndian(ipRemoteEndpoint.Address.MapToIPv4().GetAddressBytes()); - InetAddressHolderAddressSetter(holder, bytes); - } - } - else if (ipRemoteEndpoint.AddressFamily == AddressFamily.InterNetwork) - { - if (address is global::java.net.Inet6Address address6) - { - // InetAddress stores its data on a nested 'holder' instance - var holder = Inet6AddressHolderGetter(address6); - if (holder == null) - throw new global::java.net.SocketException("Could not get Inet6Address holder."); - - // set the address directly onto the holder - var bytes = ipRemoteEndpoint.Address.MapToIPv6().GetAddressBytes(); - Inet6AddressHolderSetIpAddressDelegate(holder, bytes); - } - else - { - // InetAddress stores its data on a nested 'holder' instance - var holder = InetAddressHolderDelegate(address); - if (holder == null) - throw new global::java.net.SocketException("Could not get InetAddress holder."); - - // set the address directly onto the holder - var bytes = BinaryPrimitives.ReadInt32BigEndian(ipRemoteEndpoint.Address.GetAddressBytes()); - InetAddressHolderAddressSetter(holder, bytes); - } - } - - return ipRemoteEndpoint.Port; - } - finally - { - - } - }); - }); -#endif - } - -#if !FIRST_PASS - - /// - /// Peek at the queue to see if there is an ICMP port unreachable. If there is then receive it. - /// - /// - static void PurgeOutstandingICMP(Socket socket) - { - // check for outstanding packet - while (socket.Poll(0, SelectMode.SelectRead)) - { - var ep = (EndPoint)new IPEndPoint(IPAddress.IPv6Any, 0); - - // check for real data on the socket, if so, we can exit, no exceptions - try - { - socket.EndReceiveFrom(socket.BeginReceiveFrom(TempBuffer, 0, TempBuffer.Length, SocketFlags.Peek, ref ep, null, null), ref ep); - return; - } - catch - { - // swallow any exceptions emitted by peek, the exception will be thrown again upon following read - } - - // consume real data (exception) - try - { - socket.EndReceiveFrom(socket.BeginReceiveFrom(TempBuffer, 0, TempBuffer.Length, SocketFlags.None, ref ep, null, null), ref ep); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionReset) - { - // we consumed exception reset and thus can continue to look for next - } - catch - { - // some other exception besides connection reset - // ignore since the purge method should only purge - return; - } - } - } - -#endif - - /// - /// Implements the native method for 'peekData'. - /// - /// - /// - /// - /// - /// - public static int peekData(object this_, object packet_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(this_, packet_, (impl, packet) => - { - return InvokeWithSocket(impl, socket => - { - if (packet == null) - throw new global::java.lang.NullPointerException("packet"); - if (packet.buf == null) - throw new global::java.lang.NullPointerException("packet buffer"); - - try - { - if (impl.timeout > 0) - { - // Windows Poll method reports errors as readable, however, Linux reports it as errored, so - // we can use Poll on Windows for both errors, but must use Select on Linux to trap both - // read and error states - if (RuntimeUtil.IsWindows) - { - try - { - // wait for data to be available - if (socket.Poll((int)Math.Min(impl.timeout * 1000L, int.MaxValue), SelectMode.SelectRead) == false) - throw new global::java.net.SocketTimeoutException("Receive timed out."); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.TimedOut) - { - throw new global::java.net.SocketTimeoutException("Receive timed out."); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.Interrupted) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch - { - throw; - } - } - else - { - try - { - var rl = new List() { socket }; - var el = new List() { socket }; - Socket.Select(rl, null, el, (int)Math.Min(impl.timeout * 1000L, int.MaxValue)); - if (rl.Count == 0 && el.Count == 0) - throw new global::java.net.SocketTimeoutException("Receive timed out."); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.TimedOut) - { - throw new global::java.net.SocketTimeoutException("Receive timed out."); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.Interrupted) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch - { - throw; - } - } - } - - var remoteEndpoint = (EndPoint)new IPEndPoint(IPAddress.IPv6Any, 0); - var length = 0; - - try - { - length = socket.EndReceiveFrom(socket.BeginReceiveFrom(packet.buf, packet.offset, packet.bufLength, SocketFlags.Peek, ref remoteEndpoint, null, null), ref remoteEndpoint); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.MessageSize) - { - // message size error indicates we did read something, but not the whole message - // just return what we did read, since it's UDP and nobody cares anyways - length = packet.bufLength; - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionReset) - { - // Windows may leave multiple ICMP packets on the socket, purge them - if (RuntimeUtil.IsWindows) - PurgeOutstandingICMP(socket); - - throw new global::java.net.PortUnreachableException("ICMP Port Unreachable"); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionRefused) - { - throw new global::java.net.PortUnreachableException("ICMP Port Unreachable"); - } - catch - { - // some other exception, report no data read - packet.port = 0; - packet.length = 0; - throw; - } - - // check that we received an IP endpoint - if (remoteEndpoint is not IPEndPoint ipRemoteEndpoint) - throw new global::java.net.SocketException("Unexpected resulting endpoint type."); - - var remoteAddress = ipRemoteEndpoint.ToInetAddress(); - var packetAddress = packet.address; - if (packetAddress == null || packetAddress.equals(remoteAddress) == false) - packet.address = ipRemoteEndpoint.ToInetAddress(); - - packet.port = ipRemoteEndpoint.Port; - packet.length = length; - return ipRemoteEndpoint.Port; - } - finally - { - - } - }); - }); -#endif - } - - /// - /// Implements the native method for 'receive0'. - /// - /// - /// - /// - /// - public static void receive0(object this_, object packet_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(this_, packet_, (impl, packet) => - { - InvokeWithSocket(impl, socket => - { - if (packet == null) - throw new global::java.lang.NullPointerException("packet"); - if (packet.buf == null) - throw new global::java.lang.NullPointerException("packet buffer"); - - try - { - if (impl.timeout > 0) - { - // Windows Poll method reports errors as readable, however, Linux reports it as errored, so - // we can use Poll on Windows for both errors, but must use Select on Linux to trap both - // read and error states - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - try - { - if (socket.Poll((int)Math.Min(impl.timeout * 1000L, int.MaxValue), SelectMode.SelectRead) == false) - throw new global::java.net.SocketTimeoutException("Receive timed out."); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.TimedOut) - { - throw new global::java.net.SocketTimeoutException("Receive timed out."); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.Interrupted) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch - { - throw; - } - } - else - { - try - { - var rl = new List() { socket }; - var el = new List() { socket }; - Socket.Select(rl, null, el, (int)Math.Min(impl.timeout * 1000L, int.MaxValue)); - if (rl.Count == 0 && el.Count == 0) - throw new global::java.net.SocketTimeoutException("Receive timed out."); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.TimedOut) - { - throw new global::java.net.SocketTimeoutException("Receive timed out."); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.Interrupted) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch - { - throw; - } - } - } - - var remoteEndpoint = (EndPoint)new IPEndPoint(IPAddress.IPv6Any, 0); - var length = 0; - - try - { - length = socket.EndReceiveFrom(socket.BeginReceiveFrom(packet.buf, packet.offset, packet.bufLength, SocketFlags.None, ref remoteEndpoint, null, null), ref remoteEndpoint); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.MessageSize) - { - // message size error indicates we did read something, but not the whole message - // just return what we did read, since it's UDP and nobody cares anyways - length = packet.bufLength; - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionReset) - { - // Windows may leave multiple ICMP packets on the socket, purge them - if (RuntimeUtil.IsWindows) - PurgeOutstandingICMP(socket); - - throw new global::java.net.PortUnreachableException("ICMP Port Unreachable"); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionRefused) - { - throw new global::java.net.PortUnreachableException("ICMP Port Unreachable"); - } - catch - { - // some other exception, report no data read - packet.offset = 0; - packet.length = 0; - throw; - } - - // check that we received an IP endpoint - if (remoteEndpoint is not IPEndPoint ipRemoteEndpoint) - throw new global::java.net.SocketException("Unexpected resulting endpoint type."); - - var remoteAddress = ipRemoteEndpoint.ToInetAddress(); - var packetAddress = packet.address; - if (packetAddress == null || packetAddress.equals(remoteAddress) == false) - packet.address = ipRemoteEndpoint.ToInetAddress(); - - packet.port = ipRemoteEndpoint.Port; - packet.length = length; - return ipRemoteEndpoint.Port; - } - finally - { - - } - }); - }); -#endif - } - - /// - /// Implements the native method for 'setTimeToLive'. - /// - /// - /// - /// - /// - public static void setTimeToLive(object this_, int ttl) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(this_, (impl) => - { - InvokeWithSocket(impl, socket => - { - socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive, ttl); - }); - }); -#endif - } - - /// - /// Implements the native method for 'getTimeToLive'. - /// - /// - /// - /// - /// - public static int getTimeToLive(object this_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(this_, (impl) => - { - return InvokeWithSocket(impl, socket => - { - return (int)socket.GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive); - }); - }); -#endif - } - - /// - /// Implements the native method for 'setTTL'. - /// - /// - /// - /// - /// - public static void setTTL(object this_, byte ttl) - { - setTimeToLive(this_, ttl); - } - - /// - /// Implements the native method for 'getTTL'. - /// - /// - /// - /// - /// - public static byte getTTL(object this_) - { - return (byte)getTimeToLive(this_); - } - -#if !FIRST_PASS - - /// - /// Implements the backend for 'join' and 'leave' methods. - /// - /// - /// - /// - /// - /// - /// - static void JoinOrLeave(Socket socket, global::java.net.InetAddress inetaddr, global::java.net.NetworkInterface netIf, SocketOptionName action) - { - if (inetaddr == null) - throw new global::java.lang.NullPointerException(nameof(inetaddr)); - - var addr = GetEndPointAddress(inetaddr); - var ipv6 = Socket.OSSupportsIPv6 && addr.AddressFamily == AddressFamily.InterNetworkV6; - - // attempt to join IPv6 multicast - if (ipv6) - { - var o = new IPv6MulticastOption(addr); - if (netIf != null) - o.InterfaceIndex = netIf.getIndex(); - - try - { - socket.SetSocketOption(SocketOptionLevel.IPv6, action, o); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ProtocolNotSupported) - { - ipv6 = false; // fallback to IPv4 - } - } - - if (ipv6 == false) - { - var o = new MulticastOption(addr); - if (netIf != null) - o.InterfaceIndex = netIf.getIndex(); - - socket.SetSocketOption(SocketOptionLevel.IP, action, o); - } - } - -#endif - - /// - /// Implements the native method for 'join'. - /// - /// - /// - /// - /// - /// - public static void join(object this_, object inetaddr_, object netIf_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(this_, inetaddr_, netIf_, (impl, inetaddr, netIf) => - { - InvokeWithSocket(impl, socket => - { - JoinOrLeave(socket, inetaddr, netIf, SocketOptionName.AddMembership); - }); - }); -#endif - } - - /// - /// Implements the native method for 'leave'. - /// - /// - /// - /// - /// - /// - public static void leave(object this_, object inetaddr_, object netIf_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(this_, inetaddr_, netIf_, (impl, inetaddr, netIf) => - { - InvokeWithSocket(impl, socket => - { - JoinOrLeave(socket, inetaddr, netIf, SocketOptionName.DropMembership); - }); - }); -#endif - } - -#if !FIRST_PASS - - /// - /// Implements the getter of the socket options IP_MULTICAST_IF and IP_MULTICAST_IF2. - /// - /// - /// - /// - /// - /// - static object GetMulticastInterfaceOption(Socket socket, int option) - { - if (socket is null) - throw new ArgumentNullException(nameof(socket)); - - var index = (int)socket.GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastInterface); - if (index < 0) - throw new global::java.net.SocketException("Error getting socket option."); - - // index of socket is set - if (index > 0) - { - // find network interface with the index - var iface = global::java.net.NetworkInterface.getByIndex(index); - if (iface == null) - throw new global::java.net.SocketException($"IPV6_MULTICAST_IF returned index to unrecognized interface: {index}."); - - // IP_MULTICAST_IF2 wants the NetworkInterface directly - if (option == global::java.net.SocketOptions.IP_MULTICAST_IF2) - return iface; - - // otherwise collect the InetAddresses and return the first entry - var addresses = new List(); - for (var e = iface.getInetAddresses(); e.hasMoreElements();) - addresses.Add((global::java.net.InetAddress)e.nextElement()); - if (addresses.Count == 0) - throw new global::java.net.SocketException("IPV6_MULTICAST_IF returned interface without IP bindings."); - - return addresses[0]; - } - - var addr = global::java.net.InetAddress.anyLocalAddress(); - if (option == global::java.net.SocketOptions.IP_MULTICAST_IF) - return addr; - - // return a new anonymous network interface with index -1 and empty address array - var anon = new global::java.net.NetworkInterface(); - NetworkInterfaceIndexSetter(anon, -1); - NetworkInterfaceAddrsSetter(anon, Array.Empty()); - NetworkInterfaceNameSetter(anon, ""); - return anon; - } - -#endif - - /// - /// Implements the native method for 'socketGetOption'. - /// - /// - /// - /// - /// - /// - public static object socketGetOption(object this_, int opt) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(this_, impl => - { - return InvokeWithSocket(impl, socket => - { - // .NET provides property - if (opt == global::java.net.SocketOptions.SO_BINDADDR) - return ((IPEndPoint)socket.LocalEndPoint).ToInetAddress(); - - // .NET provides property - if (opt == global::java.net.SocketOptions.SO_TIMEOUT) - return socket.ReceiveTimeout; - - // .NET provides property - if (opt == global::java.net.SocketOptions.SO_LINGER) - return socket.LingerState.Enabled ? socket.LingerState.LingerTime : -1; - - // .NET provides property - if (opt == global::java.net.SocketOptions.SO_RCVBUF) - return socket.ReceiveBufferSize; - - // .NET provides property - if (opt == global::java.net.SocketOptions.SO_SNDBUF) - return socket.SendBufferSize; - - // .NET provides property - if (opt == global::java.net.SocketOptions.IP_MULTICAST_LOOP) - { -#if NETCOREAPP3_1_OR_GREATER - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - return socket.MulticastLoopback ? global::java.lang.Boolean.FALSE : global::java.lang.Boolean.TRUE; - else - { - unsafe - { - var val = 0; - var len = sizeof(int); - if (getsockopt(socket.SafeHandle, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, &len) != 0) - throw new SocketException(Marshal.GetLastWin32Error()); - - return val != 0 ? global::java.lang.Boolean.FALSE : global::java.lang.Boolean.TRUE; - } - } -#else - return socket.MulticastLoopback ? global::java.lang.Boolean.FALSE : global::java.lang.Boolean.TRUE; -#endif - } - - // IP_MULTICAST_IF returns an InetAddress while IP_MULTICAST_IF2 returns a NetworkInterface - if (opt == global::java.net.SocketOptions.IP_MULTICAST_IF || - opt == global::java.net.SocketOptions.IP_MULTICAST_IF2) - return GetMulticastInterfaceOption(socket, opt); - - // .NET provides property - if (opt == global::java.net.SocketOptions.TCP_NODELAY) - return socket.NoDelay ? 1 : -1; - - // lookup option options - if (SocketOptionUtil.TryGetDotNetSocketOption(opt, out var options) == false) - throw new global::java.net.SocketException("Invalid option."); - - // configure socket - return socket.GetSocketOption(options.Level, options.Name) switch - { - bool b => GetSocketOptionGetValue(options.Type, b), - int i => GetSocketOptionGetValue(options.Type, i), - _ => throw new global::java.net.SocketException("Invalid option value."), - }; - }); - }); -#endif - } - -#if !FIRST_PASS - - /// - /// Implements the setter of the socket options IP_MULTICAST_IF and IP_MULTICAST_IF2. - /// - /// - /// - /// - /// - /// - static void SetMulticastInterface(Socket socket, int option, object value) - { - if (socket is null) - throw new ArgumentNullException(nameof(socket)); - - // IP_MULTICAST_IF accepts an InetAddress, which must be converted to an interface index - if (option == global::java.net.SocketOptions.IP_MULTICAST_IF) - { - if (value is not global::java.net.InetAddress inetAddr) - throw new global::java.net.SocketException("Bad argument for IP_MULTICAST_IF: value is not an address"); - - // find interface that matches address - var iface = global::java.net.NetworkInterface.getByInetAddress(inetAddr); - if (iface == null) - throw new global::java.net.SocketException("Bad argument for IP_MULTICAST_IF: address not bound to any interface."); - - socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastInterface, iface.getIndex()); - return; - } - - // IP_MULTICAST_IF accepts a NetworkInterface, which must be converted to an interface index - if (option == global::java.net.SocketOptions.IP_MULTICAST_IF2) - { - if (value is not global::java.net.NetworkInterface ni) - throw new global::java.net.SocketException("Bad argument for IP_MULTICAST_IF2: value is not an interface"); - - socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastInterface, ni.getIndex()); - return; - } - - return; - } - -#endif - - /// - /// Implements the native method for 'socketSetOption'. - /// - /// - /// - /// - /// - /// - public static void socketSetOption0(object this_, int opt, object value) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(this_, impl => - { - InvokeWithSocket(impl, socket => - { - if (value == null) - throw new global::java.lang.NullPointerException(nameof(value)); - - // .NET provides property - if (opt == global::java.net.SocketOptions.SO_TIMEOUT) - { - var val = (global::java.lang.Integer)value; - socket.ReceiveTimeout = val.intValue(); - return; - } - - // .NET provides a property - if (opt == global::java.net.SocketOptions.SO_RCVBUF) - { - var val = (global::java.lang.Integer)value; - socket.ReceiveBufferSize = val.intValue(); - return; - } - - // .NET provides a property - if (opt == global::java.net.SocketOptions.SO_SNDBUF) - { - var val = (global::java.lang.Integer)value; - socket.SendBufferSize = val.intValue(); - return; - } - - // multicast options may receive InetAddress or NetworkInterface - if (opt == global::java.net.SocketOptions.IP_MULTICAST_IF || - opt == global::java.net.SocketOptions.IP_MULTICAST_IF2) - { - SetMulticastInterface(socket, opt, value); - return; - } - - // implementation changes based on IP/IPv6 - if (opt == global::java.net.SocketOptions.IP_MULTICAST_LOOP) - { -#if NETCOREAPP3_1_OR_GREATER - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var val = (global::java.lang.Boolean)value; - socket.MulticastLoopback = !val.booleanValue(); - return; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - unsafe - { - var val = ((global::java.lang.Boolean)value).booleanValue() ? 0 : 1; - if (setsockopt(socket.SafeHandle, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, sizeof(int)) != 0) - throw new SocketException(Marshal.GetLastWin32Error()); - } - - return; - } - else - { - throw new global::java.net.SocketException("Invalid option."); - } -#else - var val = (global::java.lang.Boolean)value; - socket.MulticastLoopback = !val.booleanValue(); - return; -#endif - } - - // .NET provides a property - if (opt == global::java.net.SocketOptions.TCP_NODELAY) - { - var val = (global::java.lang.Integer)value; - socket.NoDelay = val.intValue() != -1; - return; - } - - // lookup option options - if (SocketOptionUtil.TryGetDotNetSocketOption(opt, out var options) == false) - throw new global::java.net.SocketException("Invalid option."); - - // configure socket - socket.SetSocketOption(options.Level, options.Name, value switch - { - global::java.lang.Boolean b => GetSocketOptionSetValue(options.Type, b.booleanValue()), - global::java.lang.Integer i => GetSocketOptionSetValue(options.Type, i.intValue()), - _ => throw new global::java.net.SocketException("Invalid option value."), - }); - }); - }); -#endif - } - -#if !FIRST_PASS - - /// - /// Handles socket options stored as a boolean. - /// - /// - /// - /// - /// - static int GetSocketOptionSetValue(SocketOptionUtil.SocketOptionType type, bool value) => type switch - { - SocketOptionUtil.SocketOptionType.Boolean => value ? 1 : 0, - SocketOptionUtil.SocketOptionType.Integer => value ? 1 : 0, - _ => throw new global::java.net.SocketException("Invalid option value."), - }; - - /// - /// Handles socket options stored as an integer. - /// - /// - /// - /// - /// - static int GetSocketOptionSetValue(SocketOptionUtil.SocketOptionType type, int value) => type switch - { - SocketOptionUtil.SocketOptionType.Boolean => (value != -1) ? 1 : 0, - SocketOptionUtil.SocketOptionType.Integer => value, - _ => throw new global::java.net.SocketException("Invalid option value."), - }; - - /// - /// Handles socket options stored as a boolean. - /// - /// - /// - /// - /// - static object GetSocketOptionGetValue(SocketOptionUtil.SocketOptionType type, bool value) => type switch - { - SocketOptionUtil.SocketOptionType.Boolean => new global::java.lang.Boolean(value), - _ => throw new global::java.net.SocketException("Invalid option value."), - }; - - /// - /// Handles socket options stored as an integer. - /// - /// - /// - /// - /// - static object GetSocketOptionGetValue(SocketOptionUtil.SocketOptionType type, int value) => type switch - { - SocketOptionUtil.SocketOptionType.Boolean => value == 0 ? global::java.lang.Boolean.FALSE : global::java.lang.Boolean.TRUE, - SocketOptionUtil.SocketOptionType.Integer => new global::java.lang.Integer(value), - SocketOptionUtil.SocketOptionType.Unknown => value, - _ => throw new global::java.net.SocketException("Invalid option value."), - }; - -#endif - -#if !FIRST_PASS - - /// - /// Invokes the given action with the current socket, catching and mapping any resulting .NET exceptions. - /// - /// - /// - /// - /// - /// - /// - static void InvokeWithSocket(global::java.net.PlainDatagramSocketImpl impl, Action action) - { - var socket = impl.fd?.getSocket(); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - action(socket); - } - - /// - /// Invokes the given function with the current socket, catching and mapping any resulting .NET exceptions. - /// - /// - /// - /// - /// - /// - /// - static TResult InvokeWithSocket(global::java.net.PlainDatagramSocketImpl impl, Func func) - { - var socket = impl.fd?.getSocket(); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - return func(socket); - } - -#endif - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/java/net/PlainSocketImpl.cs b/src/IKVM.Runtime/Java/Externs/java/net/PlainSocketImpl.cs deleted file mode 100644 index 47bfc8581b..0000000000 --- a/src/IKVM.Runtime/Java/Externs/java/net/PlainSocketImpl.cs +++ /dev/null @@ -1,1044 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Net; -using System.Net.Sockets; -using System.Reflection; -using System.Runtime.InteropServices; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.JNI; -using IKVM.Runtime.Util.Java.Net; - -using static IKVM.Java.Externs.java.net.SocketImplUtil; - -namespace IKVM.Java.Externs.java.net -{ - - /// - /// Implements the external methods for . - /// - static class PlainSocketImpl - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - static PlainSocketImplAccessor plainSocketImplAccessor; - - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - - static PlainSocketImplAccessor PlainSocketImplAccessor => JVM.Internal.BaseAccessors.Get(ref plainSocketImplAccessor); - - [Flags] - enum HANDLE_FLAGS - { - - NONE = 0, - INHERIT = 0x00000001, - PROTECT_FROM_CLOSE = 0x00000002, - - } - -#if NETFRAMEWORK - - /// - /// Invokes the Win32 SetHandleInformation function. - /// - /// - /// - /// - /// - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool SetHandleInformation(IntPtr hObject, HANDLE_FLAGS dwMask, HANDLE_FLAGS dwFlags); -#else - - /// - /// Invokes the Win32 SetHandleInformation function. - /// - /// - /// - /// - /// - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool SetHandleInformation(SafeHandle hObject, HANDLE_FLAGS dwMask, HANDLE_FLAGS dwFlags); - -#endif - - /// - /// Compiles a fast getter for a . - /// - /// - /// - /// - /// - static Func MakeFieldGetter(FieldInfo field) - { - var p = Expression.Parameter(typeof(T)); - var e = Expression.Lambda>(Expression.Field(Expression.ConvertChecked(p, field.DeclaringType), field), p); - return e.Compile(); - } - - /// - /// Compiles a fast setter for a . - /// - /// - /// - /// - /// - static Action MakeFieldSetter(FieldInfo field) - { - var p = Expression.Parameter(typeof(T)); - var v = Expression.Parameter(typeof(V)); - var e = Expression.Lambda>(Expression.Assign(Expression.Field(field.DeclaringType.IsValueType ? Expression.Unbox(p, field.DeclaringType) : Expression.ConvertChecked(p, field.DeclaringType), field), v), p, v); - return e.Compile(); - } - - static readonly FieldInfo AbstractPlainSocketImplTrafficClassField = typeof(global::java.net.AbstractPlainSocketImpl).GetField("trafficClass", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Func AbstractPlainSocketImplTrafficClassGetter = MakeFieldGetter(AbstractPlainSocketImplTrafficClassField); - static readonly FieldInfo AbstractPlainSocketImplServerSocketField = typeof(global::java.net.AbstractPlainSocketImpl).GetField("serverSocket", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Func AbstractPlainSocketImplServerSocketGetter = MakeFieldGetter(AbstractPlainSocketImplServerSocketField); - static readonly FieldInfo Inet6AddressCachedScopeIdField = typeof(global::java.net.Inet6Address).GetField("cached_scope_id", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Action Inet6AddressCachedScopeIdSetter = MakeFieldSetter(Inet6AddressCachedScopeIdField); - static readonly Func Inet6AddressCachedScopeIdGetter = MakeFieldGetter(Inet6AddressCachedScopeIdField); - - static global::ikvm.@internal.CallerID __callerID; - delegate void __jniDelegate__initProto(IntPtr jniEnv, IntPtr self); - static __jniDelegate__initProto __jniPtr__initProto; - delegate void __jniDelegate__socketCreate(IntPtr jniEnv, IntPtr self, sbyte stream); - static __jniDelegate__socketCreate __jniPtr__socketCreate; - delegate void __jniDelegate__socketConnect(IntPtr jniEnv, IntPtr self, IntPtr iaObj, int port, int timeout); - static __jniDelegate__socketConnect __jniPtr__socketConnect; - delegate void __jniDelegate__socketBind(IntPtr jniEnv, IntPtr self, IntPtr iaObj, int localport); - static __jniDelegate__socketBind __jniPtr__socketBind; - delegate void __jniDelegate__socketListen(IntPtr jniEnv, IntPtr self, int count); - static __jniDelegate__socketListen __jniPtr__socketListen; - delegate void __jniDelegate__socketAccept(IntPtr jniEnv, IntPtr self, IntPtr socket); - static __jniDelegate__socketAccept __jniPtr__socketAccept; - delegate int __jniDelegate__socketAvailable(IntPtr jniEnv, IntPtr self); - static __jniDelegate__socketAvailable __jniPtr__socketAvailable; - delegate int __jniDelegate__socketSetOption(IntPtr jniEnv, IntPtr self, int cmd, sbyte on, IntPtr value); - static __jniDelegate__socketSetOption __jniPtr__socketSetOption; - delegate int __jniDelegate__socketGetOption(IntPtr jniEnv, IntPtr self, int cmd, IntPtr iaContainerObj); - static __jniDelegate__socketGetOption __jniPtr__socketGetOption; - delegate int __jniDelegate__socketSendUrgentData(IntPtr jniEnv, IntPtr self, int data); - static __jniDelegate__socketSendUrgentData __jniPtr__socketSendUrgentData; - delegate int __jniDelegate__socketClose0(IntPtr jniEnv, IntPtr self, sbyte useDeferredClose); - static __jniDelegate__socketClose0 __jniPtr__socketClose0; - delegate int __jniDelegate__socketShutdown(IntPtr jniEnv, IntPtr self, int howto); - static __jniDelegate__socketShutdown __jniPtr__socketShutdown; - - /// - /// Converts the given into an appropriate endpoint address. - /// - /// - /// - static IPAddress GetEndPointAddress(global::java.net.InetAddress address) - { - var a = address.ToIPAddress(); - if (address is global::java.net.Inet6Address ip6 && a.IsIPv6LinkLocal && a.ScopeId == 0) - a.ScopeId = GetDefaultScopeId(ip6); - return a; - } - - /// - /// Attempts to get the scope ID of a link-local . - /// - /// - /// - static int GetDefaultScopeId(global::java.net.Inet6Address address) - { - if (Inet6AddressCachedScopeIdGetter(address) is int s2 and not 0) - return s2; - - // for Linux we need to obtain the default scope ID by effectively doing a route lookup - if (RuntimeUtil.IsLinux && FindScopeId(address) is int s3 and not 0) - { - Inet6AddressCachedScopeIdSetter(address, s3); - return s3; - } - - return 0; - } - - /// - /// Attempts to lookup the scope id from a non-scoped address. - /// - /// - /// - static int FindScopeId(global::java.net.Inet6Address address) - { - var l = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces() - .SelectMany(i => i.GetIPProperties().UnicastAddresses) - .Where(i => i.Address.IsIPv6LinkLocal && i.Address.ScopeId != 0) - .Where(i => MemoryExtensions.SequenceEqual(i.Address.GetAddressBytes().AsSpan(), address.getAddress().AsSpan())) - .Take(2) - .ToList(); - - if (l.Count > 1) - throw new global::java.net.SocketException("Duplicate link local addresses: must specify scope-id"); - if (l.Count > 0) - return (int)l[0].Address.ScopeId; - - return 0; - } - -#endif - - static readonly byte[] PeekBuffer = new byte[1]; - - /// - /// Implements the native method for 'initProto'. - /// - public static void initProto() - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__initProto ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__initProto>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(initProto), "()V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__initProto(jniEnv, jniFrm.MakeLocalRef(ClassLiteral.Value)); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'socketCreate'. - /// - public static void socketCreate(object self, bool stream) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - InvokeAction(self, impl => - { - var socket = new Socket(stream ? SocketType.Stream : SocketType.Dgram, ProtocolType.Tcp); - socket.Blocking = true; - - // if this is a server socket then enable SO_REUSEADDR automatically - if (AbstractPlainSocketImplServerSocketGetter(impl) != null) - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - - FileDescriptorAccessor.SetSocket(impl.fd, socket); - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__socketCreate ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketCreate>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(socketCreate), "(Z)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__socketCreate(jniEnv, jniFrm.MakeLocalRef(self), stream ? JNIEnv.JNI_TRUE : JNIEnv.JNI_FALSE); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'socketConnect'. - /// - public static void socketConnect(object self, object iaObj, int port, int timeout) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - InvokeAction(self, iaObj, (impl, address) => - { - var socket = FileDescriptorAccessor.GetSocket(impl.fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - var trafficClass = AbstractPlainSocketImplTrafficClassGetter(impl); - if (trafficClass != 0) - socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.TypeOfService, trafficClass); - - var prevBlocking = socket.Blocking; - - try - { - if (timeout > 0) - { - socket.Blocking = false; - - // non-blocking connect throws a WouldBlock exception, after which we Poll for completion - try - { - socket.Connect(GetEndPointAddress(address), port); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - var re = new List() { socket }; - var wr = new List() { socket }; - var ex = new List() { socket }; - Socket.Select(re, wr, ex, (int)Math.Min(timeout * 1000L, int.MaxValue)); - var er = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error); - if (er != 0) - throw new SocketException(er); - if (wr.Count == 0) - throw new global::java.net.SocketTimeoutException("Connect timed out."); - } - } - else - { - socket.Blocking = true; - socket.Connect(GetEndPointAddress(address), port); - } - - impl.address = address; - impl.port = port; - - if (impl.localport == 0) - impl.localport = ((IPEndPoint)socket.LocalEndPoint).Port; - } - catch (ObjectDisposedException) - { - throw new global::java.io.InterruptedIOException(); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.InvalidArgument) - { - throw new global::java.net.SocketException(e.Message); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionRefused) - { - throw new global::java.net.ConnectException(e.Message); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.HostUnreachable) - { - throw new global::java.net.NoRouteToHostException(e.Message); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressNotAvailable) - { - throw new global::java.net.NoRouteToHostException(e.Message); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.TimedOut) - { - throw new global::java.net.ConnectException(e.Message); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.IsConnected) - { - throw new global::java.net.SocketException("Socket closed"); - } - finally - { - socket.Blocking = prevBlocking; - } - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__socketConnect ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketConnect>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(socketConnect), "(Ljava/net/InetAddress;I)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__socketConnect(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(iaObj), port, timeout); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'socketBind'. - /// - public static void socketBind(object self, global::java.net.InetAddress iaObj, int localport) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - InvokeAction(self, impl => - { - var socket = FileDescriptorAccessor.GetSocket(impl.fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - try - { - socket.Bind(new IPEndPoint(iaObj.isAnyLocalAddress() ? IPAddress.IPv6Any : GetEndPointAddress(iaObj), localport)); - impl.address = iaObj; - impl.localport = localport == 0 ? ((IPEndPoint)socket.LocalEndPoint).Port : localport; - } - catch (ObjectDisposedException) - { - throw new global::java.io.InterruptedIOException("Bind failed"); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressAlreadyInUse) - { - throw new global::java.net.BindException("Bind failed"); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressNotAvailable) - { - throw new global::java.net.BindException("Bind failed"); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.AccessDenied) - { - throw new global::java.net.BindException("Bind failed"); - } - catch (SocketException) - { - throw new global::java.net.SocketException("Bind failed"); - } - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__socketBind ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketBind>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(socketBind), "(Ljava/net/InetAddress;I)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__socketBind(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(iaObj), localport); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'socketListen'. - /// - public static void socketListen(object self, int count) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - InvokeAction(self, impl => - { - var socket = FileDescriptorAccessor.GetSocket(impl.fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - socket.Listen(count); - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__socketListen ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketListen>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(socketListen), "(I)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__socketListen(jniEnv, jniFrm.MakeLocalRef(self), count); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'socketAccept'. - /// - public static void socketAccept(object self, object s_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - InvokeAction(self, s_, (impl, s) => - { - var socket = FileDescriptorAccessor.GetSocket(impl.fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - var prevBlocking = socket.Blocking; - - try - { - socket.Blocking = true; - - // wait for connection attempt - if (impl.timeout > 0) - if (socket.Poll((int)Math.Min(impl.timeout * 1000L, int.MaxValue), SelectMode.SelectRead) == false) - throw new global::java.net.SocketTimeoutException("Accept timed out."); - - // accept new socket - var newSocket = socket.Accept(); - if (newSocket == null) - throw new global::java.net.SocketException("Invalid socket."); - - // associate new FileDescriptor with socket - var newfd = new global::java.io.FileDescriptor(); - FileDescriptorAccessor.SetSocket(newfd, newSocket); - - // populate newly accepted socket - var remoteIpEndPoint = (IPEndPoint)newSocket.RemoteEndPoint; - s.fd = newfd; - s.address = remoteIpEndPoint.ToInetAddress(); - s.port = remoteIpEndPoint.Port; - s.localport = impl.port; - } - catch (ObjectDisposedException) - { - throw new global::java.io.InterruptedIOException(); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.Interrupted) - { - throw new global::java.io.InterruptedIOException(e.Message); - } - finally - { - socket.Blocking = prevBlocking; - } - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__socketAccept ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketAccept>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(socketAccept), "(Ljava/net/SocketImpl;)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__socketAccept(jniEnv, jniFrm.MakeLocalRef(self), jniFrm.MakeLocalRef(s_)); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'socketAvailable'. - /// - public static int socketAvailable(object this_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return InvokeFunc(this_, impl => - { - var socket = FileDescriptorAccessor.GetSocket(impl.fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - try - { - return socket.Available; - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionReset) - { - throw new global::sun.net.ConnectionResetException(); - } - catch (SocketException e) - { - throw new global::java.net.SocketException(e.Message); - } - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__socketAvailable ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketAvailable>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(socketAvailable), "()I")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - return __jniPtr__socketAvailable(jniEnv, jniFrm.MakeLocalRef(this_)); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'socketClose0'. - /// - public static void socketClose0(object self, bool useDeferredClose) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - InvokeAction(self, impl => - { - // exit if descriptor already closed - if (impl.fd == null || FileDescriptorAccessor.GetHandle(impl.fd) == -1) - return; - - var socket = FileDescriptorAccessor.GetSocket(impl.fd); - if (socket == null) - throw new global::java.net.SocketException("Socket already closed."); - - // if we're not configured to linger, disable sending, but continue to allow receive - if (socket.LingerState.Enabled == false) - { - try - { - socket.Shutdown(SocketShutdown.Send); - } - catch (SocketException) - { - // ignore - } - } - - // null socket before close, as close may take a minute to flush - var h = FileDescriptorAccessor.GetHandle(impl.fd); - FileDescriptorAccessor.SetHandle(impl.fd, -1); - LibIkvm.Instance.io_close_socket(h); - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__socketClose0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketClose0>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(socketClose0), "(Z)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__socketClose0(jniEnv, jniFrm.MakeLocalRef(self), useDeferredClose ? JNIEnv.JNI_TRUE : JNIEnv.JNI_FALSE); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'socketShutdown'. - /// - public static void socketShutdown(object self, int howto) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - InvokeAction(self, impl => - { - if (impl.fd == null) - throw new global::java.net.SocketException("Socket closed"); - - var socket = FileDescriptorAccessor.GetSocket(impl.fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - socket.Shutdown((SocketShutdown)howto); - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__socketShutdown ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketShutdown>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(socketShutdown), "(I)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__socketShutdown(jniEnv, jniFrm.MakeLocalRef(self), howto); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'socketSetOption0'. - /// - public static void socketSetOption0(object self, int cmd, bool on, object value) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - InvokeAction(self, impl => - { - var socket = FileDescriptorAccessor.GetSocket(impl.fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - if (value == null) - throw new global::java.lang.NullPointerException(nameof(value)); - - // .NET provides property - if (cmd == global::java.net.SocketOptions.SO_TIMEOUT) - { - var timeout = (global::java.lang.Integer)value; - socket.ReceiveTimeout = timeout.intValue(); - return; - } - - // .NET provides property - if (cmd == global::java.net.SocketOptions.SO_LINGER) - { - var linger = (global::java.lang.Integer)value; - socket.LingerState = new LingerOption(on, linger.intValue()); - return; - } - - // .NET provides a property - if (cmd == global::java.net.SocketOptions.SO_RCVBUF) - { - var val = (global::java.lang.Integer)value; - socket.ReceiveBufferSize = val.intValue(); - return; - } - - // .NET provides a property - if (cmd == global::java.net.SocketOptions.SO_SNDBUF) - { - var val = (global::java.lang.Integer)value; - socket.SendBufferSize = val.intValue(); - return; - } - - // .NET provides a property - if (cmd == global::java.net.SocketOptions.TCP_NODELAY) - { - socket.NoDelay = on; - return; - } - - // lookup option options - if (SocketOptionUtil.TryGetDotNetSocketOption(cmd, out var options) == false) - throw new global::java.net.SocketException("Invalid option."); - - // configure socket - socket.SetSocketOption(options.Level, options.Name, value switch - { - global::java.lang.Boolean b => GetSocketOptionSetValue(options.Type, b.booleanValue()), - global::java.lang.Integer i => GetSocketOptionSetValue(options.Type, i.intValue()), - _ => throw new global::java.net.SocketException("Invalid option value."), - }); - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__socketSetOption ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketSetOption>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(socketSetOption0), "(IZLjava/lang/Object;)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__socketSetOption(jniEnv, jniFrm.MakeLocalRef(self), cmd, on ? JNIEnv.JNI_TRUE : JNIEnv.JNI_FALSE, jniFrm.MakeLocalRef(value)); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method for 'socketGetOption'. - /// - public static int socketGetOption(object self, int opt, object iaContainerObj_) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return InvokeFunc(self, iaContainerObj_, (impl, iaContainerObj) => - { - var socket = FileDescriptorAccessor.GetSocket(impl.fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - // .NET provides property - if (opt == global::java.net.SocketOptions.SO_TIMEOUT) - return socket.ReceiveTimeout; - - // .NET provides property - if (opt == global::java.net.SocketOptions.SO_LINGER) - return socket.LingerState.Enabled ? socket.LingerState.LingerTime : -1; - - // .NET provides property - if (opt == global::java.net.SocketOptions.SO_RCVBUF) - return socket.ReceiveBufferSize; - - // .NET provides property - if (opt == global::java.net.SocketOptions.SO_SNDBUF) - return socket.SendBufferSize; - - // .NET provides property - if (opt == global::java.net.SocketOptions.SO_BINDADDR) - { - iaContainerObj.addr = ((IPEndPoint)socket.LocalEndPoint).ToInetAddress(); - return 0; - } - - // .NET provides property - if (opt == global::java.net.SocketOptions.TCP_NODELAY) - return socket.NoDelay ? 1 : -1; - - // lookup option options - if (SocketOptionUtil.TryGetDotNetSocketOption(opt, out var options) == false) - throw new global::java.net.SocketException("Invalid option."); - - // configure socket - return socket.GetSocketOption(options.Level, options.Name) switch - { - bool b => GetSocketOptionGetValue(options.Type, b), - int i => GetSocketOptionGetValue(options.Type, i), - _ => throw new global::java.net.SocketException("Invalid option value."), - }; - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__socketGetOption ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketGetOption>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(socketGetOption), "(I)I")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - return __jniPtr__socketGetOption(jniEnv, jniFrm.MakeLocalRef(self), opt, jniFrm.MakeLocalRef(iaContainerObj_)); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - -#if !FIRST_PASS - - /// - /// Handles socket options stored as a boolean. - /// - /// - /// - /// - /// - static int GetSocketOptionSetValue(SocketOptionUtil.SocketOptionType type, bool value) => type switch - { - SocketOptionUtil.SocketOptionType.Boolean => value ? 1 : 0, - SocketOptionUtil.SocketOptionType.Integer => value ? 1 : 0, - _ => throw new global::java.net.SocketException("Invalid option value."), - }; - - /// - /// Handles socket options stored as an integer. - /// - /// - /// - /// - /// - static int GetSocketOptionSetValue(SocketOptionUtil.SocketOptionType type, int value) => type switch - { - SocketOptionUtil.SocketOptionType.Boolean => (value != -1) ? 1 : 0, - SocketOptionUtil.SocketOptionType.Integer => value, - _ => throw new global::java.net.SocketException("Invalid option value."), - }; - - /// - /// Handles socket options stored as a boolean. - /// - /// - /// - /// - /// - static int GetSocketOptionGetValue(SocketOptionUtil.SocketOptionType type, bool value) => type switch - { - SocketOptionUtil.SocketOptionType.Boolean => value ? 1 : -1, - _ => throw new global::java.net.SocketException("Invalid option value."), - }; - - /// - /// Handles socket options stored as an integer. - /// - /// - /// - /// - /// - static int GetSocketOptionGetValue(SocketOptionUtil.SocketOptionType type, int value) => type switch - { - SocketOptionUtil.SocketOptionType.Boolean => value == 0 ? -1 : 1, - SocketOptionUtil.SocketOptionType.Integer => value, - SocketOptionUtil.SocketOptionType.Unknown => value, - _ => throw new global::java.net.SocketException("Invalid option value."), - }; - -#endif - - /// - /// Implements the native method for 'socketSendUrgentData'. - /// - public static void socketSendUrgentData(object this_, int data) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - InvokeAction(this_, impl => - { - var socket = FileDescriptorAccessor.GetSocket(impl.fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - var prevBlocking = socket.Blocking; - var prevTimeout = socket.SendTimeout; - - try - { - socket.Blocking = true; - socket.SendTimeout = impl.timeout; - - var buffer = new byte[] { (byte)data }; - socket.Send(buffer, 0, 1, SocketFlags.OutOfBand); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.Interrupted) - { - throw new global::java.io.InterruptedIOException(e.Message); - } - finally - { - socket.Blocking = prevBlocking; - socket.SendTimeout = prevTimeout; - } - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.PlainSocketImpl).TypeHandle); - __jniPtr__socketSendUrgentData ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketSendUrgentData>(JNIFrame.GetFuncPtr(__callerID, "java/net/PlainSocketImpl", nameof(socketSendUrgentData), "(B)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__socketSendUrgentData(jniEnv, jniFrm.MakeLocalRef(this_), data); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/java/net/SocketInputStream.cs b/src/IKVM.Runtime/Java/Externs/java/net/SocketInputStream.cs deleted file mode 100644 index 1beab0ab5f..0000000000 --- a/src/IKVM.Runtime/Java/Externs/java/net/SocketInputStream.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Net.Sockets; -using System.Runtime.InteropServices; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.JNI; - -using static IKVM.Java.Externs.java.net.SocketImplUtil; - -namespace IKVM.Java.Externs.java.net -{ - - static class SocketInputStream - { - -#if FIRST_PASS == false && IMPORTER == false && EXPORTER == false - - static FileDescriptorAccessor fileDescriptorAccessor; - - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - - static global::ikvm.@internal.CallerID __callerID; - delegate int __jniDelegate__socketRead0(IntPtr jniEnv, IntPtr self, IntPtr fdObj, IntPtr data, int off, int len, int timeout); - static __jniDelegate__socketRead0 __jniPtr__socketRead0; - -#endif - - public static int socketRead0(object this_, object fdObj, byte[] data, int off, int len, int timeout) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return InvokeFunc(this_, self => - { - if (fdObj == null) - throw new global::java.net.SocketException("Socket closed"); - - var socket = FileDescriptorAccessor.GetSocket(fdObj); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - if (timeout > 0 && socket.Available == 0) - { - try - { - if (socket.Poll((int)Math.Min(timeout * 1000L, int.MaxValue), SelectMode.SelectRead) == false) - throw new global::java.net.SocketTimeoutException("Receive timed out."); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.TimedOut) - { - throw new global::java.net.SocketTimeoutException("Receive timed out."); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.Interrupted) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch - { - throw; - } - } - - try - { - return socket.EndReceive(socket.BeginReceive(data, off, len, SocketFlags.None, null, null)); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.Interrupted) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (SocketException) - { - throw; - } - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.SocketInputStream).TypeHandle); - __jniPtr__socketRead0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketRead0>(JNIFrame.GetFuncPtr(__callerID, "java/net/SocketInputStream", nameof(socketRead0), "(Ljava/io/FileDescriptor;[BIII)I")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - return __jniPtr__socketRead0(jniEnv, jniFrm.MakeLocalRef(this_), jniFrm.MakeLocalRef(fdObj), jniFrm.MakeLocalRef(data), off, len, timeout); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/java/net/SocketInvokeUtil.cs b/src/IKVM.Runtime/Java/Externs/java/net/SocketInvokeUtil.cs deleted file mode 100644 index 3fe6e7af01..0000000000 --- a/src/IKVM.Runtime/Java/Externs/java/net/SocketInvokeUtil.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System; -using System.Net.Sockets; - -using IKVM.Runtime.Util.Java.Net; - -namespace IKVM.Java.Externs.java.net -{ - - /// - /// Provides some static methods for working with socket implementations. - /// - static class SocketImplUtil - { - -#if !FIRST_PASS - - /// - /// Invokes the given delegate mapping exception to their appropriate Java type. - /// - /// - /// - /// - public static void InvokeAction(object arg1, Action action) - { - InvokeAction(() => action((TArg1)arg1)); - } - - /// - /// Invokes the given delegate mapping exception to their appropriate Java type. - /// - /// - /// - /// - /// - /// - public static void InvokeAction(object arg1, object arg2, Action action) - { - InvokeAction(() => action((TArg1)arg1, (TArg2)arg2)); - } - - /// - /// Invokes the given delegate mapping exception to their appropriate Java type. - /// - /// - /// - /// - /// - /// - /// - /// - public static void InvokeAction(object arg1, object arg2, object arg3, Action action) - { - InvokeAction(() => action((TArg1)arg1, (TArg2)arg2, (TArg3)arg3)); - } - - /// - /// Invokes the given action, catching and mapping any resulting .NET exceptions. - /// - /// - /// - public static void InvokeAction(Action action) - { - try - { - action(); - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - } - - /// - /// Invokes the given delegate mapping exception to their appropriate Java type. - /// - /// - /// - /// - /// - /// - public static TResult InvokeFunc(object arg1, Func action) - { - return InvokeFunc(() => action((TArg1)arg1)); - } - - /// - /// Invokes the given delegate mapping exception to their appropriate Java type. - /// - /// - /// - /// - /// - /// - /// - /// - public static TResult InvokeFunc(object arg1, object arg2, Func action) - { - return InvokeFunc(() => action((TArg1)arg1, (TArg2)arg2)); - } - - /// - /// Invokes the given delegate mapping exception to their appropriate Java type. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static TResult InvokeFunc(object arg1, object arg2, object arg3, Func action) - { - return InvokeFunc(() => action((TArg1)arg1, (TArg2)arg2, (TArg3)arg3)); - } - - /// - /// Invokes the given action, catching and mapping any resulting .NET exceptions. - /// - /// - /// - public static TResult InvokeFunc(Func func) - { - try - { - return func(); - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - } - -#endif - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/java/net/SocketOptionUtil.cs b/src/IKVM.Runtime/Java/Externs/java/net/SocketOptionUtil.cs deleted file mode 100644 index f9b8bd907e..0000000000 --- a/src/IKVM.Runtime/Java/Externs/java/net/SocketOptionUtil.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System.Net.Sockets; - -namespace IKVM.Java.Externs.java.net -{ - - /// - /// Provides a map of Java socket information to .NET socket information. - /// - static class SocketOptionUtil - { - -#if !FIRST_PASS - - public enum SocketOptionType - { - - Boolean, - Integer, - Unknown, - - } - - /// - /// Describes a mapping between a and it's associated .NET information. - /// - struct SocketOptionMapItem - { - - /// - /// Initializes a new instance. - /// - /// - /// - /// - /// - public SocketOptionMapItem(int option, SocketOptionLevel level, SocketOptionName name, SocketOptionType type) - { - Option = option; - Level = level; - Name = name; - Type = type; - } - - /// - /// Gets the option. - /// - public int Option { get; set; } - - /// - /// Gets the . - /// - public SocketOptionLevel Level { get; set; } - - /// - /// Gets the . - /// - public SocketOptionName Name { get; set; } - - /// - /// Gets the type of the socket option when getting. - /// - public SocketOptionType Type { get; set; } - - } - - readonly static SocketOptionMapItem[] map = new[] - { - new SocketOptionMapItem(global::java.net.SocketOptions.SO_OOBINLINE, SocketOptionLevel.Socket, SocketOptionName.OutOfBandInline, SocketOptionType.Boolean), - new SocketOptionMapItem(global::java.net.SocketOptions.SO_SNDBUF, SocketOptionLevel.Socket, SocketOptionName.SendBuffer, SocketOptionType.Integer), - new SocketOptionMapItem(global::java.net.SocketOptions.SO_RCVBUF, SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, SocketOptionType.Integer), - new SocketOptionMapItem(global::java.net.SocketOptions.SO_KEEPALIVE, SocketOptionLevel.Socket, SocketOptionName.KeepAlive, SocketOptionType.Boolean), - new SocketOptionMapItem(global::java.net.SocketOptions.SO_REUSEADDR, SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, SocketOptionType.Boolean), - new SocketOptionMapItem(global::java.net.SocketOptions.SO_BROADCAST, SocketOptionLevel.Socket, SocketOptionName.Broadcast, SocketOptionType.Boolean), - new SocketOptionMapItem(global::java.net.SocketOptions.SO_TIMEOUT, SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, SocketOptionType.Integer), - new SocketOptionMapItem(global::java.net.SocketOptions.IP_MULTICAST_IF, SocketOptionLevel.IP, SocketOptionName.MulticastInterface, SocketOptionType.Integer), - new SocketOptionMapItem(global::java.net.SocketOptions.IP_MULTICAST_LOOP, SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, SocketOptionType.Boolean), - new SocketOptionMapItem(global::java.net.SocketOptions.IP_TOS, SocketOptionLevel.IP, SocketOptionName.TypeOfService, SocketOptionType.Integer), - new SocketOptionMapItem(global::java.net.SocketOptions.TCP_NODELAY, SocketOptionLevel.Tcp, SocketOptionName.NoDelay, SocketOptionType.Boolean), - }; - - /// - /// Gets the socket option map item from the given option. - /// - /// - /// - /// - public static bool TryGetDotNetSocketOption(int option, out (SocketOptionLevel Level, SocketOptionName Name, SocketOptionType Type) options) - { - foreach (var o in map) - { - if (o.Option == option) - { - options = (o.Level, o.Name, o.Type); - return true; - } - } - - options = default; - return false; - } - -#endif - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/java/net/SocketOutputStream.cs b/src/IKVM.Runtime/Java/Externs/java/net/SocketOutputStream.cs deleted file mode 100644 index 8efbb37472..0000000000 --- a/src/IKVM.Runtime/Java/Externs/java/net/SocketOutputStream.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Net.Sockets; -using System.Runtime.InteropServices; - -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime; -using IKVM.Runtime.JNI; - -using static IKVM.Java.Externs.java.net.SocketImplUtil; - -namespace IKVM.Java.Externs.java.net -{ - - static class SocketOutputStream - { - -#if FIRST_PASS == false && IMPORTER == false && EXPORTER == false - - static FileDescriptorAccessor fileDescriptorAccessor; - - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - - static global::ikvm.@internal.CallerID __callerID; - delegate void __jniDelegate__socketWrite0(IntPtr jniEnv, IntPtr self, IntPtr fdObj, IntPtr data, int off, int len); - static __jniDelegate__socketWrite0 __jniPtr__socketWrite0; - -#endif - - /// - /// Implements the native method for 'socketWrite0'. - /// - /// - /// - /// - /// - /// - /// - /// - public static void socketWrite0(object this_, object fdObj, byte[] data, int off, int len) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - if (data == null) - throw new global::java.lang.NullPointerException("data argument."); - - InvokeAction(this_, impl => - { - if (fdObj == null) - throw new global::java.net.SocketException("Socket closed"); - - var socket = FileDescriptorAccessor.GetSocket(fdObj); - if (socket == null) - throw new global::java.net.SocketException("Socket closed"); - - var prevBlocking = socket.Blocking; - var prevSendTimeout = socket.SendTimeout; - - try - { - socket.Blocking = false; - socket.Blocking = true; - socket.SendTimeout = 0; - socket.Send(data, off, Math.Min(len, data.Length - off), SocketFlags.None); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.Interrupted) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (SocketException) - { - throw; - } - finally - { - socket.Blocking = prevBlocking; - socket.SendTimeout = prevSendTimeout; - } - }); - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::java.net.SocketOutputStream).TypeHandle); - __jniPtr__socketWrite0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__socketWrite0>(JNIFrame.GetFuncPtr(__callerID, "java/net/SocketOutputStream", nameof(socketWrite0), "(Ljava/io/FileDescriptor;[BII)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__socketWrite0(jniEnv, jniFrm.MakeLocalRef(this_), jniFrm.MakeLocalRef(fdObj), jniFrm.MakeLocalRef(data), off, len); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/management/FileSystemImpl.cs b/src/IKVM.Runtime/Java/Externs/sun/management/FileSystemImpl.cs deleted file mode 100644 index f5f0e1ba37..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/management/FileSystemImpl.cs +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright (C) 2011-2014 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; - -namespace IKVM.Java.Externs.sun.management -{ - - static class FileSystemImpl - { - - public static void init0() - { - - } - - public static bool isSecuritySupported0(string path) - { - throw new NotSupportedException(); - } - - public static bool isAccessUserOnly0(string path) - { - throw new NotSupportedException(); - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/management/OperatingSystemImpl.cs b/src/IKVM.Runtime/Java/Externs/sun/management/OperatingSystemImpl.cs deleted file mode 100644 index 090ac16358..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/management/OperatingSystemImpl.cs +++ /dev/null @@ -1,459 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text.RegularExpressions; - -using Mono.Unix.Native; - -namespace IKVM.Java.Externs.sun.management -{ - - static class OperatingSystemImpl - { - - [StructLayout(LayoutKind.Sequential)] - struct PROCESS_MEMORY_COUNTERS - { - - public uint cb; - public uint PageFaultCount; - public UIntPtr PeakWorkingSetSize; - public UIntPtr WorkingSetSize; - public UIntPtr QuotaPeakPagedPoolUsage; - public UIntPtr QuotaPagedPoolUsage; - public UIntPtr QuotaPeakNonPagedPoolUsage; - public UIntPtr QuotaNonPagedPoolUsage; - public UIntPtr PagefileUsage; - public UIntPtr PeakPagefileUsage; - - } - - struct MEMORYSTATUSEX - { - - public uint dwLength; - public uint dwMemoryLoad; - public ulong ullTotalPhys; - public ulong ullAvailPhys; - public ulong ullTotalPageFile; - public ulong ullAvailPageFile; - public ulong ullTotalVirtual; - public ulong ullAvailVirtual; - public ulong ullAvailExtendedVirtual; - - } - - [StructLayout(LayoutKind.Sequential)] - struct PERFORMANCE_INFORMATION - { - - public uint cb; - public UIntPtr CommitTotal; - public UIntPtr CommitLimit; - public UIntPtr CommitPeak; - public UIntPtr PhysicalTotal; - public UIntPtr PhysicalAvailable; - public UIntPtr SystemCache; - public UIntPtr KernelTotal; - public UIntPtr KernelPaged; - public UIntPtr KernelNonpaged; - public UIntPtr PageSize; - public uint HandleCount; - public uint ProcessCount; - public uint ThreadCount; - - } - - [DllImport("psapi", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - static extern bool GetProcessMemoryInfo(IntPtr Process, out PROCESS_MEMORY_COUNTERS ppsmemCounters, uint cb); - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer); - - [DllImport("psapi", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - static extern bool GetPerformanceInfo(ref PERFORMANCE_INFORMATION pPerformanceInformation, uint size); - - /// - /// Describes the Linux 'sysinfo' structure. - /// - [StructLayout(LayoutKind.Sequential)] - unsafe struct sysinfo_t_x64 - { - - /// - /// Seconds since boot. - /// - public long uptime; - - /// - /// 1, 5, and 15 minute load averages. - /// - public fixed ulong loads[3]; - - /// - /// Total usable main memory size. - /// - public ulong totalram; - - /// - /// Available memory size. - /// - public ulong freeram; - - /// - /// Amount of shared memory. - /// - public ulong sharedram; - - /// - /// Memory used by buffers. - /// - public ulong bufferram; - - /// - /// Total swap space size. - /// - public ulong totalswap; - - /// - /// swap space still available. - /// - public ulong freeswap; - - /// - /// Number of current processes. - /// - public ushort procs; - - /// - /// Number of current processes. - /// - public ushort pad; - - /// - /// Total high memory size. - /// - public ulong totalhigh; - - /// - /// Available high memory size. - /// - public ulong freehigh; - - /// po;llokp - /// Memory unit size in bytes. - /// - public uint mem_unit; - - } - - /// - /// Invokes the native linux method 'sysinfo' for a x64 platform. - /// - /// - /// - [DllImport("libc", EntryPoint = "sysinfo")] - static extern int sysinfo_x64(ref sysinfo_t_x64 info); - - /// - /// Describes the rlimit structure for a x64 Linux platform. - /// - [StructLayout(LayoutKind.Sequential)] - struct rlimit_t_x64 - { - - public ulong rlim_cur; - public ulong rlim_max; - - } - - enum RLIMIT - { - FSIZE = 0, - NOFILE = 1, - CORE = 2, - CPU = 3, - DATA = 4, - STACK = 5, - AS = 6, - } - - /// - /// Invokes the native linux method 'getrlimit' for a x64 platform. - /// - /// - /// - [DllImport("libc", EntryPoint = "getrlimit")] - static extern int getrlimit_x64(RLIMIT resource, ref rlimit_t_x64 info); - - /// - /// Regular expression for the Linux /proc/pid/stat file. - /// - static readonly Regex LinuxProcStatRegex = new Regex(@"^-?\d+ \(.+\) [A-Za-z] -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ (-?\d+)", RegexOptions.Compiled | RegexOptions.CultureInvariant); - - /// - /// Initializes the static information. - /// - public static void initialize() - { - - } - - /// - /// Implements the native method 'getCommittedVirtualMemorySize0'. - /// - /// - /// - public static long getCommittedVirtualMemorySize0(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return Process.GetCurrentProcess().PagedMemorySize64; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - try - { - using var s = File.OpenRead("/proc/self/stat"); - using var r = new StreamReader(s); - - var l = r.ReadLine(); - if (l != null && LinuxProcStatRegex.Match(l) is Match m && m.Groups.Count >= 2) - return (long)ulong.Parse(m.Groups[1].Value); - - throw new global::java.lang.InternalError("Unable to get virtual memory usage"); - } - catch (IOException e) - { - throw new global::java.lang.InternalError("Unable to open or read /proc/self/stat", e); - } - catch (Exception e) - { - throw new global::java.lang.InternalError("Unable to get virtual memory usage", e); - } - } - else - { - return -1; - } -#endif - } - - /// - /// Implements the native method 'getTotalSwapSpaceSize'. - /// - /// - /// - /// - public static long getTotalSwapSpaceSize(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var r = -1L; - var p = new MEMORYSTATUSEX(); - p.dwLength = (uint)Marshal.SizeOf(p); - if (GlobalMemoryStatusEx(ref p)) - r = (long)p.ullTotalPageFile; - - return r; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && IntPtr.Size == 8) - { - var si = new sysinfo_t_x64(); - if (sysinfo_x64(ref si) != 0) - throw new global::java.lang.InternalError("sysinfo failed to get swap size"); - - return (long)si.totalswap * si.mem_unit; - } - else - { - return -1; - } -#endif - } - - /// - /// Implements the native method 'getFreeSwapSpaceSize'. - /// - /// - /// - /// - public static long getFreeSwapSpaceSize(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var r = -1L; - var p = new MEMORYSTATUSEX(); - p.dwLength = (uint)Marshal.SizeOf(p); - if (GlobalMemoryStatusEx(ref p)) - r = (long)p.ullAvailPageFile; - - return r; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && IntPtr.Size == 8) - { - var si = new sysinfo_t_x64(); - if (sysinfo_x64(ref si) != 0) - throw new global::java.lang.InternalError("sysinfo failed to get swap size"); - - return (long)si.freeswap * si.mem_unit; - } - else - { - return -1; - } -#endif - } - - /// - /// Implements the native method 'getFreePhysicalMemorySize'. - /// - /// - /// - public static long getFreePhysicalMemorySize(object self) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var m = -1L; - var p = new PERFORMANCE_INFORMATION(); - if (GetPerformanceInfo(ref p, (uint)Marshal.SizeOf(p))) - m = (long)(ulong)p.PhysicalAvailable; - - return m; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - return Syscall.sysconf(SysconfName._SC_AVPHYS_PAGES) * Syscall.sysconf(SysconfName._SC_PAGESIZE); - } - else - { - return -1; - } - } - - /// - /// Implements the native method 'getTotalPhysicalMemorySize'. - /// - /// - /// - public static long getTotalPhysicalMemorySize(object self) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var m = -1L; - var p = new PERFORMANCE_INFORMATION(); - if (GetPerformanceInfo(ref p, (uint)Marshal.SizeOf(p))) - m = (long)(ulong)p.PhysicalTotal; - - return m; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - return Syscall.sysconf(SysconfName._SC_PHYS_PAGES); - } - else - { - return -1; - } - } - - /// - /// Implements the native method 'getProcessCpuTime'. - /// - /// - /// - public static long getProcessCpuTime(object self) - { - return Process.GetCurrentProcess().TotalProcessorTime.Ticks * 100; - } - - /// - /// Implements the native method 'getSystemCpuLoad'. - /// - /// - /// - public static double getSystemCpuLoad(object self) - { - return -1; - } - - /// - /// Implements the native method 'getProcessCpuLoad'. - /// - /// - /// - public static double getProcessCpuLoad(object self) - { - return -1; - } - - /// - /// Implements the native method 'getOpenFileDescriptorCount'. - /// - /// - /// - public static long getOpenFileDescriptorCount(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - try - { - return Directory.GetFiles("/proc/self/fd").Length; - } - catch (Exception e) - { - throw new global::java.lang.InternalError(e); - } - } - else - { - return -1; - } -#endif - } - - /// - /// Implements the native method 'getMaxFileDescriptorCount'. - /// - /// - /// - public static long getMaxFileDescriptorCount(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && IntPtr.Size == 8) - { - var rlp = new rlimit_t_x64(); - if (getrlimit_x64(RLIMIT.NOFILE, ref rlp) == -1) - throw new global::java.lang.InternalError("getrlimit failed"); - - return (long)rlp.rlim_cur; - } - else - { - return -1; - } -#endif - } - - } - -} \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/sun/net/ExtendedOptionsImpl.cs b/src/IKVM.Runtime/Java/Externs/sun/net/ExtendedOptionsImpl.cs deleted file mode 100644 index c3821845af..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/net/ExtendedOptionsImpl.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; - -namespace IKVM.Java.Externs.sun.net -{ - - static class ExtendedOptionsImpl - { - - public static void init() - { - - } - - public static bool flowSupported() - { - return false; - } - - public static void getFlowOption(object this_, object f_) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - throw new global::java.lang.UnsupportedOperationException(); -#endif - } - - public static void setFlowOption(object this_, object f_) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - throw new global::java.lang.UnsupportedOperationException(); -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/net/PortConfig.cs b/src/IKVM.Runtime/Java/Externs/sun/net/PortConfig.cs deleted file mode 100644 index 75c43b5d97..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/net/PortConfig.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System.IO; - -using IKVM.Runtime; - -namespace IKVM.Java.Externs.sun.net -{ - - /// - /// Implements the native methods for 'sun.net.PortConfig'. - /// - static class PortConfig - { - - const int WindowsDefaultLowerPortRange = 49152; - const int WindowsDefaultUpperPortRange = 65535; - const string LinuxIpLocalPortRangeFile = "/proc/sys/net/ipv4/ip_local_port_range"; - const int LinuxDefaultLowerPortRange = 32768; - const int LinuxDefaultUpperPortRange = 60999; - const int OSXDefaultLowerPortRange = 49152; - const int OSXDefaultUpperPortRange = 65535; - - /// - /// Implements the native method 'getLower0'. - /// - /// - public static int getLower0() - { - if (RuntimeUtil.IsWindows) - { - return WindowsDefaultLowerPortRange; - } - else if (RuntimeUtil.IsLinux) - { - if (File.Exists(LinuxIpLocalPortRangeFile) == false) - return LinuxDefaultLowerPortRange; - - var f = File.ReadAllText(LinuxIpLocalPortRangeFile); - var a = f.Split('\t'); - if (a.Length < 2) - return LinuxDefaultLowerPortRange; - - if (int.TryParse(a[0], out var i)) - return i; - - return LinuxDefaultLowerPortRange; - } - else if (RuntimeUtil.IsOSX) - { - return OSXDefaultLowerPortRange; - } - else - { - return -1; - } - } - - /// - /// Implements the native method 'getUpper0'. - /// - /// - public static int getUpper0() - { - if (RuntimeUtil.IsWindows) - { - return WindowsDefaultUpperPortRange; - } - else if (RuntimeUtil.IsLinux) - { - if (File.Exists(LinuxIpLocalPortRangeFile) == false) - return LinuxDefaultUpperPortRange; - - var f = File.ReadAllText(LinuxIpLocalPortRangeFile); - var a = f.Split('\t'); - if (a.Length < 2) - return LinuxDefaultUpperPortRange; - - if (int.TryParse(a[1], out var i)) - return i; - - return LinuxDefaultUpperPortRange; - } - else if (RuntimeUtil.IsOSX) - { - return OSXDefaultUpperPortRange; - } - else - { - return -1; - } - } - - } - -} \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/sun/net/spi/DefaultProxySelector.cs b/src/IKVM.Runtime/Java/Externs/sun/net/spi/DefaultProxySelector.cs deleted file mode 100644 index 8a9aa5132f..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/net/spi/DefaultProxySelector.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright (C) 2007-2015 Jeroen Frijters - Copyright (C) 2009 Volker Berlin (i-net software) - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.Java.Externs.sun.net.spi -{ - - static class DefaultProxySelector - { - - public static bool init() - { - return true; - } - - public static object getSystemProxy(object thisDefaultProxySelector, string protocol, string host) - { - // TODO - return null; - } - - } - -} \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DatagramChannelImpl.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DatagramChannelImpl.cs deleted file mode 100644 index 7cbfec7e1b..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DatagramChannelImpl.cs +++ /dev/null @@ -1,301 +0,0 @@ -using System; -using System.Buffers; -using System.Linq.Expressions; -using System.Net; -using System.Net.Sockets; -using System.Reflection; -using System.Runtime.InteropServices; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.Accessors.Sun.Nio.Ch; -using IKVM.Runtime.JNI; -using IKVM.Runtime.Util.Java.Net; - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Implements the native methods of 'sun.nio.ch.DatagramChannelImpl'. - /// - static class DatagramChannelImpl - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - static DatagramChannelImplAccessor datagramChannelImplAccessor; - - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - - static DatagramChannelImplAccessor DatagramChannelImplAccessor => JVM.Internal.BaseAccessors.Get(ref datagramChannelImplAccessor); - - /// - /// Compiles a fast setter for a . - /// - /// - /// - /// - /// - static Action MakeFieldSetter(FieldInfo field) - { - var p = Expression.Parameter(typeof(T)); - var v = Expression.Parameter(typeof(V)); - var e = Expression.Lambda>(Expression.Assign(Expression.Field(field.DeclaringType.IsValueType ? Expression.Unbox(p, field.DeclaringType) : Expression.ConvertChecked(p, field.DeclaringType), field), v), p, v); - return e.Compile(); - } - -#if NETCOREAPP - - // HACK .NET Core has an explicit check for _isConnected https://github.com/dotnet/runtime/issues/77962 - static readonly FieldInfo SocketIsConnectedField = typeof(Socket).GetField("_isConnected", BindingFlags.NonPublic | BindingFlags.Instance); - static readonly Action SocketIsConnectedFieldSetter = SocketIsConnectedField != null ? MakeFieldSetter(SocketIsConnectedField) : null; - -#endif - - const IOControlCode SIO_UDP_CONNRESET = (IOControlCode)(-1744830452); - static readonly byte[] IOControlTrueBuffer = BitConverter.GetBytes(1); - static readonly byte[] IOControlFalseBuffer = BitConverter.GetBytes(0); - static readonly byte[] TempBuffer = new byte[1]; - - static global::ikvm.@internal.CallerID __callerID; - delegate void __jniDelegate__disconnect0(IntPtr jniEnv, IntPtr self, IntPtr fdo, sbyte isIPv6); - static __jniDelegate__disconnect0 __jniPtr__disconnect0; - - /// - /// Peek at the queue to see if there is an ICMP port unreachable. If there is, then receive it. - /// - /// - static void PurgeOutstandingICMP(Socket socket) - { - while (true) - { - // check for outstanding packet - if (socket.Poll(0, SelectMode.SelectRead) == false) - break; - - try - { - var ep = (EndPoint)new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); - socket.EndReceiveFrom(socket.BeginReceiveFrom(TempBuffer, 0, TempBuffer.Length, SocketFlags.Peek, ref ep, null, null), ref ep); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionReset) - { - try - { - var ep = (EndPoint)new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); - socket.EndReceiveFrom(socket.BeginReceiveFrom(TempBuffer, 0, TempBuffer.Length, SocketFlags.Peek, ref ep, null, null), ref ep); - } - catch (SocketException e2) when (e2.SocketErrorCode == SocketError.ConnectionReset) - { - - } - - continue; - } - - break; - } - } - -#endif - - /// - /// Implements the native method 'disconnect0'. - /// - /// - /// - public static void disconnect0(object fd, bool isIPv6) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else -#if NETCOREAPP - // zero out isconnected - if (SocketIsConnectedFieldSetter != null) - { - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - SocketIsConnectedFieldSetter(FileDescriptorAccessor.GetSocket(fd), false); - } -#endif - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - try - { - // NOTE we use async connect to work around the issue that the .NET Socket class disallows sync Connect after the socket has received WSAECONNRESET - var any = socket.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any; - socket.EndConnect(socket.BeginConnect(new IPEndPoint(any, 0), null, null)); - socket.IOControl(SIO_UDP_CONNRESET, IOControlFalseBuffer, null); - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::sun.nio.ch.DatagramChannelImpl).TypeHandle); - __jniPtr__disconnect0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__disconnect0>(JNIFrame.GetFuncPtr(__callerID, "sun/nio/ch/DatagramChannelImpl", nameof(disconnect0), "(Ljava/io/FileDescriptor;Z)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - __jniPtr__disconnect0(jniEnv, jniFrm.MakeLocalRef(ClassLiteral.Value), jniFrm.MakeLocalRef(fd), isIPv6 ? JNIEnv.JNI_TRUE : JNIEnv.JNI_FALSE); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native 'receive0' method. - /// - /// - /// - /// - /// - /// - /// - public static unsafe int receive0(object self, object fd, long address, int len, bool connected) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - var remoteEndpoint = (EndPoint)new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); - var length = 0; - - try - { - var packet = ArrayPool.Shared.Rent(len); - - try - { - length = socket.ReceiveFrom(packet, 0, len, SocketFlags.None, ref remoteEndpoint); - Marshal.Copy(packet, 0, (IntPtr)address, length); - } - finally - { - ArrayPool.Shared.Return(packet); - } - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.MessageSize) - { - // buffer should be filled with as much as possible, and we should indicate that, but the rest is discarded - length = len; - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionReset) - { - // Windows may leave multiple ICMP packets on the socket, purge them - if (RuntimeUtil.IsWindows) - PurgeOutstandingICMP(socket); - - throw new global::java.net.PortUnreachableException("ICMP Port Unreachable"); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionRefused) - { - throw new global::java.net.PortUnreachableException("ICMP Port Unreachable"); - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - - // check that we received an IP endpoint - if (remoteEndpoint is not IPEndPoint ipRemoteEndpoint) - throw new global::java.net.SocketException("Unexpected resulting endpoint type."); - - // update remote address if it has changed - var remoteAddress = DatagramChannelImplAccessor.InvokeRemoteAddress(self); - if (remoteAddress == null || ipRemoteEndpoint.ToInetSocketAddress().equals(remoteAddress) == false) - DatagramChannelImplAccessor.SetSender(self, ipRemoteEndpoint.ToInetSocketAddress()); - - return length; -#endif - } - - /// - /// Implements the native method 'send0'. - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static unsafe int send0(object self, bool preferIPv6, object fd, long address, int len, global::java.net.InetAddress addr, int port) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - - try - { - var packet = ArrayPool.Shared.Rent(len); - - try - { - Marshal.Copy((IntPtr)address, packet, 0, len); - return socket.SendTo(packet, 0, len, SocketFlags.None, new IPEndPoint(addr.ToIPAddress(), port)); - } - finally - { - ArrayPool.Shared.Return(packet); - } - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DatagramDispatcher.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DatagramDispatcher.cs deleted file mode 100644 index acf009bf2c..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DatagramDispatcher.cs +++ /dev/null @@ -1,390 +0,0 @@ -using System; -using System.Buffers; -using System.Net; -using System.Net.Sockets; -using System.Runtime.InteropServices; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.Util.Java.Net; - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Implements the native methods for 'DatagramDispatcher'. - /// - static class DatagramDispatcher - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - -#endif - - static readonly byte[] TempBuffer = new byte[1]; - - /// - /// Peek at the queue to see if there is an ICMP port unreachable. If there is, then receive it. - /// - /// - static void PurgeOutstandingICMP(Socket socket) - { - while (true) - { - // check for outstanding packet - if (socket.Poll(0, SelectMode.SelectRead) == false) - break; - - try - { - var ep = (EndPoint)new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); - socket.EndReceiveFrom(socket.BeginReceiveFrom(TempBuffer, 0, TempBuffer.Length, SocketFlags.Peek, ref ep, null, null), ref ep); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionReset) - { - try - { - var ep = (EndPoint)new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); - socket.EndReceiveFrom(socket.BeginReceiveFrom(TempBuffer, 0, TempBuffer.Length, SocketFlags.Peek, ref ep, null, null), ref ep); - } - catch (SocketException e2) when (e2.SocketErrorCode == SocketError.ConnectionReset) - { - - } - - continue; - } - - break; - } - } - - [StructLayout(LayoutKind.Sequential)] - struct iovec - { - - public IntPtr iov_base; - public int iov_len; - - } - - /// - /// Implements the native method 'read'. - /// - /// - /// - /// - /// - /// - public static unsafe int read(object self, object fd, long address, int len) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (len == 0) - return 0; - - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - try - { -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(len); - - try - { - var n = socket.Receive(buf, 0, len, SocketFlags.None); - if (n == 0) - return global::sun.nio.ch.IOStatus.EOF; - - Marshal.Copy(buf, 0, (IntPtr)address, n); - return n; - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - var n = socket.Receive(new Span((byte*)(IntPtr)address, len)); - if (n == 0) - return global::sun.nio.ch.IOStatus.EOF; - - return n; -#endif - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionReset) - { - // Windows may leave multiple ICMP packets on the socket, purge them - if (RuntimeUtil.IsWindows) - PurgeOutstandingICMP(socket); - - throw new global::java.net.PortUnreachableException("ICMP Port Unreachable"); - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - /// - /// Implements the native method 'readv'. - /// - /// - /// - /// - /// - /// - public static unsafe long readv(object self, object fd, long address, int len) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - if (len == 0) - return 0; - - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - try - { - // allocate list of array segments to hold received data - var vecs = new Span((byte*)(IntPtr)address, len); - var bufs = new ArraySegment[vecs.Length]; - - try - { - // prepare array segments for buffers - for (int i = 0; i < vecs.Length; i++) - bufs[i] = new ArraySegment(ArrayPool.Shared.Rent(vecs[i].iov_len), 0, vecs[i].iov_len); - - // receive into segments - var length = socket.Receive(bufs); - - // copy segments back into vectors - var l = length; - for (int i = 0; i < vecs.Length; i++) - { - var szz = Math.Min(l, vecs[i].iov_len); - Marshal.Copy(bufs[i].Array, 0, vecs[i].iov_base, szz); - l -= szz; - } - - // we should have accounted for all of the bytes - if (l != 0) - throw new global::java.lang.RuntimeException("Bytes remaining after read."); - - return length; - } - finally - { - for (int i = 0; i < bufs.Length; i++) - ArrayPool.Shared.Return(bufs[i].Array); - } - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionReset) - { - // Windows may leave multiple ICMP packets on the socket, purge them - if (RuntimeUtil.IsWindows) - PurgeOutstandingICMP(socket); - - throw new global::java.net.PortUnreachableException("ICMP Port Unreachable"); - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - /// - /// Implements the native method 'write'. - /// - /// - /// - /// - /// - /// - public static unsafe int write(object self, object fd, long address, int len) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - try - { -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(len); - - try - { - Marshal.Copy((IntPtr)address, buf, 0, len); - return socket.Send(buf, 0, len, SocketFlags.None); - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - return socket.Send(new ReadOnlySpan((byte*)(IntPtr)address, len)); -#endif - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionReset) - { - // Windows may leave multiple ICMP packets on the socket, purge them - if (RuntimeUtil.IsWindows) - PurgeOutstandingICMP(socket); - - throw new global::java.net.PortUnreachableException("ICMP Port Unreachable"); - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - /// - /// Implements the native method 'writev'. - /// - /// - /// - /// - /// - /// - public static unsafe long writev(object self, object fd, long address, int len) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - try - { - // allocate list of array segments to hold incoming buffers - var vecs = new ReadOnlySpan((void*)(IntPtr)address, len); - var bufs = new ArraySegment[vecs.Length]; - - try - { - // copy incoming buffers into segments - for (int i = 0; i < vecs.Length; i++) - { - bufs[i] = new ArraySegment(ArrayPool.Shared.Rent(vecs[i].iov_len), 0, vecs[i].iov_len); - Marshal.Copy(vecs[i].iov_base, bufs[i].Array, bufs[i].Offset, vecs[i].iov_len); - } - - // send segments - return socket.Send(bufs); - } - finally - { - // return allocated arrays - for (int i = 0; i < bufs.Length; i++) - if (bufs[i].Array != null) - ArrayPool.Shared.Return(bufs[i].Array); - } - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.ConnectionReset) - { - // Windows may leave multiple ICMP packets on the socket, purge them - if (RuntimeUtil.IsWindows) - PurgeOutstandingICMP(socket); - - throw new global::java.net.PortUnreachableException("ICMP Port Unreachable"); - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - /// - /// Implements the native method 'close'. - /// - /// - /// - public static void close(object self, object fd) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - if (fd == null) - return; - - try - { - var h = FileDescriptorAccessor.GetHandle(fd); - FileDescriptorAccessor.SetHandle(fd, -1); - LibIkvm.Instance.io_close_socket(h); - } - catch - { - // ignore - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousChannelExtensions.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousChannelExtensions.cs deleted file mode 100644 index e5213ea9af..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousChannelExtensions.cs +++ /dev/null @@ -1,508 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -using IKVM.Runtime.Util.Java.Util.Concurrent; - -#if FIRST_PASS == false - -using java.nio.channels; -using java.security; - -using sun.nio.ch; - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - static class DotNetAsynchronousChannelExtensions - { - - /// - /// Executes the specified function on the channel group. - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static global::java.util.concurrent.Future Execute(this DotNetAsynchronousChannelGroup self, TChannel channel, object attachment, CompletionHandler handler, Func> func) - where TChannel : AsynchronousChannel - { - var c = SynchronizationContext.Current; - - try - { - SynchronizationContext.SetSynchronizationContext(self.executor().ToSynchronizationContext()); - var cts = new CancellationTokenSource(); - var t = func(channel, global::java.lang.System.getSecurityManager() != null ? AccessController.getContext() : null, cts.Token); - - try - { - if (t.IsCompleted && t.IsFaulted) - t.GetAwaiter().GetResult(); - } - catch (Exception e) - { - if (handler != null) - { - Invoker.invoke(channel, handler, attachment, null, e); - return null; - } - - return CompletedFuture.withFailure(e); - } - - var f = new PendingFuture(channel, handler, attachment, null); - f.setContext(cts); - t.ContinueWith(a => { try { f.setResult(a.GetAwaiter().GetResult()); } catch (Exception e) { f.setFailure(e); }; Invoker.invoke(f); }); - return f; - } - finally - { - SynchronizationContext.SetSynchronizationContext(c); - } - } - - /// - /// Executes the specified function on the channel group. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static global::java.util.concurrent.Future Execute(this DotNetAsynchronousChannelGroup self, TChannel channel, TArg1 arg, object attachment, CompletionHandler handler, Func> func) - where TChannel : AsynchronousChannel - { - var c = SynchronizationContext.Current; - - try - { - SynchronizationContext.SetSynchronizationContext(self.executor().ToSynchronizationContext()); - var cts = new CancellationTokenSource(); - var t = func(channel, arg, global::java.lang.System.getSecurityManager() != null ? AccessController.getContext() : null, cts.Token); - - try - { - if (t.IsCompleted && t.IsFaulted) - t.GetAwaiter().GetResult(); - } - catch (Exception e) - { - if (handler != null) - { - Invoker.invoke(channel, handler, attachment, null, e); - return null; - } - - return CompletedFuture.withFailure(e); - } - - var f = new PendingFuture(channel, handler, attachment, null); - f.setContext(cts); - t.ContinueWith(a => { try { f.setResult(a.GetAwaiter().GetResult()); } catch (Exception e) { f.setFailure(e); }; Invoker.invoke(f); }); - return f; - } - finally - { - SynchronizationContext.SetSynchronizationContext(c); - } - } - - /// - /// Executes the specified function on the channel group. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static global::java.util.concurrent.Future Execute(this DotNetAsynchronousChannelGroup self, TChannel channel, TArg1 arg1, TArg2 arg2, object attachment, CompletionHandler handler, Func> func) - where TChannel : AsynchronousChannel - { - var c = SynchronizationContext.Current; - - try - { - SynchronizationContext.SetSynchronizationContext(self.executor().ToSynchronizationContext()); - var cts = new CancellationTokenSource(); - var t = func(channel, arg1, arg2, global::java.lang.System.getSecurityManager() != null ? AccessController.getContext() : null, cts.Token); - - try - { - if (t.IsCompleted && t.IsFaulted) - t.GetAwaiter().GetResult(); - } - catch (Exception e) - { - if (handler != null) - { - Invoker.invoke(channel, handler, attachment, null, e); - return null; - } - - return CompletedFuture.withFailure(e); - } - - var f = new PendingFuture(channel, handler, attachment, null); - f.setContext(cts); - t.ContinueWith(a => { try { f.setResult(a.GetAwaiter().GetResult()); } catch (Exception e) { f.setFailure(e); }; Invoker.invoke(f); }); - return f; - } - finally - { - SynchronizationContext.SetSynchronizationContext(c); - } - } - - /// - /// Executes the specified function on the channel group. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static global::java.util.concurrent.Future Execute(this DotNetAsynchronousChannelGroup self, TChannel channel, TArg1 arg1, TArg2 arg2, TArg3 arg3, object attachment, CompletionHandler handler, Func> func) - where TChannel : AsynchronousChannel - { - var c = SynchronizationContext.Current; - - try - { - SynchronizationContext.SetSynchronizationContext(self.executor().ToSynchronizationContext()); - var cts = new CancellationTokenSource(); - var t = func(channel, arg1, arg2, arg3, global::java.lang.System.getSecurityManager() != null ? AccessController.getContext() : null, cts.Token); - - try - { - if (t.IsCompleted && t.IsFaulted) - t.GetAwaiter().GetResult(); - } - catch (Exception e) - { - if (handler != null) - { - Invoker.invoke(channel, handler, attachment, null, e); - return null; - } - - return CompletedFuture.withFailure(e); - } - - var f = new PendingFuture(channel, handler, attachment, null); - f.setContext(cts); - t.ContinueWith(a => { try { f.setResult(a.GetAwaiter().GetResult()); } catch (Exception e) { f.setFailure(e); }; Invoker.invoke(f); }); - return f; - } - finally - { - SynchronizationContext.SetSynchronizationContext(c); - } - } - - /// - /// Executes the specified function on the channel group. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static global::java.util.concurrent.Future Execute(this DotNetAsynchronousChannelGroup self, TChannel channel, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, object attachment, CompletionHandler handler, Func> func) - where TChannel : AsynchronousChannel - { - var c = SynchronizationContext.Current; - - try - { - SynchronizationContext.SetSynchronizationContext(self.executor().ToSynchronizationContext()); - var cts = new CancellationTokenSource(); - var t = func(channel, arg1, arg2, arg3, arg4, global::java.lang.System.getSecurityManager() != null ? AccessController.getContext() : null, cts.Token); - - try - { - if (t.IsCompleted && t.IsFaulted) - t.GetAwaiter().GetResult(); - } - catch (Exception e) - { - if (handler != null) - { - Invoker.invoke(channel, handler, attachment, null, e); - return null; - } - - return CompletedFuture.withFailure(e); - } - - var f = new PendingFuture(channel, handler, attachment, null); - f.setContext(cts); - t.ContinueWith(a => { try { f.setResult(a.GetAwaiter().GetResult()); } catch (Exception e) { f.setFailure(e); }; Invoker.invoke(f); }); - return f; - } - finally - { - SynchronizationContext.SetSynchronizationContext(c); - } - } - - /// - /// Executes the specified function on the channel group. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static global::java.util.concurrent.Future Execute(this DotNetAsynchronousChannelGroup self, TChannel channel, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, object attachment, CompletionHandler handler, Func> func) - where TChannel : AsynchronousChannel - { - var c = SynchronizationContext.Current; - - try - { - SynchronizationContext.SetSynchronizationContext(self.executor().ToSynchronizationContext()); - var cts = new CancellationTokenSource(); - var t = func(channel, arg1, arg2, arg3, arg4, arg5, global::java.lang.System.getSecurityManager() != null ? AccessController.getContext() : null, cts.Token); - - try - { - if (t.IsCompleted && t.IsFaulted) - t.GetAwaiter().GetResult(); - } - catch (Exception e) - { - if (handler != null) - { - Invoker.invoke(channel, handler, attachment, null, e); - return null; - } - - return CompletedFuture.withFailure(e); - } - - var f = new PendingFuture(channel, handler, attachment, null); - f.setContext(cts); - t.ContinueWith(a => { try { f.setResult(a.GetAwaiter().GetResult()); } catch (Exception e) { f.setFailure(e); }; Invoker.invoke(f); }); - return f; - } - finally - { - SynchronizationContext.SetSynchronizationContext(c); - } - } - - /// - /// Executes the specified function on the channel group. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static global::java.util.concurrent.Future Execute(this DotNetAsynchronousChannelGroup self, TChannel channel, TArg arg, object attachment, CompletionHandler handler, Func func) - where TChannel : AsynchronousChannel - { - var c = SynchronizationContext.Current; - - try - { - SynchronizationContext.SetSynchronizationContext(self.executor().ToSynchronizationContext()); - var cts = new CancellationTokenSource(); - var t = func(channel, arg, global::java.lang.System.getSecurityManager() != null ? AccessController.getContext() : null, cts.Token); - - try - { - if (t.IsCompleted && t.IsFaulted) - t.GetAwaiter().GetResult(); - } - catch (Exception e) - { - if (handler != null) - { - Invoker.invoke(channel, handler, attachment, null, e); - return null; - } - - return CompletedFuture.withFailure(e); - } - - var f = new PendingFuture(channel, handler, attachment, null); - f.setContext(cts); - t.ContinueWith(a => { try { a.GetAwaiter().GetResult(); f.setResult(null); } catch (Exception e) { f.setFailure(e); }; Invoker.invoke(f); }); - return f; - } - finally - { - SynchronizationContext.SetSynchronizationContext(c); - } - } - - /// - /// Executes the specified function on the channel group. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static global::java.util.concurrent.Future Execute(this DotNetAsynchronousChannelGroup self, TChannel channel, TArg1 arg1, TArg2 arg2, object attachment, CompletionHandler handler, Func func) - where TChannel : AsynchronousChannel - { - var c = SynchronizationContext.Current; - - try - { - SynchronizationContext.SetSynchronizationContext(self.executor().ToSynchronizationContext()); - var cts = new CancellationTokenSource(); - var t = func(channel, arg1, arg2, global::java.lang.System.getSecurityManager() != null ? AccessController.getContext() : null, cts.Token); - - try - { - if (t.IsCompleted && t.IsFaulted) - t.GetAwaiter().GetResult(); - } - catch (Exception e) - { - if (handler != null) - { - Invoker.invoke(channel, handler, attachment, null, e); - return null; - } - - return CompletedFuture.withFailure(e); - } - - var f = new PendingFuture(channel, handler, attachment, null); - f.setContext(cts); - t.ContinueWith(a => { try { a.GetAwaiter().GetResult(); f.setResult(null); } catch (Exception e) { f.setFailure(e); }; Invoker.invoke(f); }); - return f; - } - finally - { - SynchronizationContext.SetSynchronizationContext(c); - } - } - - /// - /// Executes the specified function on the channel group. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static global::java.util.concurrent.Future Execute(this DotNetAsynchronousChannelGroup self, TChannel channel, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, object attachment, CompletionHandler handler, Func func) - where TChannel : AsynchronousChannel - { - var c = SynchronizationContext.Current; - - try - { - SynchronizationContext.SetSynchronizationContext(self.executor().ToSynchronizationContext()); - var cts = new CancellationTokenSource(); - var t = func(channel, arg1, arg2, arg3, arg4, arg5, global::java.lang.System.getSecurityManager() != null ? AccessController.getContext() : null, cts.Token); - - try - { - if (t.IsCompleted && t.IsFaulted) - t.GetAwaiter().GetResult(); - } - catch (Exception e) - { - if (handler != null) - { - Invoker.invoke(channel, handler, attachment, null, e); - return null; - } - - return CompletedFuture.withFailure(e); - } - - var f = new PendingFuture(channel, handler, attachment, null); - f.setContext(cts); - t.ContinueWith(a => { try { a.GetAwaiter().GetResult(); f.setResult(null); } catch (Exception e) { f.setFailure(e); }; Invoker.invoke(f); }); - return f; - } - finally - { - SynchronizationContext.SetSynchronizationContext(c); - } - } - - } - -} - -#endif diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousFileChannelImpl.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousFileChannelImpl.cs deleted file mode 100644 index c5ed3d948d..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousFileChannelImpl.cs +++ /dev/null @@ -1,1182 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.IO; -using System.Threading; - -using System.ComponentModel; -using System.Runtime.InteropServices; - -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.Util.Java.Nio; -using IKVM.Runtime; - -using Microsoft.Win32.SafeHandles; - -using Mono.Unix.Native; -using Mono.Unix; - -#if FIRST_PASS == false - -using java.io; -using java.nio; -using java.security; -using java.lang; -using java.nio.channels; - -using sun.nio.ch; - -#endif - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Implements the native methods for 'DotNetAsynchronousFileChannelImpl'. - /// - static class DotNetAsynchronousFileChannelImpl - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - -#endif - - /// - /// Implements the native method for 'onCancel0'. - /// - /// - /// - public static void onCancel0(object self, object task) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - OnCancel((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self, (PendingFuture)task); -#endif - } - - /// - /// Implements the native method for 'close0'. - /// - /// - public static void close0(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - Close((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self); -#endif - } - - /// - /// Implements the native method 'size0'. - /// - /// - public static long size0(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return Size((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self); -#endif - } - - /// - /// Implements the native method 'truncate0'. - /// - /// - public static object truncate0(object self, long size) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return Truncate((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self, size); -#endif - } - - /// - /// Implements the native method 'force0'. - /// - /// - public static void force0(object self, bool metaData) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - Force((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self, metaData); -#endif - } - - /// - /// Implements the native method for 'implLock0'. - /// - /// - /// - /// - /// - /// - /// - public static object implLock0(object self, long position, long size, bool shared, object attachment, object handler) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return ((global::sun.nio.ch.DotNetAsynchronousChannelGroup)((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self).group()).Execute((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self, position, size, shared, attachment, (global::java.nio.channels.CompletionHandler)handler, LockAsync); -#endif - } - - /// - /// Implements the native method for 'tryLock0'. - /// - /// - /// - /// - /// - public static object tryLock0(object self, long position, long size, bool shared) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return TryLock((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self, position, size, shared); -#endif - } - - /// - /// Implements the native method for 'tryLock0'. - /// - /// - /// - public static void implRelease0(object self, object fli) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - Release((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self, (FileLockImpl)fli); -#endif - } - - /// - /// Implements the native method for 'implRead0'. - /// - /// - /// - /// - /// - /// - public static object implRead0(object self, object dst, long position, object attachment, object handler) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return ((global::sun.nio.ch.DotNetAsynchronousChannelGroup)((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self).group()).Execute((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self, (global::java.nio.ByteBuffer)dst, position, attachment, (global::java.nio.channels.CompletionHandler)handler, ReadAsync); -#endif - } - - /// - /// Implements the native method for 'implWrite0'. - /// - /// - /// - /// - /// - /// - public static object implWrite0(object self, object src, long position, object attachment, object handler) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return ((global::sun.nio.ch.DotNetAsynchronousChannelGroup)((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self).group()).Execute((global::sun.nio.ch.DotNetAsynchronousFileChannelImpl)self, (global::java.nio.ByteBuffer)src, position, attachment, (global::java.nio.channels.CompletionHandler)handler, WriteAsync); -#endif - } - - -#if FIRST_PASS == false - - /// - /// Invoked when the pending future is cancelled. - /// - /// - /// - /// - static void OnCancel(global::sun.nio.ch.DotNetAsynchronousFileChannelImpl self, PendingFuture future) - { - // signal cancellation on associated cancellation token source - var cts = (CancellationTokenSource)future.getContext(); - cts?.Cancel(); - } - - /// - /// Invoked when the channel is closed. - /// - /// - /// - static void Close(global::sun.nio.ch.DotNetAsynchronousFileChannelImpl self) - { - if (self.fdObj == null) - return; - - self.closeLock.writeLock().@lock(); - - try - { - if (self.closed) - return; - - self.closed = true; - } - finally - { - self.closeLock.writeLock().unlock(); - } - - self.invalidateAllLocks(); - - var h = FileDescriptorAccessor.GetHandle(self.fdObj); - FileDescriptorAccessor.SetHandle(self.fdObj, -1); - LibIkvm.Instance.io_close_file(h); - } - - /// - /// - /// - /// - /// - static long Size(global::sun.nio.ch.DotNetAsynchronousFileChannelImpl self) - { - var stream = FileDescriptorAccessor.GetStream(self.fdObj); - if (stream == null) - throw new global::java.nio.channels.ClosedChannelException(); - - try - { - self.begin(); - - try - { - return stream.Length; - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - } - finally - { - self.end(); - } - } - - /// - /// - /// - /// - /// - static AsynchronousFileChannel Truncate(global::sun.nio.ch.DotNetAsynchronousFileChannelImpl self, long size) - { - if (size < 0) - throw new IllegalArgumentException("Negative size"); - if (self.writing == false) - throw new global::java.nio.channels.NonWritableChannelException(); - - var stream = FileDescriptorAccessor.GetStream(self.fdObj); - if (stream == null) - throw new global::java.nio.channels.AsynchronousCloseException(); - - // matters for VFS files - if (stream.CanWrite == false) - throw new global::java.nio.channels.NonWritableChannelException(); - - try - { - self.begin(); - - if (size < stream.Length) - stream.SetLength(size); - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - finally - { - self.end(); - } - - return self; - } - - /// - /// - /// - /// - /// - static void Force(global::sun.nio.ch.DotNetAsynchronousFileChannelImpl self, bool metaData) - { - var stream = FileDescriptorAccessor.GetStream(self.fdObj); - if (stream == null) - throw new global::java.nio.channels.AsynchronousCloseException(); - - // matters for VFS files - if (stream.CanWrite == false) - throw new global::java.nio.channels.NonWritableChannelException(); - - try - { - self.begin(); - stream.Flush(); - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - finally - { - self.end(); - } - } - - /// - /// Invokes the LockFileEx Win32 function. - /// - /// - /// - /// - /// - /// - /// - /// - [DllImport("kernel32")] - static extern unsafe int LockFileEx(SafeFileHandle hFile, int dwFlags, int dwReserved, int nNumberOfBytesToLockLow, int nNumberOfBytesToLockHigh, NativeOverlapped* lpOverlapped); - - /// - /// Wraps the LockFileEx function as an async operation. - /// - /// - static unsafe ValueTask LockFileExAsync(SafeFileHandle hFile, int dwFlags, int dwReserved, int nNumberOfBytesToLockLow, int nNumberOfBytesToLockHigh, Overlapped overlapped) - { - var task = new TaskCompletionSource(); - var iocb = (IOCompletionCallback)((errorCode, numBytes, nativeOverlapped) => - { - try - { - if (errorCode == 0) - task.SetResult(null); - else - task.SetException(new Win32Exception((int)errorCode)); - } - catch (System.Exception e) - { - task.SetException(e); - } - finally - { - Overlapped.Free(nativeOverlapped); - } - }); - - var optr = overlapped.Pack(iocb, null); - if (LockFileEx(hFile, dwFlags, dwReserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh, optr) == 0) - { - Overlapped.Free(optr); - throw new Win32Exception(Marshal.GetLastWin32Error()); - } - - return new ValueTask(task.Task); - } - - /// - /// Invokes the UnlockFileEx Win32 function. - /// - /// - /// - /// - /// - /// - /// - [DllImport("kernel32", SetLastError = true)] - static extern unsafe int UnlockFileEx(SafeFileHandle hFile, int dwReserved, int nNumberOfBytesToUnlockLow, int nNumberOfBytesToUnlockHigh, NativeOverlapped* lpOverlapped); - - /// - /// Record locking flags for OS X. - /// - enum OSX_LockType : short - { - - F_RDLCK = 1, - F_UNLCK = 2, - F_WRLCK = 3, - - } - - /// - /// Flock structure on OSX. Fields are in a different order than Mono.Posix. - /// - [StructLayout(LayoutKind.Sequential)] - struct OSX_Flock - { - - public long l_start; - public long l_len; - public int l_pid; - public OSX_LockType l_type; - public SeekFlags l_whence; - - } - - /// - /// 'fcntl' command values for OS X. - /// - enum OSX_FcntlCommand - { - - F_GETLK = 7, - F_SETLK = 8, - F_SETLKW = 9, - - } - - /// - /// 'errno' values for OS X. - /// - enum OSX_Errno - { - - EAGAIN = 35, - EACCES = 13, - EINTR = 4, - EDEADLK = 11, - - } - - /// - /// Invokes the 'fcntl' function on OS X. - /// - /// - /// - /// - /// - [DllImport("c", SetLastError = true, EntryPoint = "fcntl")] - static extern int OSX_fcntl(int fd, OSX_FcntlCommand cmd, ref OSX_Flock @lock); - - /// - /// Implements the Lock logic as an asynchronous task. - /// - /// - /// - /// - /// - /// - static Task LockAsync(global::sun.nio.ch.DotNetAsynchronousFileChannelImpl self, long position, long size, bool shared, AccessControlContext accessControlContext, CancellationToken cancellationToken) - { - if (shared && self.reading == false) - throw new global::java.nio.channels.NonReadableChannelException(); - if (shared == false && self.writing == false) - throw new global::java.nio.channels.NonWritableChannelException(); - - var stream = FileDescriptorAccessor.GetStream(self.fdObj); - if (stream == null) - return Task.FromException(new global::java.nio.channels.ClosedChannelException()); - if (stream is not FileStream fs) - throw new global::java.io.IOException("Stream does not support locking."); - - var fli = self.addToFileLockTable(position, size, shared); - if (fli == null) - return Task.FromException(new global::java.nio.channels.ClosedChannelException()); - - return ImplAsync(); - - async Task ImplAsync() - { - try - { - if (RuntimeUtil.IsWindows) - { - const int LOCKFILE_EXCLUSIVE_LOCK = 2; - - try - { - var o = new Overlapped(); - o.OffsetLow = (int)position; - o.OffsetHigh = (int)(position >> 32); - - var flags = 0; - if (shared == false) - flags |= LOCKFILE_EXCLUSIVE_LOCK; - - await LockFileExAsync(fs.SafeFileHandle, flags, 0, (int)size, (int)(size >> 32), o); - - return fli; - } - catch (System.Exception) when (IsOpen(self) == false) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - } - else if (RuntimeUtil.IsLinux) - { - while (true) - { - try - { - if (cancellationToken.IsCancellationRequested) - return null; - - try - { - self.begin(); - - var fl = new Flock(); - fl.l_whence = SeekFlags.SEEK_SET; - fl.l_len = size == long.MaxValue ? 0 : size; - fl.l_start = position; - fl.l_type = shared ? LockType.F_RDLCK : LockType.F_WRLCK; - - // fails immediately with EAGAIN or EACCES if cannot obtain - var r = Syscall.fcntl((int)fs.SafeFileHandle.DangerousGetHandle(), FcntlCommand.F_SETLK, ref fl); - if (r == -1) - { - var errno = Stdlib.GetLastError(); - if (errno == Errno.EAGAIN || errno == Errno.EACCES) - { - await Task.Delay(TimeSpan.FromMilliseconds(100)); - continue; - } - - UnixMarshal.ThrowExceptionForError(errno); - } - - return fli; - } - finally - { - self.end(); - } - } - catch (ObjectDisposedException) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception) when (IsOpen(self) == false) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - } - } - else if (RuntimeUtil.IsOSX) - { - while (true) - { - try - { - if (cancellationToken.IsCancellationRequested) - return null; - - try - { - self.begin(); - - var fl = new OSX_Flock(); - fl.l_whence = SeekFlags.SEEK_SET; - fl.l_len = size == long.MaxValue ? 0 : size; - fl.l_start = position; - fl.l_type = shared ? OSX_LockType.F_RDLCK : OSX_LockType.F_WRLCK; - - // fails immediately with EAGAIN or EACCES if cannot obtain - var r = OSX_fcntl((int)fs.SafeFileHandle.DangerousGetHandle(), OSX_FcntlCommand.F_SETLK, ref fl); - if (r == -1) - { - var errno = (OSX_Errno)(int)Stdlib.GetLastError(); - if (errno == OSX_Errno.EAGAIN || errno == OSX_Errno.EACCES) - { - await Task.Delay(TimeSpan.FromMilliseconds(100)); - continue; - } - - UnixMarshal.ThrowExceptionForError((Errno)(int)errno); - } - - return fli; - } - finally - { - self.end(); - } - } - catch (ObjectDisposedException) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception) when (IsOpen(self) == false) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - } - } - else - { - while (true) - { - try - { - if (cancellationToken.IsCancellationRequested) - return null; - - try - { - self.begin(); - - fs.Lock(position, size); - return fli; - } - catch (System.IO.IOException) - { - // we failed to acquire the lock, try again next iteration - } - finally - { - self.end(); - } - - // try again shortly - await Task.Delay(TimeSpan.FromMilliseconds(100)); - } - catch (ObjectDisposedException) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception) when (IsOpen(self) == false) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - } - } - } - catch - { - self.removeFromFileLockTable(fli); - } - - return null; - }; - } - - /// - /// Attempts to lock a file region. - /// - /// - /// - /// - /// - /// - static unsafe FileLock TryLock(global::sun.nio.ch.DotNetAsynchronousFileChannelImpl self, long position, long size, bool shared) - { - if (shared && self.reading == false) - throw new global::java.nio.channels.NonReadableChannelException(); - if (shared == false && self.writing == false) - throw new global::java.nio.channels.NonWritableChannelException(); - - if (IsOpen(self) == false) - throw new global::java.nio.channels.ClosedChannelException(); - - var stream = FileDescriptorAccessor.GetStream(self.fdObj); - if (stream == null) - throw new global::java.nio.channels.AsynchronousCloseException(); - if (stream is not FileStream fs) - throw new global::java.io.IOException("File does not support locking."); - - var fli = self.addToFileLockTable(position, size, shared); - if (fli == null) - throw new global::java.nio.channels.ClosedChannelException(); - - try - { - try - { - self.begin(); - - if (RuntimeUtil.IsWindows) - { - const int LOCKFILE_FAIL_IMMEDIATELY = 1; - const int LOCKFILE_EXCLUSIVE_LOCK = 2; - - var o = new Overlapped(); - o.OffsetLow = (int)position; - o.OffsetHigh = (int)(position >> 32); - - var flags = LOCKFILE_FAIL_IMMEDIATELY; - if (shared == false) - flags |= LOCKFILE_EXCLUSIVE_LOCK; - - // issue async request but wait for synchronous result - var t = LockFileExAsync(fs.SafeFileHandle, flags, 0, (int)size, (int)(size >> 32), o); - t.GetAwaiter().GetResult(); - - return fli; - } - else if (RuntimeUtil.IsLinux) - { - var fl = new Flock(); - fl.l_whence = SeekFlags.SEEK_SET; - fl.l_len = size == long.MaxValue ? 0 : size; - fl.l_start = position; - fl.l_type = shared ? LockType.F_RDLCK : LockType.F_WRLCK; - - // fails immediately with EAGAIN or EACCES if cannot obtain - if (Syscall.fcntl((int)fs.SafeFileHandle.DangerousGetHandle(), FcntlCommand.F_SETLK, ref fl) == 0) - return fli; - - var errno = Syscall.GetLastError(); - if (errno == Errno.EAGAIN || errno == Errno.EACCES) - { - self.removeFromFileLockTable(fli); - return null; - } - - UnixMarshal.ThrowExceptionForError(errno); - } - else if (RuntimeUtil.IsOSX) - { - var fl = new OSX_Flock(); - fl.l_whence = SeekFlags.SEEK_SET; - fl.l_len = size == long.MaxValue ? 0 : size; - fl.l_start = position; - fl.l_type = shared ? OSX_LockType.F_RDLCK : OSX_LockType.F_WRLCK; - - // fails immediately with EAGAIN or EACCES if cannot obtain - if (OSX_fcntl((int)fs.SafeFileHandle.DangerousGetHandle(), OSX_FcntlCommand.F_SETLK, ref fl) == 0) - return fli; - - var errno = (OSX_Errno)Stdlib.GetLastError(); - if (errno == OSX_Errno.EAGAIN || errno == OSX_Errno.EACCES) - { - self.removeFromFileLockTable(fli); - return null; - } - - UnixMarshal.ThrowExceptionForError((Errno)(int)errno); - } - else - { - fs.Lock(position, size); - } - } - catch (ObjectDisposedException) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception) when (IsOpen(self) == false) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - finally - { - self.end(); - } - } - catch - { - self.removeFromFileLockTable(fli); - } - - return null; - } - - /// - /// Implements the Release logic as an asynchronous task. - /// - /// - static unsafe void Release(global::sun.nio.ch.DotNetAsynchronousFileChannelImpl self, FileLockImpl fli) - { - if (IsOpen(self) == false) - return; - - var stream = FileDescriptorAccessor.GetStream(self.fdObj); - if (stream == null) - return; - - if (stream is not FileStream fs) - throw new global::java.io.IOException("File does not support locking."); - - try - { - self.begin(); - - var pos = fli.position(); - var size = fli.size(); - - if (RuntimeUtil.IsWindows) - { - const int ERROR_NOT_LOCKED = 158; - - try - { - var o = new Overlapped(); - o.OffsetLow = (int)pos; - o.OffsetHigh = (int)(pos >> 32); - var p = o.Pack(null, null); - - try - { - if (UnlockFileEx(fs.SafeFileHandle, 0, (int)size, (int)(size >> 32), p) == 0) - throw new Win32Exception(Marshal.GetLastWin32Error()); - } - finally - { - Overlapped.Free(p); - } - } - catch (Win32Exception e) when (e.ErrorCode == ERROR_NOT_LOCKED) - { - return; - } - } - else if (RuntimeUtil.IsLinux) - { - var fl = new Flock(); - fl.l_whence = SeekFlags.SEEK_SET; - fl.l_len = size == long.MaxValue ? 0 : size; - fl.l_start = pos; - fl.l_type = LockType.F_UNLCK; - - var r = Syscall.fcntl((int)fs.SafeFileHandle.DangerousGetHandle(), FcntlCommand.F_SETLK, ref fl); - if (r == -1) - UnixMarshal.ThrowExceptionForLastErrorIf(r); - } - else if (RuntimeUtil.IsOSX) - { - var fl = new OSX_Flock(); - fl.l_whence = SeekFlags.SEEK_SET; - fl.l_len = size == long.MaxValue ? 0 : size; - fl.l_start = pos; - fl.l_type = OSX_LockType.F_UNLCK; - - var r = OSX_fcntl((int)fs.SafeFileHandle.DangerousGetHandle(), OSX_FcntlCommand.F_SETLK, ref fl); - if (r == -1) - UnixMarshal.ThrowExceptionForLastErrorIf(r); - } - else - { - fs.Unlock(pos, size); - } - } - catch (System.IO.IOException e) when (NotLockedHack.IsErrorNotLocked(e)) - { - return; - } - catch (ObjectDisposedException) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception) when (IsOpen(self) == false) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - finally - { - self.end(); - } - } - - /// - /// Implements the Read logic as an asynchronous task. - /// - /// - /// - /// - /// - /// - static Task ReadAsync(global::sun.nio.ch.DotNetAsynchronousFileChannelImpl self, global::java.nio.ByteBuffer dst, long position, AccessControlContext accessControlContext, CancellationToken cancellationToken) - { - if (self.reading == false) - throw new global::java.nio.channels.NonReadableChannelException(); - if (position < 0) - throw new global::java.lang.IllegalArgumentException("Negative position"); - if (dst.isReadOnly()) - throw new global::java.lang.IllegalArgumentException("Read-only buffer"); - - if (IsOpen(self) == false) - return Task.FromException(new global::java.nio.channels.ClosedChannelException()); - - var stream = FileDescriptorAccessor.GetStream(self.fdObj); - if (stream == null) - return Task.FromException(new global::java.nio.channels.ClosedChannelException()); - if (stream.CanRead == false) - return Task.FromException(new global::java.io.IOException("Stream does not support reading.")); - - // check buffer - int pos = dst.position(); - int lim = dst.limit(); - int rem = pos <= lim ? lim - pos : 0; - if (rem == 0) - return Task.FromResult(new Integer(0)); - if (pos > lim) - return Task.FromException(new global::java.lang.IllegalArgumentException("Position after limit.")); - - if (cancellationToken.IsCancellationRequested) - return null; - - return ImplAsync(); - - async Task ImplAsync() - { - var lck = FileDescriptorAccessor.GetSemaphore(self.fdObj); - if (lck == null) - { - lck = new SemaphoreSlim(1, 1); - if (FileDescriptorAccessor.CompareExchangeSemaphore(self.fdObj, lck, null) != null) - lck.Dispose(); - - lck = FileDescriptorAccessor.GetSemaphore(self.fdObj); - } - - try - { - await lck.WaitAsync(cancellationToken); - } - catch (OperationCanceledException) - { - return null; - } - - try - { - // move file to specified position - if (stream.Position != position) - { - if (stream.CanSeek == false) - throw new global::java.lang.IllegalArgumentException("Seek failed."); - - stream.Seek(position, SeekOrigin.Begin); - } - -#if NETFRAMEWORK - if (dst is DirectBuffer dir) - { - var tmp = new byte[rem]; - var n = await stream.ReadAsync(tmp, 0, rem, cancellationToken); - dst.put(tmp, 0, n); - return new global::java.lang.Integer(n); - } - else - { - var n = await stream.ReadAsync(dst.array(), dst.arrayOffset() + pos, rem, cancellationToken); - dst.position(pos + n); - return new global::java.lang.Integer(n); - } -#else - if (dst is DirectBuffer dir) - { - using var mgr = new DirectBufferMemoryManager(dir); - var mem = mgr.Memory.Slice(pos, rem); - var n = await stream.ReadAsync(mem, cancellationToken); - dst.position(pos + n); - return new Integer(n); - } - else - { - var n = await stream.ReadAsync(dst.array(), dst.arrayOffset() + pos, rem, cancellationToken); - dst.position(pos + n); - return new Integer(n); - } -#endif - } - catch (OperationCanceledException) - { - return null; - } - catch (ObjectDisposedException) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception) when (IsOpen(self) == false) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception) when (cancellationToken.IsCancellationRequested) - { - return null; - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - finally - { - lck.Release(); - } - } - } - - /// - /// Implements the Write logic as an asynchronous task. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - static Task WriteAsync(global::sun.nio.ch.DotNetAsynchronousFileChannelImpl self, global::java.nio.ByteBuffer src, long position, AccessControlContext accessControlContext, CancellationToken cancellationToken) - { - if (self.writing == false) - throw new global::java.nio.channels.NonWritableChannelException(); - if (position < 0) - throw new global::java.lang.IllegalArgumentException("Negative position"); - - if (IsOpen(self) == false) - return Task.FromException(new global::java.nio.channels.ClosedChannelException()); - - var stream = FileDescriptorAccessor.GetStream(self.fdObj); - if (stream == null) - return Task.FromException(new global::java.nio.channels.ClosedChannelException()); - if (stream.CanWrite == false) - return Task.FromException(new global::java.io.IOException("Stream does not support writing.")); - - // check buffer - int pos = src.position(); - int lim = src.limit(); - int rem = pos <= lim ? lim - pos : 0; - if (rem == 0) - return Task.FromResult(new global::java.lang.Integer(0)); - if (pos > lim) - return Task.FromException(new global::java.lang.IllegalArgumentException("Position after limit.")); - - if (cancellationToken.IsCancellationRequested) - return null; - - return ImplAsync(); - - async Task ImplAsync() - { - var lck = FileDescriptorAccessor.GetSemaphore(self.fdObj); - if (lck == null) - { - lck = new SemaphoreSlim(1, 1); - if (FileDescriptorAccessor.CompareExchangeSemaphore(self.fdObj, lck, null) != null) - lck.Dispose(); - - lck = FileDescriptorAccessor.GetSemaphore(self.fdObj); - } - - try - { - await lck.WaitAsync(cancellationToken); - } - catch (OperationCanceledException) - { - return null; - } - - try - { - // move file to specified position - if (stream.Position != position) - { - if (stream.CanSeek == false) - throw new global::java.lang.IllegalArgumentException("Seek failed."); - - stream.Seek(position, SeekOrigin.Begin); - } - -#if NETFRAMEWORK - if (src is DirectBuffer dir) - { - var tmp = new byte[rem]; - src.get(tmp, 0, rem); - await stream.WriteAsync(tmp, 0, rem, cancellationToken); - return new global::java.lang.Integer(rem); - } - else - { - await stream.WriteAsync(src.array(), src.arrayOffset() + pos, rem, cancellationToken); - src.position(pos + rem); - return new global::java.lang.Integer(rem); - } -#else - if (src is DirectBuffer dir) - { - using var mgr = new DirectBufferMemoryManager(dir); - var mem = mgr.Memory.Slice(pos, rem); - await stream.WriteAsync(mem, cancellationToken); - src.position(pos + rem); - return new Integer(rem); - } - else - { - await stream.WriteAsync(src.array(), src.arrayOffset() + pos, rem, cancellationToken); - src.position(pos + rem); - return new Integer(rem); - } -#endif - } - catch (OperationCanceledException) - { - return null; - } - catch (ObjectDisposedException) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception) when (IsOpen(self) == false) - { - throw new global::java.nio.channels.AsynchronousCloseException(); - } - catch (System.Exception) when (cancellationToken.IsCancellationRequested) - { - return null; - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - finally - { - lck.Release(); - } - } - } - - static bool IsOpen(global::sun.nio.ch.DotNetAsynchronousFileChannelImpl ch) - { - Interlocked.MemoryBarrier(); - return ch.isOpen(); - } - -#endif - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousServerSocketChannelImpl.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousServerSocketChannelImpl.cs deleted file mode 100644 index 1b4d2f1d0a..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousServerSocketChannelImpl.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading.Tasks; -using System.Threading; - -using IKVM.Runtime; -using IKVM.Runtime.Util.Java.Security; -using IKVM.Runtime.Util.Java.Net; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.Accessors.Sun.Nio.Ch; -using IKVM.Runtime.Accessors.Java.Lang; - -#if FIRST_PASS == false - -using java.lang; -using java.io; -using java.nio.channels; -using java.util.concurrent; - -using sun.nio.ch; - -#endif - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Implements the native methods for 'DotNetAsynchronousServerSocketChannelImpl'. - /// - static class DotNetAsynchronousServerSocketChannelImpl - { - -#if FIRST_PASS == false - - static SystemAccessor systemAccessor; - static SecurityManagerAccessor securityManagerAccessor; - static AccessControllerAccessor accessControllerAccessor; - static FileDescriptorAccessor fileDescriptorAccessor; - static DotNetAsynchronousServerSocketChannelImplAccessor dotNetAsynchronousServerSocketChannelImplAccessor; - static DotNetAsynchronousSocketChannelImplAccessor dotNetAsynchronousSocketChannelImplAccessor; - - static SystemAccessor SystemAccessor => JVM.Internal.BaseAccessors.Get(ref systemAccessor); - - static SecurityManagerAccessor SecurityManagerAccessor => JVM.Internal.BaseAccessors.Get(ref securityManagerAccessor); - - static AccessControllerAccessor AccessControllerAccessor => JVM.Internal.BaseAccessors.Get(ref accessControllerAccessor); - - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - - static DotNetAsynchronousServerSocketChannelImplAccessor DotNetAsynchronousServerSocketChannelImplAccessor => JVM.Internal.BaseAccessors.Get(ref dotNetAsynchronousServerSocketChannelImplAccessor); - - static DotNetAsynchronousSocketChannelImplAccessor DotNetAsynchronousSocketChannelImplAccessor => JVM.Internal.BaseAccessors.Get(ref dotNetAsynchronousSocketChannelImplAccessor); - -#endif - - /// - /// Implements the native method for 'implAccept0'. - /// - /// - /// - /// - public static object implAccept0(object self, object attachment, object handler) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return Accept((global::sun.nio.ch.DotNetAsynchronousServerSocketChannelImpl)self, attachment, (CompletionHandler)handler); -#endif - } - - /// - /// Implements the native methodf or 'implClose0'. - /// - /// - public static void implClose0(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - Close((global::sun.nio.ch.DotNetAsynchronousServerSocketChannelImpl)self); -#endif - } - -#if FIRST_PASS == false - - /// - /// Implements the Accept logic as an asynchronous task converted to a Future. - /// - /// - /// - /// - /// - static Future Accept(global::sun.nio.ch.DotNetAsynchronousServerSocketChannelImpl self, object attachment, CompletionHandler handler) - { - return ((DotNetAsynchronousChannelGroup)self.group()).Execute(self, attachment, handler, AcceptAsync); - } - - /// - /// Creates a new client channel. - /// - /// - /// - static object CreateClientChannel(object server, object fd, object remote) - { - try - { - DotNetAsynchronousServerSocketChannelImplAccessor.InvokeBegin(server); - return DotNetAsynchronousSocketChannelImplAccessor.Init(DotNetAsynchronousServerSocketChannelImplAccessor.InvokeGroup(server), fd, remote); - } - finally - { - DotNetAsynchronousServerSocketChannelImplAccessor.InvokeEnd(server); - } - } - - /// - /// Implements the Accept logic as an asynchronous task. - /// - /// - /// - /// s - static Task AcceptAsync(global::sun.nio.ch.DotNetAsynchronousServerSocketChannelImpl self, object accessControlContext, CancellationToken cancellationToken) - { - if (self.isOpen() == false) - return Task.FromException(new ClosedChannelException()); - - if (self.isAcceptKilled()) - throw new RuntimeException("Accept not allowed due to cancellation."); - - if (self.localAddress == null) - throw new NotYetBoundException(); - - if (self.accepting.compareAndSet(false, true) == false) - throw new AcceptPendingException(); - - return ImplAsync(); - - async Task ImplAsync() - { - try - { - try - { - // execute asynchronous Accept task - var listenSocket = FileDescriptorAccessor.GetSocket(self.fd); -#if NETFRAMEWORK - var acceptSocket = await Task.Factory.FromAsync(listenSocket.BeginAccept, listenSocket.EndAccept, 0, null); -#else - var acceptSocket = await listenSocket.AcceptAsync(); -#endif - - // connection accept completed after group has shutdown - if (self.group().isShutdown()) - throw new ShutdownChannelGroupException(); - - try - { - DotNetAsynchronousServerSocketChannelImplAccessor.InvokeBegin(self); - - // obtain new addresses - var local = ((IPEndPoint)acceptSocket.LocalEndPoint).ToInetSocketAddress(); - var remote = ((IPEndPoint)acceptSocket.RemoteEndPoint).ToInetSocketAddress(); - var fdo = FileDescriptorAccessor.Init(); - FileDescriptorAccessor.SetSocket(fdo, acceptSocket); - var client = CreateClientChannel(self, fdo, remote); - - // check access to specified host - if (accessControlContext != null) - AccessControllerAccessor.InvokeDoPrivileged(new ActionPrivilegedAction(() => SecurityManagerAccessor.InvokeCheckAccept(SystemAccessor.InvokeGetSecurityManager(), (string)remote.getAddress().getHostAddress(), (int)remote.getPort())), accessControlContext); - - // return resulting channel - return client; - } - finally - { - DotNetAsynchronousServerSocketChannelImplAccessor.InvokeEnd(self); - } - } - catch (SecurityException) - { - throw; - } - catch (System.Net.Sockets.SocketException) when (self.isOpen() == false) - { - throw new AsynchronousCloseException(); - } - catch (System.Net.Sockets.SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new AsynchronousCloseException(); - } - catch (System.Exception e) - { - throw new IOException(e); - } - } - finally - { - self.accepting.set(false); - } - } - } - - /// - /// Closes the socket associaed with the server socket channel. - /// - /// - static void Close(global::sun.nio.ch.DotNetAsynchronousServerSocketChannelImpl self) - { - if (self.fd == null) - return; - - try - { - var h = FileDescriptorAccessor.GetHandle(self.fd); - FileDescriptorAccessor.SetHandle(self.fd, -1); - LibIkvm.Instance.io_close_socket(h); - } - catch - { - // ignore - } - } - -#endif - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousSocketChannelImpl.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousSocketChannelImpl.cs deleted file mode 100644 index 4e3b179352..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/DotNetAsynchronousSocketChannelImpl.cs +++ /dev/null @@ -1,908 +0,0 @@ -using System; -using System.Buffers; -using System.Net.Sockets; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.Accessors.Sun.Nio.Ch; -using IKVM.Runtime.Util.Java.Net; -using IKVM.Runtime.Util.Java.Nio; -using IKVM.Runtime.Util.Java.Security; - -#if FIRST_PASS == false - -using java.io; -using java.lang; -using java.net; -using java.nio; -using java.nio.channels; -using java.security; -using java.util.concurrent; - -using sun.nio.ch; -using sun.security.util; - -#endif - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Implements the native methods for 'DotNetAsynchronousSocketChannelImpl'. - /// - static class DotNetAsynchronousSocketChannelImpl - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - static DotNetAsynchronousSocketChannelImplAccessor dotNetAsynchronousSocketChannelImplAccessor; - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - - static DotNetAsynchronousSocketChannelImplAccessor DotNetAsynchronousSocketChannelImplAccessor => JVM.Internal.BaseAccessors.Get(ref dotNetAsynchronousSocketChannelImplAccessor); - -#endif - - /// - /// Implements the native method for 'onCancel0'. - /// - /// - /// - public static void onCancel0(object self, object task) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - OnCancel((global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl)self, (PendingFuture)task); -#endif - } - - /// - /// Implements the native method for 'implClose0'. - /// - /// - public static void implClose0(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - Close((global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl)self); -#endif - } - - /// - /// Implements the native method for 'implConnect0'. - /// - /// - /// - /// - /// - public static object implConnect0(object self, object remote, object attachment, object handler) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return ((DotNetAsynchronousChannelGroup)((global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl)self).group()).Execute((global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl)self, (global::java.net.SocketAddress)remote, attachment, (CompletionHandler)handler, ConnectAsync); -#endif - } - - /// - /// Implements the native method for 'implRead0'. - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static object implRead0(object self, bool isScatteringRead, object dst, object[] dsts, long timeout, object unit, object attachment, object handler) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return ((DotNetAsynchronousChannelGroup)((global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl)self).group()).Execute((global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl)self, isScatteringRead, (ByteBuffer)dst, (ByteBuffer[])dsts, timeout, (TimeUnit)unit, attachment, (CompletionHandler)handler, ReadAsync); -#endif - } - - /// - /// Implements the native method for 'implWrite0'. - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static object implWrite0(object self, bool gatheringWrite, object src, object[] srcs, long timeout, object unit, object attachment, object handler) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return ((DotNetAsynchronousChannelGroup)((global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl)self).group()).Execute((global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl)self, gatheringWrite, (ByteBuffer)src, (ByteBuffer[])srcs, timeout, (TimeUnit)unit, attachment, (CompletionHandler)handler, WriteAsync); -#endif - } - - -#if FIRST_PASS == false - - /// - /// Invoked when the pending future is cancelled. - /// - /// - /// - /// - static void OnCancel(global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl self, PendingFuture future) - { - // signal cancellation on associated cancellation token source - var cts = (CancellationTokenSource)future.getContext(); - cts?.Cancel(); - } - - /// - /// - /// - /// - /// - static void Close(global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl self) - { - if (self.fd == null) - return; - - try - { - var h = FileDescriptorAccessor.GetHandle(self.fd); - FileDescriptorAccessor.SetHandle(self.fd, -1); - LibIkvm.Instance.io_close_socket(h); - } - catch - { - // ignore - } - } - - /// - /// Implements the Connect logic as an asynchronous task. - /// - /// - /// - /// - /// - static Task ConnectAsync(global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl self, global::java.net.SocketAddress remote, global::java.security.AccessControlContext accessControlContext, CancellationToken cancellationToken) - { - if (self.isOpen() == false) - return Task.FromException(new ClosedChannelException()); - - var socket = FileDescriptorAccessor.GetSocket(self.fd); - if (socket == null) - return Task.FromException(new global::java.nio.channels.ClosedChannelException()); - - // cancel was invoked during the operation - if (cancellationToken.IsCancellationRequested) - throw new IllegalStateException("Connect not allowed due to timeout or cancellation."); - - // checks the validity of the socket address - var remoteAddress = global::sun.nio.ch.Net.checkAddress(remote); - if (accessControlContext != null) - AccessController.doPrivileged(new ActionPrivilegedAction(() => global::java.lang.System.getSecurityManager()?.checkConnect(remoteAddress.getAddress().getHostAddress(), remoteAddress.getPort())), accessControlContext); - - lock (self.stateLock) - { - // ensure channel is not already connected - if (self.state == AsynchronousSocketChannelImpl.ST_CONNECTED) - throw new AlreadyConnectedException(); - - // ensure channel is not already in process of being connected - if (self.state == AsynchronousSocketChannelImpl.ST_PENDING) - throw new ConnectionPendingException(); - - // ensure channel is bound to a local address - if (self.localAddress == null) - { - try - { - var any = new InetSocketAddress(0); - if (accessControlContext == null) - self.bind(any); - else - AccessController.doPrivileged(new ActionPrivilegedExceptionAction(() => self.bind(any)), accessControlContext); - } - catch (global::java.io.IOException e) - { - try - { - self.close(); - } - catch - { - // ignore - } - - self.state = AsynchronousSocketChannelImpl.ST_PENDING; - return Task.FromException(e); - } - } - } - - return ImplAsync(); - - async Task ImplAsync() - { - try - { - try - { - // execute asynchronous Connect task -#if NETFRAMEWORK - await Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, remoteAddress.ToIPEndpoint(), null); -#else - await socket.ConnectAsync(remoteAddress.ToIPEndpoint()); -#endif - - try - { - self.begin(); - - // set the channel to connected - lock (self.stateLock) - { - self.state = AsynchronousSocketChannelImpl.ST_CONNECTED; - self.remoteAddress = remoteAddress; - } - - return; - } - finally - { - self.end(); - } - } - catch (System.Net.Sockets.SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new AsynchronousCloseException(); - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - } - catch (System.Exception) - { - try - { - if (self.isOpen()) - self.close(); - } - catch - { - // ignore - } - - throw; - } - } - } - - /// - /// Implements the Accept logic as an asynchronous task. - /// - /// - /// This implementation differs based on whether we are doing a scattering read, whether there is a timeout specified and whether the buffers under consideration are direct. - /// - /// - /// - /// - /// - /// - /// - /// - /// - static Task ReadAsync(global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl self, bool isScatteringRead, ByteBuffer dst, ByteBuffer[] dsts, long timeout, TimeUnit unit, AccessControlContext accessControlContext, CancellationToken cancellationToken) - { - var socket = FileDescriptorAccessor.GetSocket(self.fd); - if (socket == null) - throw new global::java.io.IOException("Socket is closed."); - - // we were told to do a scattering read, but only received one buffer, do a regular read - if (isScatteringRead && dsts.Length == 1) - dst = dsts[0]; - - return ImplAsync(); - - async Task ImplAsync() - { - try - { - // timeout was specified, wait for data to be available - var t = (int)System.Math.Min(TimeUnit.MILLISECONDS.convert(timeout, unit), int.MaxValue); - if (t > 0) - { - // non-optimal usage, but we have no way to combine timeout with true async - return await Task.Run(() => - { - var previousBlocking = socket.Blocking; - var previousReceiveTimeout = socket.ReceiveTimeout; - - try - { - socket.Blocking = true; - socket.ReceiveTimeout = t; - - if (dst != null) - { - int length = 0; - - int pos = dst.position(); - int lim = dst.limit(); - int rem = pos <= lim ? lim - pos : 0; - - if (dst is DirectBuffer dir) - { -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(rem); - - try - { - length = socket.Receive(buf, rem, SocketFlags.None); - Marshal.Copy(buf, 0, (IntPtr)dir.address() + pos, length); - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - unsafe - { - length = socket.Receive(new Span((byte*)(IntPtr)dir.address() + pos, rem), SocketFlags.None); - } -#endif - } - else - { - // synchronous read (inside of a Task) directly into the underlying array of the buffer - length = socket.Receive(dst.array(), dst.arrayOffset() + pos, rem, SocketFlags.None); - } - - dst.position(pos + length); - - // no data returned means socket is EOF - if (length == 0) - length = global::sun.nio.ch.IOStatus.EOF; - - return isScatteringRead ? Long.valueOf(length) : Integer.valueOf(length); - } - else - { - int length = 0; - var bufs = new ArraySegment[dsts.Length]; - - try - { - // prepare array segments for buffers - for (int i = 0; i < dsts.Length; i++) - { - var dbf = dsts[i]; - int pos = dbf.position(); - int lim = dbf.limit(); - int rem = pos <= lim ? lim - pos : 0; - - if (dbf is DirectBuffer dir) - bufs[i] = new ArraySegment(ArrayPool.Shared.Rent(rem), 0, rem); - else - bufs[i] = new ArraySegment(dbf.array(), dbf.arrayOffset() + pos, rem); - } - - // receive data into segments - length = socket.Receive(bufs, SocketFlags.None); - - // copy segments back into buffers - var l = length; - for (int i = 0; i < dsts.Length; i++) - { - var dbf = dsts[i]; - var buf = bufs[i]; - int pos = dbf.position(); - int lim = dbf.limit(); - int rem = pos <= lim ? lim - pos : 0; - int len = System.Math.Min(l, rem); - - if (dbf is DirectBuffer dir) - Marshal.Copy(buf.Array, 0, (IntPtr)dir.address() + pos, len); - - dbf.position(pos + len); - l -= len; - } - - // we should have accounted for all of the bytes - if (l != 0) - throw new global::java.lang.RuntimeException("Bytes remaining after read."); - - // no data returned means socket is EOF - if (length == 0) - length = global::sun.nio.ch.IOStatus.EOF; - - // return total number of bytes read - return isScatteringRead ? Long.valueOf(length) : Integer.valueOf(length); - } - finally - { - for (int i = 0; i < dsts.Length; i++) - { - var dbf = dsts[i]; - var buf = bufs[i]; - - if (dbf is DirectBuffer dir) - ArrayPool.Shared.Return(buf.Array); - } - } - } - } - finally - { - socket.Blocking = previousBlocking; - socket.ReceiveTimeout = previousReceiveTimeout; - } - }); - } - else - { - var previousBlocking = socket.Blocking; - var previousReceiveTimeout = socket.ReceiveTimeout; - - try - { - socket.Blocking = false; - socket.ReceiveTimeout = 0; - - if (dst != null) - { - int length = 0; - - int pos = dst.position(); - int lim = dst.limit(); - int rem = pos <= lim ? lim - pos : 0; - - if (dst is DirectBuffer dir) - { -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(rem); - - try - { - length = await Task.Factory.FromAsync((cb, state) => socket.BeginReceive(buf, 0, rem, SocketFlags.None, cb, state), socket.EndReceive, null); - Marshal.Copy(buf, 0, (IntPtr)dir.address() + pos, length); - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - using var mgr = new DirectBufferMemoryManager(dir); - var mem = mgr.Memory.Slice(pos, rem); - length = await socket.ReceiveAsync(mem, SocketFlags.None, cancellationToken); -#endif - } - else - { -#if NETFRAMEWORK - length = await Task.Factory.FromAsync((cb, state) => socket.BeginReceive(dst.array(), dst.arrayOffset() + pos, rem, SocketFlags.None, cb, state), socket.EndReceive, null); -#else - length = await socket.ReceiveAsync(new Memory(dst.array(), dst.arrayOffset() + pos, rem), SocketFlags.None, cancellationToken); -#endif - } - - dst.position(pos + length); - - // no data returned means socket is EOF - if (length == 0) - length = global::sun.nio.ch.IOStatus.EOF; - - return isScatteringRead ? Long.valueOf(length) : Integer.valueOf(length); - } - else - { - int length = 0; - var bufs = new ArraySegment[dsts.Length]; - - try - { - // prepare array segments for buffers - for (int i = 0; i < dsts.Length; i++) - { - var dbf = dsts[i]; - int pos = dbf.position(); - int lim = dbf.limit(); - int rem = pos <= lim ? lim - pos : 0; - - if (dbf is DirectBuffer dir) - bufs[i] = new ArraySegment(ArrayPool.Shared.Rent(rem), 0, rem); - else - bufs[i] = new ArraySegment(dbf.array(), dbf.arrayOffset() + pos, rem); - } - - // receive data into segments -#if NETFRAMEWORK - length = await Task.Factory.FromAsync(socket.BeginReceive, socket.EndReceive, bufs, SocketFlags.None, null); -#else - length = await socket.ReceiveAsync(bufs, SocketFlags.None); -#endif - - var l = length; - for (int i = 0; i < dsts.Length; i++) - { - var dbf = dsts[i]; - var buf = bufs[i]; - int pos = dbf.position(); - int lim = dbf.limit(); - int rem = pos <= lim ? lim - pos : 0; - int len = System.Math.Min(l, rem); - - if (dbf is DirectBuffer dir) - Marshal.Copy(buf.Array, 0, (IntPtr)dir.address() + pos, len); - - dbf.position(pos + len); - l -= len; - } - - // we should have accounted for all of the bytes - if (l != 0) - throw new RuntimeException("Bytes remaining after read."); - - // no data returned means socket is EOF - if (length == 0) - length = global::sun.nio.ch.IOStatus.EOF; - - // return total number of bytes read - return isScatteringRead ? Long.valueOf(length) : Integer.valueOf(length); - } - finally - { - for (int i = 0; i < dsts.Length; i++) - { - var dbf = dsts[i]; - var buf = bufs[i]; - - if (dbf is DirectBuffer dir) - ArrayPool.Shared.Return(buf.Array); - } - } - - } - } - finally - { - socket.Blocking = previousBlocking; - socket.ReceiveTimeout = previousReceiveTimeout; - } - } - } - catch (System.Net.Sockets.SocketException e) when (e.SocketErrorCode == SocketError.TimedOut) - { - DotNetAsynchronousSocketChannelImplAccessor.InvokeEnableReading(self, true); - throw new global::java.nio.channels.InterruptedByTimeoutException(); - } - catch (System.Net.Sockets.SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new AsynchronousCloseException(); - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - finally - { - self.enableReading(); - } - } - } - - /// - /// Implements the Accept logic as an asynchronous task. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - static Task WriteAsync(global::sun.nio.ch.DotNetAsynchronousSocketChannelImpl self, bool gatheringWrite, ByteBuffer src, ByteBuffer[] srcs, long timeout, TimeUnit unit, AccessControlContext accessControlContext, CancellationToken cancellationToken) - { - var socket = FileDescriptorAccessor.GetSocket(self.fd); - if (socket == null) - throw new global::java.io.IOException("Socket is closed."); - - // we were told to do a scattering read, but only received one buffer, do a regular read - if (gatheringWrite && srcs.Length == 1) - src = srcs[0]; - - return ImplAsync(); - - async Task ImplAsync() - { - try - { - // timeout was specified, wait for data to be sent - var t = (int)System.Math.Min(TimeUnit.MILLISECONDS.convert(timeout, unit), int.MaxValue); - if (t > 0) - { - // non-optimal usage, but we have no way to combine timeout with true async - return await Task.Run(() => - { - var previousBlocking = socket.Blocking; - var previousSendTimeout = socket.SendTimeout; - - try - { - socket.Blocking = true; - socket.SendTimeout = t; - - if (src != null) - { - int length = 0; - - int pos = src.position(); - int lim = src.limit(); - int rem = pos <= lim ? lim - pos : 0; - - if (src is DirectBuffer dir) - { -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(rem); - - try - { - Marshal.Copy((IntPtr)dir.address() + pos, buf, 0, rem); - length = socket.Send(buf, rem, SocketFlags.None); - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - unsafe - { - length = socket.Send(new ReadOnlySpan((byte*)(IntPtr)dir.address() + pos, rem), SocketFlags.None); - } -#endif - } - else - { - length = socket.Send(src.array(), src.arrayOffset() + pos, rem, SocketFlags.None); - } - - src.position(pos + length); - return gatheringWrite ? Long.valueOf(length) : Integer.valueOf(length); - } - else - { - int length = 0; - var bufs = new ArraySegment[srcs.Length]; - - try - { - // prepare array segments for buffers - for (int i = 0; i < srcs.Length; i++) - { - var dbf = srcs[i]; - int pos = dbf.position(); - int lim = dbf.limit(); - int rem = pos <= lim ? lim - pos : 0; - - if (dbf is DirectBuffer dir) - { - var buf = ArrayPool.Shared.Rent(rem); - Marshal.Copy((IntPtr)dir.address() + pos, buf, 0, rem); - bufs[i] = new ArraySegment(buf, 0, rem); - } - else - bufs[i] = new ArraySegment(dbf.array(), dbf.arrayOffset() + pos, rem); - } - - // send data from segments - length = socket.Send(bufs, SocketFlags.None); - } - finally - { - for (int i = 0; i < srcs.Length; i++) - { - var dbf = srcs[i]; - var buf = bufs[i]; - - // return temporary buffer - if (dbf is DirectBuffer dir) - ArrayPool.Shared.Return(buf.Array); - } - } - - // advance buffers by amount sent - var l = length; - for (int i = 0; i < srcs.Length; i++) - { - var dbf = srcs[i]; - int pos = dbf.position(); - int lim = dbf.limit(); - int rem = pos <= lim ? lim - pos : 0; - var len = System.Math.Min(l, rem); - - dbf.position(pos + len); - l -= len; - } - - // return total number of bytes written - return gatheringWrite ? Long.valueOf(length) : Integer.valueOf(length); - } - } - finally - { - socket.Blocking = previousBlocking; - socket.SendTimeout = previousSendTimeout; - } - }); - } - else - { - var previousBlocking = socket.Blocking; - var previousSendTimeout = socket.SendTimeout; - - try - { - socket.Blocking = false; - socket.SendTimeout = 0; - - if (src != null) - { - int length = 0; - - int pos = src.position(); - int lim = src.limit(); - int rem = pos <= lim ? lim - pos : 0; - - if (src is DirectBuffer dir) - { -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(rem); - - try - { - Marshal.Copy((IntPtr)dir.address() + pos, buf, 0, rem); - length = await Task.Factory.FromAsync((cb, state) => socket.BeginSend(buf, 0, rem, SocketFlags.None, cb, state), socket.EndSend, null); - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - using var mgr = new DirectBufferMemoryManager(dir); - var mem = mgr.Memory.Slice(pos, rem); - length = await socket.SendAsync(mem, SocketFlags.None, cancellationToken); -#endif - } - else - { -#if NETFRAMEWORK - length = await Task.Factory.FromAsync((cb, state) => socket.BeginSend(src.array(), src.arrayOffset() + pos, rem, SocketFlags.None, cb, state), socket.EndSend, null); -#else - length = await socket.SendAsync(new Memory(src.array(), src.arrayOffset() + pos, rem), SocketFlags.None, cancellationToken); -#endif - } - - src.position(pos + length); - return gatheringWrite ? Long.valueOf(length) : Integer.valueOf(length); - } - else - { - int length = 0; - var bufs = new ArraySegment[srcs.Length]; - - try - { - // prepare array segments for buffers - for (int i = 0; i < srcs.Length; i++) - { - var dbf = srcs[i]; - int pos = dbf.position(); - int lim = dbf.limit(); - int rem = pos <= lim ? lim - pos : 0; - - if (dbf is DirectBuffer dir) - { - var buf = ArrayPool.Shared.Rent(rem); - Marshal.Copy((IntPtr)dir.address() + pos, buf, 0, rem); - bufs[i] = new ArraySegment(buf, 0, rem); - } - else - bufs[i] = new ArraySegment(dbf.array(), dbf.arrayOffset() + pos, rem); - } - - // send data from segments -#if NETFRAMEWORK - length = await Task.Factory.FromAsync(socket.BeginSend, socket.EndSend, bufs, SocketFlags.None, null); -#else - length = await socket.SendAsync(bufs, SocketFlags.None); -#endif - } - finally - { - for (int i = 0; i < srcs.Length; i++) - { - var dbf = srcs[i]; - var buf = bufs[i]; - - // return temporary buffer - if (dbf is DirectBuffer dir) - ArrayPool.Shared.Return(buf.Array); - } - } - - // advance buffers by amount sent - var l = length; - for (int i = 0; i < srcs.Length; i++) - { - var dbf = srcs[i]; - int pos = dbf.position(); - int lim = dbf.limit(); - int rem = pos <= lim ? lim - pos : 0; - var len = System.Math.Min(l, rem); - - dbf.position(pos + len); - l -= len; - } - - // return total number of bytes written - return gatheringWrite ? Long.valueOf(length) : Integer.valueOf(length); - } - } - finally - { - socket.Blocking = previousBlocking; - socket.SendTimeout = previousSendTimeout; - } - } - } - catch (System.Net.Sockets.SocketException e) when (e.SocketErrorCode == SocketError.TimedOut) - { - DotNetAsynchronousSocketChannelImplAccessor.InvokeEnableWriting(self, true); - throw new global::java.nio.channels.InterruptedByTimeoutException(); - } - catch (System.Net.Sockets.SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new AsynchronousCloseException(); - } - catch (System.Exception e) - { - throw new global::java.io.IOException(e); - } - finally - { - self.enableWriting(); - } - } - - } - -#endif - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/FileDispatcherImpl.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/FileDispatcherImpl.cs deleted file mode 100644 index db5316eb8e..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/FileDispatcherImpl.cs +++ /dev/null @@ -1,466 +0,0 @@ -using System; -using System.Buffers; -using System.IO; -using System.Runtime.InteropServices; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.JNI; - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Implements the native methods for . - /// - static partial class FileDispatcherImpl - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - - static global::ikvm.@internal.CallerID __callerID; - delegate int __jniDelegate__read0(IntPtr jniEnv, IntPtr clazz, IntPtr fdo, long address, int len); - static __jniDelegate__read0 __jniPtr__read0; - delegate int __jniDelegate__pread0(IntPtr jniEnv, IntPtr clazz, IntPtr fdo, long address, int len, long position); - static __jniDelegate__pread0 __jniPtr__pread0; - delegate long __jniDelegate__readv0(IntPtr jniEnv, IntPtr clazz, IntPtr fdo, long address, int len); - static __jniDelegate__readv0 __jniPtr__readv0; - delegate long __jniDelegate__size0(IntPtr jniEnv, IntPtr clazz, IntPtr fdo); - static __jniDelegate__size0 __jniPtr__size0; - -#endif - - [StructLayout(LayoutKind.Sequential)] - struct iovec - { - - public IntPtr iov_base; - public int iov_len; - - } - - /// - /// Implements the native method 'read0'. - /// - /// - /// - /// - /// - /// - public static unsafe int read0(object fdo, long address, int len) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (FileDescriptorAccessor.GetObj(fdo) is not null and not FileStream) - { - if (len == 0) - return 0; - - var stream = FileDescriptorAccessor.GetStream(fdo); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - - if (stream.CanRead == false) - return global::sun.nio.ch.IOStatus.UNSUPPORTED; - - try - { - int r = -1; - -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(len); - - try - { - r = stream.Read(buf, 0, len); - Marshal.Copy(buf, 0, (IntPtr)address, r); - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - r = stream.Read(new Span((byte*)(IntPtr)address, len)); -#endif - - return r == 0 ? global::sun.nio.ch.IOStatus.EOF : r; - } - catch (EndOfStreamException) - { - return global::sun.nio.ch.IOStatus.EOF; - } - catch (NotSupportedException) - { - return global::sun.nio.ch.IOStatus.UNSUPPORTED; - } - catch (ObjectDisposedException) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (Exception e) - { - throw new global::java.io.IOException("Read failed.", e); - } - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::sun.nio.ch.FileDispatcherImpl).TypeHandle); ; - __jniPtr__read0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__read0>(JNIFrame.GetFuncPtr(__callerID, "sun/nio/ch/FileDispatcherImpl", nameof(read0), "(Ljava/io/FileDescriptor;JI)I")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - return __jniPtr__read0(jniEnv, jniFrm.MakeLocalRef(ClassLiteral.Value), jniFrm.MakeLocalRef(fdo), address, len); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method 'pread0'. - /// - /// - /// - /// - /// - /// - /// - public static unsafe int pread0(object fdo, long address, int len, long position) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (FileDescriptorAccessor.GetObj(fdo) is not null and not FileStream) - { - if (len == 0) - return 0; - - var stream = FileDescriptorAccessor.GetStream(fdo); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - - if (stream.CanRead == false) - return global::sun.nio.ch.IOStatus.UNSUPPORTED; - if (stream.CanSeek == false) - return global::sun.nio.ch.IOStatus.UNSUPPORTED; - - var p = stream.Position; - - try - { - stream.Seek(position, SeekOrigin.Begin); - } - catch (EndOfStreamException) - { - return global::sun.nio.ch.IOStatus.EOF; - } - catch (NotSupportedException) - { - return global::sun.nio.ch.IOStatus.UNSUPPORTED; - } - catch (ObjectDisposedException) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (Exception e) - { - throw new global::java.io.IOException("Seek failed.", e); - } - - try - { - int length = -1; - -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(len); - - try - { - length = stream.Read(buf, 0, len); - Marshal.Copy(buf, 0, (IntPtr)address, length); - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - length = stream.Read(new Span((void*)(IntPtr)address, len)); -#endif - - stream.Seek(p, SeekOrigin.Begin); - return length == 0 ? global::sun.nio.ch.IOStatus.EOF : length; - } - catch (EndOfStreamException) - { - return global::sun.nio.ch.IOStatus.EOF; - } - catch (NotSupportedException) - { - return global::sun.nio.ch.IOStatus.UNSUPPORTED; - } - catch (ObjectDisposedException) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (Exception e) - { - throw new global::java.io.IOException("Read failed.", e); - } - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::sun.nio.ch.FileDispatcherImpl).TypeHandle); ; - __jniPtr__pread0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__pread0>(JNIFrame.GetFuncPtr(__callerID, "sun/nio/ch/FileDispatcherImpl", nameof(pread0), "(Ljava/io/FileDescriptor;JIJ)I")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - return __jniPtr__pread0(jniEnv, jniFrm.MakeLocalRef(ClassLiteral.Value), jniFrm.MakeLocalRef(fdo), address, len, position); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method 'readv0'. - /// - /// - /// - /// - /// - public static unsafe long readv0(object fdo, long address, int len) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (FileDescriptorAccessor.GetObj(fdo) is not null and not FileStream) - { - var stream = FileDescriptorAccessor.GetStream(fdo); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - - if (stream.CanRead == false) - return global::sun.nio.ch.IOStatus.UNSUPPORTED; - - try - { - // map io vecors to read into - var vecs = new ReadOnlySpan((byte*)(IntPtr)address, len); - var length = 0; - - // issue independent reads for each vector - for (int i = 0; i < vecs.Length; i++) - { - int l; - -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(vecs[i].iov_len); - - try - { - l = stream.Read(buf, 0, vecs[i].iov_len); - Marshal.Copy(buf, 0, vecs[i].iov_base, l); - length += l; - - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - l = stream.Read(new Span((byte*)vecs[i].iov_base, vecs[i].iov_len)); - length += l; -#endif - - // we failed to read up to the requested amount, so we must be at the end - if (l < vecs[i].iov_len) - break; - } - - // if we read a total of zero bytes, we must be at the end of the file - return length == 0 ? global::sun.nio.ch.IOStatus.EOF : length; - } - catch (EndOfStreamException) - { - return global::sun.nio.ch.IOStatus.EOF; - } - catch (NotSupportedException) - { - return global::sun.nio.ch.IOStatus.UNSUPPORTED; - } - catch (ObjectDisposedException) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (Exception e) - { - throw new global::java.io.IOException("Read failed.", e); - } - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::sun.nio.ch.FileDispatcherImpl).TypeHandle); ; - __jniPtr__readv0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__readv0>(JNIFrame.GetFuncPtr(__callerID, "sun/nio/ch/FileDispatcherImpl", nameof(readv0), "(Ljava/io/FileDescriptor;JI)J")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - return __jniPtr__readv0(jniEnv, jniFrm.MakeLocalRef(ClassLiteral.Value), jniFrm.MakeLocalRef(fdo), address, len); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method 'size'. - /// - /// - /// - public static long size0(object fdo) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (FileDescriptorAccessor.GetObj(fdo) is not null and not FileStream) - { - var stream = FileDescriptorAccessor.GetStream(fdo); - if (stream == null) - throw new global::java.io.IOException("Stream closed."); - - try - { - return stream.Length; - } - catch (EndOfStreamException) - { - return global::sun.nio.ch.IOStatus.EOF; - } - catch (NotSupportedException) - { - return global::sun.nio.ch.IOStatus.UNSUPPORTED; - } - catch (ObjectDisposedException) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (Exception e) - { - throw new global::java.io.IOException("Size failed.", e); - } - } - else - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::sun.nio.ch.FileDispatcherImpl).TypeHandle); ; - __jniPtr__size0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__size0>(JNIFrame.GetFuncPtr(__callerID, "sun/nio/ch/FileDispatcherImpl", nameof(size0), "(Ljava/io/FileDescriptor;)J")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - return __jniPtr__size0(jniEnv, jniFrm.MakeLocalRef(ClassLiteral.Value), jniFrm.MakeLocalRef(fdo)); - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } -#endif - } - - /// - /// Implements the native method 'close'. - /// - /// - public static void close0(object fdo) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (fdo == null) - return; - - try - { - var h = FileDescriptorAccessor.GetHandle(fdo); - FileDescriptorAccessor.SetHandle(fdo, -1); - LibIkvm.Instance.io_close_file(h); - } - catch - { - // ignore - } -#endif - } - - /// - /// Implements the native method 'transferToDirectlyNeedsPositionLock0'. - /// - /// - public static bool transferToDirectlyNeedsPositionLock0() - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return RuntimeUtil.IsWindows; -#endif - } - - /// - /// Implements the native method 'duplicateForMapping'. - /// - /// - /// - /// - public static object duplicateForMapping(object self, object fdo) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var newfd = FileDescriptorAccessor.Init(); - return newfd; -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/IOUtil.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/IOUtil.cs deleted file mode 100644 index fd0590f01a..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/IOUtil.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System; -using System.Net.Sockets; -using System.Security.Cryptography; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Implements the external methods for . - /// - static class IOUtil - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - -#endif - - static readonly RandomNumberGenerator rng = RandomNumberGenerator.Create(); - - ///// - ///// Implements the native method 'initIDs'. - ///// - //public static void initIDs() - //{ - - //} - - /// - /// Implements the native method 'randomBytes'. - /// - public static bool randomBytes(byte[] someBytes) - { - rng.GetBytes(someBytes); - return true; - } - - /// - /// Implements the native method 'makePipe'. - /// - public static long makePipe(bool blocking) - { - throw new NotImplementedException(); - } - - /// - /// Implements the native method 'drain'. - /// - public static bool drain(int fd) - { - throw new NotSupportedException(); - } - - /// - /// Implements the native method 'configureBlocking'. - /// - public static void configureBlocking(object fd, bool blocking) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.io.IOException("Socket closed."); - - try - { - // defer operation if outstanding task - // .NET socket fails to set blocking if outstanding Connect - var task = FileDescriptorAccessor.GetTask(fd); - if (task != null) - FileDescriptorAccessor.SetTask(fd, task.ContinueWith(_ => socket.Blocking = blocking)); - else - socket.Blocking = blocking; - } - catch (SocketException e) - { - throw new global::java.net.SocketException(e.Message); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - /// - /// Implements the native method 'fdVal'. - /// - public static int fdVal(object fd) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return FileDescriptorAccessor.GetFd(fd); -#endif - } - - /// - /// Implements the native method 'setfdVal'. - /// - public static void setfdVal(global::java.io.FileDescriptor fd, int value) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - FileDescriptorAccessor.SetFd(fd, value); -#endif - } - - /// - /// Implements the native method 'fdLimit'. - /// - public static int fdLimit() - { - throw new NotSupportedException(); - } - - ///// - ///// Implements the native method 'iovMax'. - ///// - //public static int iovMax() - //{ - // return 16; - //} - - ///// - ///// Implements the native method 'load'. - ///// - //public static void load() - //{ - - //} - - } - -} \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/Net.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/Net.cs deleted file mode 100644 index 11557d31e6..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/Net.cs +++ /dev/null @@ -1,582 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Runtime.InteropServices; -using System.Threading.Tasks; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.Util.Java.Net; - -using static IKVM.Java.Externs.java.net.SocketImplUtil; - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Implements the external methods for . - /// - static class Net - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - - [StructLayout(LayoutKind.Explicit)] - unsafe struct sockaddr_storage - { - - [FieldOffset(0)] - void* __ss_align; - - [FieldOffset(0)] - fixed byte __ss_size[128]; - - [FieldOffset(0)] - ushort __ss_family; - - public ushort ss_family { get => __ss_family; set => __ss_family = value; } - - } - - [StructLayout(LayoutKind.Explicit)] - public unsafe struct in_addr - { - - [FieldOffset(0)] - uint __align; - - [FieldOffset(0)] - public fixed byte s_addr[4]; - - } - - [StructLayout(LayoutKind.Sequential)] - unsafe struct sockaddr_in - { - - public ushort sin_family; - - public ushort sin_port; - - public in_addr sin_addr; - - fixed byte __sin_zero[8]; - - } - - [StructLayout(LayoutKind.Explicit)] - unsafe struct in6_addr - { - - [FieldOffset(0)] - uint __align; - - [FieldOffset(0)] - public fixed byte s6_addr[16]; - - } - - [StructLayout(LayoutKind.Sequential)] - struct sockaddr_in6 - { - - public ushort sin6_family; - - public ushort sin6_port; - - public uint sin6_flowinfo; - - public in6_addr sin6_addr; - - public uint sin6_scope_id; - - } - - [StructLayout(LayoutKind.Sequential)] - struct ip_mreq_source - { - - public in_addr imr_multiaddr; - public in_addr imr_sourceaddr; - public in_addr imr_interface; - - } - - [StructLayout(LayoutKind.Sequential)] - struct group_source_req - { - - public uint gsr_interface; - public sockaddr_storage gsr_group; - public sockaddr_storage gsr_source; - - } - - static readonly ushort AF_UNSPEC; - static readonly ushort AF_INET; - static readonly ushort AF_INET6; - - static readonly int IPPROTO_IP; - static readonly int IPPROTO_IPV6; - static readonly int IP_ADD_SOURCE_MEMBERSHIP; - static readonly int IP_DROP_SOURCE_MEMBERSHIP; - static readonly int MCAST_BLOCK_SOURCE; - static readonly int MCAST_UNBLOCK_SOURCE; - static readonly int MCAST_JOIN_SOURCE_GROUP; - static readonly int MCAST_LEAVE_SOURCE_GROUP; - - /// - /// Invokes the 'setsockopt' Posix function. - /// - /// - /// - /// - /// - /// - /// - [DllImport("libc", SetLastError = true)] - static unsafe extern int setsockopt(SafeHandle sockfd, int level, int optname, void* optval, int optlen); - - /// - /// Invokes the 'getsockopt' Posix function. - /// - /// - /// - /// - /// - /// - /// - [DllImport("libc", SetLastError = true)] - static unsafe extern int getsockopt(SafeHandle sockfd, int level, int optname, void* optval, int* optlen); - - /// - /// Initializes the static instance. - /// - static Net() - { - if (RuntimeUtil.IsWindows) - { - AF_UNSPEC = 0; - AF_INET = 2; - AF_INET6 = 23; - IPPROTO_IP = 0; - IPPROTO_IPV6 = 41; - IP_ADD_SOURCE_MEMBERSHIP = 39; - IP_DROP_SOURCE_MEMBERSHIP = 40; - MCAST_BLOCK_SOURCE = 43; - MCAST_UNBLOCK_SOURCE = 44; - MCAST_JOIN_SOURCE_GROUP = 45; - MCAST_LEAVE_SOURCE_GROUP = 46; - } - else if (RuntimeUtil.IsLinux) - { - AF_UNSPEC = 0; - AF_INET = 2; - AF_INET6 = 10; - IPPROTO_IP = 0; - IPPROTO_IPV6 = 41; - IP_ADD_SOURCE_MEMBERSHIP = 39; - IP_DROP_SOURCE_MEMBERSHIP = 40; - MCAST_BLOCK_SOURCE = 43; - MCAST_UNBLOCK_SOURCE = 44; - MCAST_JOIN_SOURCE_GROUP = 46; - MCAST_LEAVE_SOURCE_GROUP = 47; - } - else if (RuntimeUtil.IsOSX) - { - AF_UNSPEC = 0; - AF_INET = 2; - AF_INET6 = 30; - IPPROTO_IP = 0; - IPPROTO_IPV6 = 41; - IP_ADD_SOURCE_MEMBERSHIP = 70; - IP_DROP_SOURCE_MEMBERSHIP = 71; - MCAST_BLOCK_SOURCE = 84; - MCAST_UNBLOCK_SOURCE = 85; - MCAST_JOIN_SOURCE_GROUP = 82; - MCAST_LEAVE_SOURCE_GROUP = 83; - } - else - { - throw new PlatformNotSupportedException(); - } - } - -#endif - - /// - /// Implements the native method for 'bind0'. - /// - /// - /// - /// - /// - /// - /// - public static void bind0(global::java.io.FileDescriptor fd, bool preferIPv6, bool useExclBind, global::java.net.InetAddress addr, int port) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(() => - { - InvokeWithSocket(fd, socket => - { - if (useExclBind && (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress) != 1) - socket.ExclusiveAddressUse = true; - - socket.Bind(new IPEndPoint(addr.ToIPAddress(), port)); - }); - }); -#endif - } - - /// - /// Implements the native method for 'listen'. - /// - /// - /// - /// - public static void listen(object fd, int backlog) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(() => - { - InvokeWithSocket(fd, socket => - { - socket.Listen(backlog); - }); - }); -#endif - } - - /// - /// Implements the native method for 'connect0'. - /// - /// - /// - /// - /// - /// - public static int connect0(bool preferIPv6, object fd, global::java.net.InetAddress remote, int remotePort) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(() => - { - return InvokeWithSocket(fd, socket => - { - var ep = new IPEndPoint(remote.ToIPAddress(), remotePort); - var datagram = socket.SocketType == SocketType.Dgram; - if (datagram || socket.Blocking) - { - socket.Connect(ep); - if (datagram) - SetConnectionReset(socket, true); - - return 1; - } - else - { - var task = FileDescriptorAccessor.GetTask(fd); - if (task != null) - throw new global::java.net.SocketException("Outstanding async request."); - - task = Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, ep, null); - FileDescriptorAccessor.SetTask(fd, task); - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - }); - }); -#endif - } - - /// - /// Implements the native method for 'shutdown'. - /// - /// - /// - public static void shutdown(object fd, int how) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(() => - { - InvokeWithSocket(fd, socket => - { - socket.Shutdown((SocketShutdown)how); - }); - }); -#endif - } - - /// - /// Implements the native method for 'localInetAddress'. - /// - /// - /// - public static int localPort(object fd) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(() => - { - return InvokeWithSocket(fd, socket => - { - return ((IPEndPoint)socket.LocalEndPoint).Port; - }); - }); -#endif - } - - /// - /// Implements the native method for 'localInetAddress'. - /// - /// - /// - public static global::java.net.InetAddress localInetAddress(object fd) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(() => - { - return InvokeWithSocket(fd, socket => - { - return ((IPEndPoint)socket.LocalEndPoint).ToInetAddress(); - }); - }); -#endif - } - - /// - /// - /// Implements the native method for 'remotePort'. - /// - /// - /// - public static int remotePort(object fd) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(() => - { - return InvokeWithSocket(fd, socket => - { - return ((IPEndPoint)socket.RemoteEndPoint).Port; - }); - }); -#endif - } - - /// - /// Implements the native method for 'remoteInetAddress'. - /// - /// - /// - public static global::java.net.InetAddress remoteInetAddress(object fd) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(() => - { - return InvokeWithSocket(fd, socket => - { - return ((IPEndPoint)socket.RemoteEndPoint).ToInetAddress(); - }); - }); -#endif - } - - /// - /// Implements the native method for 'setIntOption0'. - /// - /// - /// - /// - /// - /// - public static int getIntOption0(object fd, bool mayNeedConversion, int level, int opt) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(() => - { - return InvokeWithSocket(fd, socket => - { - var sol = (SocketOptionLevel)level; - var son = (SocketOptionName)opt; - - if (sol == SocketOptionLevel.IPv6 && opt == 39) - return 0; - - try - { - object obj = socket.GetSocketOption(sol, son); - return obj is LingerOption linger ? linger.Enabled ? linger.LingerTime : -1 : (int)obj; - } - catch (SocketException e) when (mayNeedConversion && e.SocketErrorCode == SocketError.ProtocolOption && sol == SocketOptionLevel.IP && son == SocketOptionName.TypeOfService) - { - return 0; - } - }); - }); -#endif - } - - /// - /// Implements the native method for 'setIntOption0'. - /// - /// - /// - /// - /// - /// - /// - /// - public static void setIntOption0(object fd, bool mayNeedConversion, int level, int opt, int arg, bool isIPv6) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - InvokeAction(() => - { - InvokeWithSocket(fd, socket => - { - var sol = (SocketOptionLevel)level; - var son = (SocketOptionName)opt; - - if (sol == SocketOptionLevel.IPv6 && opt == 39) - return; - - if (mayNeedConversion) - { - const int IPTOS_TOS_MASK = 0x1e; - const int IPTOS_PREC_MASK = 0xe0; - if (sol == SocketOptionLevel.IP && son == SocketOptionName.TypeOfService) - arg &= IPTOS_TOS_MASK | IPTOS_PREC_MASK; - } - - try - { - socket.SetSocketOption(sol, son, arg); - } - catch (SocketException e) when (mayNeedConversion && e.SocketErrorCode == SocketError.ProtocolOption && sol == SocketOptionLevel.IP && (son == SocketOptionName.TypeOfService || son == SocketOptionName.MulticastLoopback)) - { - return; - } - catch (SocketException e) when (mayNeedConversion && e.SocketErrorCode == SocketError.InvalidArgument && sol == SocketOptionLevel.IP && son == SocketOptionName.TypeOfService) - { - return; - } - }); - }); -#endif - } - - /// - /// Implements the native method for 'poll'. - /// - /// - /// - /// - /// - /// - public static int poll(object fd, int events, long timeout) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return InvokeFunc(() => - { - return InvokeWithSocket(fd, socket => - { - var selectMode = events switch - { - int e when e == global::sun.nio.ch.Net.POLLCONN => SelectMode.SelectWrite, - int e when e == global::sun.nio.ch.Net.POLLOUT => SelectMode.SelectWrite, - int e when e == global::sun.nio.ch.Net.POLLIN => SelectMode.SelectRead, - _ => throw new NotSupportedException(), - }; - - if (socket.Poll((int)Math.Min(timeout * 1000L, int.MaxValue), selectMode)) - return events; - - return 0; - }); - }); -#endif - } - - /// - /// Windows 2000 introduced a "feature" that causes it to return WSAECONNRESET from receive, - /// if a previous send resulted in an ICMP port unreachable. For unconnected datagram sockets, - /// we disable this feature by using this ioctl. - /// - /// - /// - internal static void SetConnectionReset(Socket socket, bool enable) - { - if (RuntimeUtil.IsWindows) - { - const int IOC_IN = unchecked((int)0x80000000); - const int IOC_VENDOR = 0x18000000; - const int SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; - socket.IOControl(SIO_UDP_CONNRESET, new byte[] { enable ? (byte)1 : (byte)0 }, null); - } - } - -#if !FIRST_PASS - - /// - /// Invokes the given action with the current socket, catching and mapping any resulting .NET exceptions. - /// - /// - /// - /// - /// - /// - /// - static void InvokeWithSocket(object fd, Action action) - { - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - action(socket); - } - - /// - /// Invokes the given function with the current socket, catching and mapping any resulting .NET exceptions. - /// - /// - /// - /// - /// - /// - /// - static TResult InvokeWithSocket(object fd, Func func) - { - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - return func(socket); - } - -#endif - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/NotLockedHack.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/NotLockedHack.cs deleted file mode 100644 index e454e27546..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/NotLockedHack.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.IO; - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Attempts to lock an unlocked file to capture teh error message, since IOException provides no way to know - /// whether the reason corresponds to not being locked. - /// - static class NotLockedHack - { - - static readonly string message; - - /// - /// Initializes the static instance. - /// - static NotLockedHack() - { - try - { - var tmp = Path.GetTempFileName(); - - using (var fs = new FileStream(tmp, FileMode.Create)) - { - try - { - fs.Unlock(0, 1); - } - catch (System.IO.IOException e) - { - message = e.Message; - } - } - - File.Delete(tmp); - } - catch (Exception) - { - - } - } - - /// - /// Returns true if the exception represents the file not being locked. - /// - /// - /// - public static bool IsErrorNotLocked(IOException e) - { - return e.Message == message; - } - - } - -} \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/ServerSocketChannelImpl.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/ServerSocketChannelImpl.cs deleted file mode 100644 index 35e880db95..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/ServerSocketChannelImpl.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Net.Sockets; -using System.Runtime.InteropServices; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.Util.Java.Net; - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Implements the native methods for 'ServerSocketChannelImpl'. - /// - static class ServerSocketChannelImpl - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - -#endif - - [Flags] - enum HANDLE_FLAGS - { - - NONE = 0, - INHERIT = 0x00000001, - PROTECT_FROM_CLOSE = 0x00000002, - - } - -#if NETFRAMEWORK - - /// - /// Invokes the Win32 SetHandleInformation function. - /// - /// - /// - /// - /// - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool SetHandleInformation(IntPtr hObject, HANDLE_FLAGS dwMask, HANDLE_FLAGS dwFlags); -#else - - /// - /// Invokes the Win32 SetHandleInformation function. - /// - /// - /// - /// - /// - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool SetHandleInformation(SafeHandle hObject, HANDLE_FLAGS dwMask, HANDLE_FLAGS dwFlags); - -#endif - - - /// - /// Implements the native method 'accept0'. - /// - /// - /// - /// - /// - /// - /// - public static int accept0(object self, object ssfd, object newfd, object isaa) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - var socket = FileDescriptorAccessor.GetSocket(ssfd); - if (socket == null) - throw new global::java.io.IOException("Socket closed."); - - try - { - if (socket.Blocking || socket.Poll(0, SelectMode.SelectRead)) - { - var newSocket = socket.Accept(); - if (newSocket == null) - throw new global::java.net.SocketException("Invalid socket."); - - FileDescriptorAccessor.SetSocket(newfd, newSocket); - var ep = (System.Net.IPEndPoint)newSocket.RemoteEndPoint; - ((object[])isaa)[0] = ep.ToInetSocketAddress(); - return 1; - } - else - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - /// - /// Implements the native method 'initIDs'. - /// - public static void initIDs() - { - - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/SocketChannelImpl.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/SocketChannelImpl.cs deleted file mode 100644 index 55cd574ac5..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/SocketChannelImpl.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Buffers; -using System.Net.Sockets; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.Util.Java.Net; - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Implements the native methods for 'SocketChannelImpl'. - /// - static class SocketChannelImpl - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - -#endif - - /// - /// Implements the native method 'checkConnect'. - /// - /// - /// - /// - /// - public static int checkConnect(object fd, bool block, bool ready) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.io.IOException("Socket closed."); - - try - { - var task = FileDescriptorAccessor.GetTask(fd); - if (block || ready || task.IsCompleted) - { - FileDescriptorAccessor.SetTask(fd, null); - task.GetAwaiter().GetResult(); - return 1; - } - else - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - } - catch (SocketException e) - { - throw new global::java.net.ConnectException(e.Message); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - /// - /// Implements the native method 'sendOutOfBandData'. - /// - /// - /// - /// - public static int sendOutOfBandData(object fd, byte data) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.io.IOException("Socket closed."); - - try - { -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(1); - - try - { - buf[0] = data; - return socket.Send(buf, 1, SocketFlags.OutOfBand); - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - unsafe - { - var buf = (Span)stackalloc byte[1]; - buf[0] = data; - return socket.Send(buf, SocketFlags.OutOfBand); - } -#endif - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - if (RuntimeUtil.IsWindows) - throw new global::java.net.SocketException("Resource temporarily unavailable"); - else if (RuntimeUtil.IsOSX) - throw new global::java.net.SocketException("No buffer space available"); - else - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/SocketDispatcher.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/ch/SocketDispatcher.cs deleted file mode 100644 index 0cc0fbb895..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/ch/SocketDispatcher.cs +++ /dev/null @@ -1,358 +0,0 @@ -using System; -using System.Buffers; -using System.Net.Sockets; -using System.Runtime.InteropServices; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.Util.Java.Net; - -namespace IKVM.Java.Externs.sun.nio.ch -{ - - /// - /// Implements the native methods for 'SocketDispatcher'. - /// - static class SocketDispatcher - { - -#if FIRST_PASS == false - - static FileDescriptorAccessor fileDescriptorAccessor; - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - -#endif - - [StructLayout(LayoutKind.Sequential)] - struct iovec - { - - public IntPtr iov_base; - public int iov_len; - - } - - /// - /// Implements the native method 'read'. - /// - /// - /// - /// - /// - /// - public static unsafe int read(object self, object fd, long address, int len) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (len == 0) - return 0; - - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - try - { -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(len); - - try - { - var n = socket.Receive(buf, 0, len, SocketFlags.None); - if (n == 0) - return global::sun.nio.ch.IOStatus.EOF; - - Marshal.Copy(buf, 0, (IntPtr)address, n); - return n; - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - var n = socket.Receive(new Span((byte*)(IntPtr)address, len)); - if (n == 0) - return global::sun.nio.ch.IOStatus.EOF; - - return n; -#endif - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.Shutdown) - { - return global::sun.nio.ch.IOStatus.EOF; - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - /// - /// Implements the native method 'readv'. - /// - /// - /// - /// - /// - /// - public static unsafe long readv(object self, object fd, long address, int len) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - if (len == 0) - return 0; - - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - try - { - // allocate list of array segments to hold received data - var vecs = new Span((byte*)(IntPtr)address, len); - var bufs = new ArraySegment[vecs.Length]; - - try - { - // prepare array segments for buffers - for (int i = 0; i < vecs.Length; i++) - bufs[i] = new ArraySegment(ArrayPool.Shared.Rent(vecs[i].iov_len), 0, vecs[i].iov_len); - - // receive into segments - var length = socket.Receive(bufs); - - // copy segments back into vectors - var l = length; - for (int i = 0; i < vecs.Length; i++) - { - var szz = Math.Min(l, vecs[i].iov_len); - Marshal.Copy(bufs[i].Array, 0, vecs[i].iov_base, szz); - l -= szz; - } - - // we should have accounted for all of the bytes - if (l != 0) - throw new global::java.lang.RuntimeException("Bytes remaining after read."); - - return length; - } - finally - { - for (int i = 0; i < bufs.Length; i++) - ArrayPool.Shared.Return(bufs[i].Array); - } - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.Shutdown) - { - return global::sun.nio.ch.IOStatus.EOF; - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - /// - /// Implements the native method 'write'. - /// - /// - /// - /// - /// - /// - public static unsafe int write(object self, object fd, long address, int len) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - try - { -#if NETFRAMEWORK - var buf = ArrayPool.Shared.Rent(len); - - try - { - Marshal.Copy((IntPtr)address, buf, 0, len); - return socket.Send(buf, 0, len, SocketFlags.None); - } - finally - { - ArrayPool.Shared.Return(buf); - } -#else - return socket.Send(new ReadOnlySpan((byte*)(IntPtr)address, len)); -#endif - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - /// - /// Implements the native method 'writev'. - /// - /// - /// - /// - /// - /// - public static unsafe long writev(object self, object fd, long address, int len) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - throw new global::java.net.SocketException("Socket closed."); - - try - { - // allocate list of array segments to hold incoming buffers - var vecs = new ReadOnlySpan((void*)(IntPtr)address, len); - var bufs = new ArraySegment[vecs.Length]; - - try - { - // copy incoming buffers into segments - for (int i = 0; i < vecs.Length; i++) - { - bufs[i] = new ArraySegment(ArrayPool.Shared.Rent(vecs[i].iov_len), 0, vecs[i].iov_len); - Marshal.Copy(vecs[i].iov_base, bufs[i].Array, bufs[i].Offset, vecs[i].iov_len); - } - - // send segments - return socket.Send(bufs); - } - finally - { - // return allocated arrays - for (int i = 0; i < bufs.Length; i++) - if (bufs[i].Array != null) - ArrayPool.Shared.Return(bufs[i].Array); - } - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.WouldBlock) - { - return global::sun.nio.ch.IOStatus.UNAVAILABLE; - } - catch (SocketException e) - { - throw e.ToIOException(); - } - catch (ObjectDisposedException) - { - throw new global::java.net.SocketException("Socket closed."); - } - catch (Exception e) - { - throw new global::java.io.IOException(e); - } -#endif - } - - /// - /// Implements the native method 'preClose'. - /// - /// - /// - public static void preClose(object self, object fd) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - var socket = FileDescriptorAccessor.GetSocket(fd); - if (socket == null) - return; - - try - { - if (socket.LingerState.Enabled == false) - if (socket.Connected) - socket.Shutdown(SocketShutdown.Send); - } - catch (ObjectDisposedException) - { - return; - } - catch (SocketException) - { - // ignore - } -#endif - } - - /// - /// Implements the native method 'close'. - /// - /// - /// - public static void close(object self, object fd) - { -#if FIRST_PASS - throw new NotSupportedException(); -#else - if (fd == null) - return; - - try - { - var h = FileDescriptorAccessor.GetHandle(fd); - FileDescriptorAccessor.SetHandle(fd, -1); - LibIkvm.Instance.io_close_socket(h); - } - catch - { - // ignore - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetBasicFileAttributeView.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetBasicFileAttributeView.cs deleted file mode 100644 index 91219a56de..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetBasicFileAttributeView.cs +++ /dev/null @@ -1,130 +0,0 @@ -using System; -using System.IO; -using System.Security; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Lang; -using IKVM.Runtime.Accessors.Sun.Nio.Ch; -using IKVM.Runtime.Vfs; - -namespace IKVM.Java.Externs.sun.nio.fs -{ - - /// - /// Implements the native methods for 'DotNetBasicFileAttributeView'. - /// - static class DotNetBasicFileAttributeView - { - -#if FIRST_PASS == false - - static SystemAccessor systemAccessor; - static SecurityManagerAccessor securityManagerAccessor; - static FileTimeAccessor fileTimeAccessor; - static DotNetBasicFileAttributeViewAccessor dotNetBasicFileAttributeViewAccessor; - - static SystemAccessor SystemAccessor => JVM.Internal.BaseAccessors.Get(ref systemAccessor); - - static SecurityManagerAccessor SecurityManagerAccessor => JVM.Internal.BaseAccessors.Get(ref securityManagerAccessor); - - static FileTimeAccessor FileTimeAccessor => JVM.Internal.BaseAccessors.Get(ref fileTimeAccessor); - - static DotNetBasicFileAttributeViewAccessor DotNetBasicFileAttributeViewAccessor => JVM.Internal.BaseAccessors.Get(ref dotNetBasicFileAttributeViewAccessor); - -#endif - - /// - /// Converts the given to a . - /// - /// - /// - static DateTime? ToDateTime(object fileTime) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else -#if NETFRAMEWORK - var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); -#else - var epoch = DateTime.UnixEpoch; -#endif - return fileTime != null ? epoch + TimeSpan.FromMilliseconds(FileTimeAccessor.InvokeToMillis(fileTime)) : null; -#endif - } - - /// - /// Implements the native method 'setTimes'. - /// - /// - /// - /// - /// - /// - /// - public static void setTimes(object self, object lastModifiedTime, object lastAccessTime, object createdTime) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var path = DotNetBasicFileAttributeViewAccessor.GetPath(self); - if (path == null) - throw new global::java.lang.NullPointerException(); - - var sm = SystemAccessor.InvokeGetSecurityManager(); - if (sm != null) - SecurityManagerAccessor.InvokeCheckWrite(sm, path); - - if (JVM.Vfs.IsPath(path)) - throw new global::java.io.IOException("Cannot modify VFS entries."); - - try - { - if (File.Exists(path)) - { - if (lastModifiedTime != null) - File.SetLastWriteTimeUtc(path, (DateTime)ToDateTime(lastModifiedTime)); - if (lastAccessTime != null) - File.SetLastAccessTimeUtc(path, (DateTime)ToDateTime(lastAccessTime)); - if (createdTime != null) - File.SetCreationTimeUtc(path, (DateTime)ToDateTime(createdTime)); - } - else if (Directory.Exists(path)) - { - if (lastModifiedTime != null) - Directory.SetLastWriteTimeUtc(path, (DateTime)ToDateTime(lastModifiedTime)); - if (lastAccessTime != null) - Directory.SetLastAccessTimeUtc(path, (DateTime)ToDateTime(lastAccessTime)); - if (createdTime != null) - Directory.SetCreationTimeUtc(path, (DateTime)ToDateTime(createdTime)); - } - else - { - throw new global::java.nio.file.NoSuchFileException(path); - } - } - catch (ArgumentException e) - { - throw new global::java.io.IOException(e.Message); - } - catch (IOException e) - { - throw new global::java.io.IOException(e.Message); - } - catch (NotSupportedException e) - { - throw new global::java.io.IOException(e.Message); - } - catch (SecurityException e) - { - throw new global::java.io.IOException(e.Message); - } - catch (UnauthorizedAccessException e) - { - throw new global::java.io.IOException(e.Message); - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetDirectoryStream.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetDirectoryStream.cs deleted file mode 100644 index d9769acb13..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetDirectoryStream.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.IO; -using System.Linq; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Ikvm.Util; -using IKVM.Runtime.Accessors.Java.Nio.File; -using IKVM.Runtime.Accessors.Sun.Nio.Fs; - -namespace IKVM.Java.Externs.sun.nio.fs -{ - - /// - /// Implements the native methods for 'DotNetDirectoryStream'. - /// - static class DotNetDirectoryStream - { - -#if FIRST_PASS == false - - static EnumeratorIteratorAccessor enumeratorIteratorAccessor; - static DirectoryStreamFilterAccessor directoryStreamFilterAccessor; - static DotNetPathAccessor dotNetPathAccessor; - static DotNetDirectoryStreamAccessor dotNetDirectoryStreamAccessor; - - static EnumeratorIteratorAccessor EnumeratorIteratorAccessor => JVM.Internal.BaseAccessors.Get(ref enumeratorIteratorAccessor); - - static DirectoryStreamFilterAccessor DirectoryStreamFilterAccessor => JVM.Internal.BaseAccessors.Get(ref directoryStreamFilterAccessor); - - static DotNetPathAccessor DotNetPathAccessor => JVM.Internal.BaseAccessors.Get(ref dotNetPathAccessor); - - static DotNetDirectoryStreamAccessor DotNetDirectoryStreamAccessor => JVM.Internal.BaseAccessors.Get(ref dotNetDirectoryStreamAccessor); - -#endif - - /// - /// Implements the native method 'iterator'. - /// - /// - /// - public static object iterator(object self) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var path = DotNetDirectoryStreamAccessor.GetPath(self); - if (path == null) - throw new global::java.lang.NullPointerException(); - - var fileSystem = DotNetPathAccessor.GetFs(path); - if (fileSystem == null) - throw new global::java.lang.NullPointerException(); - - var directoryPath = DotNetPathAccessor.GetPath(path); - if (directoryPath == null) - throw new global::java.lang.NullPointerException(); - - var files = DotNetDirectoryStreamAccessor.GetFiles(self); - if (files == null) - throw new global::java.lang.NullPointerException(); - - var filter = DotNetDirectoryStreamAccessor.GetFilter(self); - if (filter == null) - throw new global::java.lang.NullPointerException(); - - try - { - bool ApplyFilter(object i) - { - try - { - return DirectoryStreamFilterAccessor.InvokeAccept(filter, i); - } - catch (global::java.io.IOException e) - { - throw new global::java.nio.file.DirectoryIteratorException(e); - } - } - - return EnumeratorIteratorAccessor.Init(files.Select(i => DotNetPathAccessor.Init(fileSystem, i)).Where(ApplyFilter).GetEnumerator()); - } - catch (global::java.lang.Throwable) - { - throw; - } - catch (Exception e) when (File.Exists(directoryPath)) - { - throw new global::java.nio.file.NotDirectoryException(directoryPath); - } - catch (Exception e) when (Directory.Exists(directoryPath) == false) - { - throw new global::java.nio.file.NotDirectoryException(directoryPath); - } - catch (Exception e) - { - throw new global::java.io.IOException(e.Message); - } -#endif - } - - /// - /// Implements the native method 'close'. - /// - /// - public static void close(object self) - { - - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetDosFileAttributeView.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetDosFileAttributeView.cs deleted file mode 100644 index 3e432437fb..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetDosFileAttributeView.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.IO; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Lang; -using IKVM.Runtime.Vfs; - -namespace IKVM.Java.Externs.sun.nio.fs -{ - - /// - /// Implements the native methods for 'DotNetDosFileAttributeView'. - /// - static class DotNetDosFileAttributeView - { - -#if FIRST_PASS == false - - static SystemAccessor systemAccessor; - static SecurityManagerAccessor securityManagerAccessor; - - static SystemAccessor SystemAccessor => JVM.Internal.BaseAccessors.Get(ref systemAccessor); - - static SecurityManagerAccessor SecurityManagerAccessor => JVM.Internal.BaseAccessors.Get(ref securityManagerAccessor); - -#endif - - /// - /// Implements the native method 'setAttribute0'. - /// - /// - /// - /// - public static void setAttribute0(string path, int attr, bool value) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var sm = SystemAccessor.InvokeGetSecurityManager(); - if (sm != null) - SecurityManagerAccessor.InvokeCheckWrite(sm, path); - - if (JVM.Vfs.IsPath(path)) - throw new global::java.io.IOException("VFS entries cannot be modified."); - - try - { - var info = new FileInfo(path); - - if (value) - info.Attributes |= (FileAttributes)attr; - else - info.Attributes &= ~(FileAttributes)attr; - } - catch (FileNotFoundException e) - { - throw new global::java.nio.file.NoSuchFileException(path); - } - catch (ArgumentException e) - { - throw new global::java.io.IOException(e.Message); - } - catch (IOException e) - { - throw new global::java.io.IOException(e.Message); - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetDosFileAttributes.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetDosFileAttributes.cs deleted file mode 100644 index 70f8ba83b5..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetDosFileAttributes.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; -using System.Security; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Lang; -using IKVM.Runtime.Accessors.Sun.Nio.Ch; -using IKVM.Runtime.Accessors.Sun.Nio.Fs; -using IKVM.Runtime.Vfs; - -namespace IKVM.Java.Externs.sun.nio.fs -{ - - /// - /// Implements the native methods for 'DotNetDosFileAttributes'. - /// - static class DotNetDosFileAttributes - { - -#if FIRST_PASS == false - - static SystemAccessor systemAccessor; - static SecurityManagerAccessor securityManagerAccessor; - static FileTimeAccessor fileTimeAccessor; - static DotNetDosFileAttributesAccessor dotNetDosFileAttributesAccessor; - static UnixFileKeyAccessor unixFileKeyAccessor; - - static SystemAccessor SystemAccessor => JVM.Internal.BaseAccessors.Get(ref systemAccessor); - - static FileTimeAccessor FileTimeAccessor => JVM.Internal.BaseAccessors.Get(ref fileTimeAccessor); - - static SecurityManagerAccessor SecurityManagerAccessor => JVM.Internal.BaseAccessors.Get(ref securityManagerAccessor); - - static DotNetDosFileAttributesAccessor DotNetDosFileAttributesAccessor => JVM.Internal.BaseAccessors.Get(ref dotNetDosFileAttributesAccessor); - - static UnixFileKeyAccessor UnixFileKeyAccessor => JVM.Internal.BaseAccessors.Get(ref unixFileKeyAccessor); - -#endif - - /// - /// Creates a object from a . - /// - /// - /// - static object ToFileTime(DateTime? dateTime) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else -#if NETFRAMEWORK - var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); -#else - var epoch = DateTime.UnixEpoch; -#endif - return dateTime != null ? FileTimeAccessor.InvokeFromMillis((long)((DateTime)dateTime - epoch).TotalMilliseconds) : null; -#endif - } - - /// - /// Implements the native method 'read'. - /// - /// - /// - /// - /// - public static object read(string path) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - var sm = SystemAccessor.InvokeGetSecurityManager(); - if (sm != null) - SecurityManagerAccessor.InvokeCheckRead(sm, path); - - if (JVM.Vfs.IsPath(path)) - { - var entry = JVM.Vfs.GetEntry(path); - - if (entry is VfsFile vfsFile) - return DotNetDosFileAttributesAccessor.Init( - FileTimeAccessor.InvokeFromMillis(0), - FileTimeAccessor.InvokeFromMillis(0), - FileTimeAccessor.InvokeFromMillis(0), - null, - false, - false, - true, - false, - vfsFile.Size, - true, - false, - false, - false); - - if (entry is VfsDirectory vfsDirectory) - return DotNetDosFileAttributesAccessor.Init( - FileTimeAccessor.InvokeFromMillis(0), - FileTimeAccessor.InvokeFromMillis(0), - FileTimeAccessor.InvokeFromMillis(0), - null, - true, - false, - false, - false, - 0, - false, - false, - false, - false); - - throw new global::java.nio.file.NoSuchFileException(path); - } - - try - { - var fileInfo = new FileInfo(path); - if (fileInfo.Exists) - { - object fileKey = null; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) == false) - if (LibIkvm.Instance.io_lstat(fileInfo.FullName, out var st_ino, out var st_dev) == 0) - fileKey = UnixFileKeyAccessor.Init(st_dev, st_ino); - - return DotNetDosFileAttributesAccessor.Init( - ToFileTime(fileInfo.CreationTimeUtc), - ToFileTime(fileInfo.LastAccessTimeUtc), - ToFileTime(fileInfo.LastWriteTimeUtc), - fileKey, - false, - false, - true, - false, - fileInfo.Length, - fileInfo.IsReadOnly, - (fileInfo.Attributes & FileAttributes.Hidden) != 0, - (fileInfo.Attributes & FileAttributes.Archive) != 0, - (fileInfo.Attributes & FileAttributes.System) != 0); - } - - var directoryInfo = new DirectoryInfo(path); - if (directoryInfo.Exists) - { - object fileKey = null; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) == false) - if (LibIkvm.Instance.io_lstat(fileInfo.FullName, out var st_ino, out var st_dev) == 0) - fileKey = UnixFileKeyAccessor.Init(st_dev, st_ino); - - return DotNetDosFileAttributesAccessor.Init( - ToFileTime(directoryInfo.CreationTimeUtc), - ToFileTime(directoryInfo.LastAccessTimeUtc), - ToFileTime(directoryInfo.LastWriteTimeUtc), - fileKey, - true, - false, - false, - false, - 0, - (directoryInfo.Attributes & FileAttributes.ReadOnly) != 0, - (directoryInfo.Attributes & FileAttributes.Hidden) != 0, - (directoryInfo.Attributes & FileAttributes.Archive) != 0, - (directoryInfo.Attributes & FileAttributes.System) != 0); - } - - throw new global::java.nio.file.NoSuchFileException(path); - } - catch (ArgumentException e) - { - throw new global::java.io.IOException(e.Message); - } - catch (IOException e) - { - throw new global::java.io.IOException(e.Message); - } - catch (NotSupportedException e) - { - throw new global::java.io.IOException(e.Message); - } - catch (SecurityException e) - { - throw new global::java.io.IOException(e.Message); - } - catch (UnauthorizedAccessException e) - { - throw new global::java.io.IOException(e.Message); - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetFileSystemProvider.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetFileSystemProvider.cs deleted file mode 100644 index bd3ad89bf9..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetFileSystemProvider.cs +++ /dev/null @@ -1,400 +0,0 @@ -using System; -using System.Buffers; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Security; -using System.Security.AccessControl; -using System.Text; - -using IKVM.Runtime; -using IKVM.Runtime.Accessors.Java.Io; -using IKVM.Runtime.Accessors.Java.Lang; -using IKVM.Runtime.Accessors.Sun.Nio.Fs; -using IKVM.Runtime.JNI; -using IKVM.Runtime.Vfs; - -using Microsoft.Win32.SafeHandles; - -using Mono.Unix; -using Mono.Unix.Native; - -namespace IKVM.Java.Externs.sun.nio.fs -{ - - /// - /// Implements the native methods for 'DotNetFileSystemProvider'. - /// - static class DotNetFileSystemProvider - { - -#if FIRST_PASS == false - - static SystemAccessor systemAccessor; - static SecurityManagerAccessor securityManagerAccessor; - static FileDescriptorAccessor fileDescriptorAccessor; - static DotNetPathAccessor dotNetPathAccessor; - static DotNetDirectoryStreamAccessor dotNetDirectoryStreamAccessor; - - static SystemAccessor SystemAccessor => JVM.Internal.BaseAccessors.Get(ref systemAccessor); - - static SecurityManagerAccessor SecurityManagerAccessor => JVM.Internal.BaseAccessors.Get(ref securityManagerAccessor); - - static FileDescriptorAccessor FileDescriptorAccessor => JVM.Internal.BaseAccessors.Get(ref fileDescriptorAccessor); - - static DotNetPathAccessor DotNetPathAccessor => JVM.Internal.BaseAccessors.Get(ref dotNetPathAccessor); - - static DotNetDirectoryStreamAccessor DotNetDirectoryStreamAccessor => JVM.Internal.BaseAccessors.Get(ref dotNetDirectoryStreamAccessor); - - static global::ikvm.@internal.CallerID __callerID; - delegate void __jniDelegate__rename0(IntPtr jniEnv, IntPtr clazz, long fromAddress, long toAddress); - static __jniDelegate__rename0 __jniPtr__rename0; - -#if NETCOREAPP - - static readonly PropertyInfo SafeFileHandleIsAsyncProperty = typeof(SafeFileHandle).GetProperty("IsAsync", BindingFlags.Public | BindingFlags.Instance); - static readonly Action SafeFileHandleIsAsyncPropertySetter = SafeFileHandleIsAsyncProperty != null ? (o, v) => SafeFileHandleIsAsyncProperty.SetValue(o, v) : null; - -#endif - -#endif - - /// - /// Implements the native method 'open0'. - /// - /// - /// - /// - /// - /// - /// - /// - public static object open0(string path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options, object sm) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (sm != null) - { - if ((rights & FileSystemRights.Read) != 0) - SecurityManagerAccessor.InvokeCheckRead(sm, path); - if ((rights & FileSystemRights.Write) != 0) - SecurityManagerAccessor.InvokeCheckWrite(sm, path); - if ((rights & FileSystemRights.AppendData) != 0) - SecurityManagerAccessor.InvokeCheckWrite(sm, path); - if ((options & FileOptions.DeleteOnClose) != 0) - SecurityManagerAccessor.InvokeCheckDelete(sm, path); - } - - var access = (FileAccess)0; - if ((rights & FileSystemRights.Read) != 0) - access |= FileAccess.Read; - if ((rights & FileSystemRights.Write) != 0) - access |= FileAccess.Write; - if ((rights & FileSystemRights.AppendData) != 0) - access |= FileAccess.Write; - if (access == 0) - access = FileAccess.ReadWrite; - - try - { - if (JVM.Vfs.IsPath(path)) - { - if (JVM.Vfs.GetEntry(path) is VfsFile vfsFile) - { - var fdo = FileDescriptorAccessor.Init(); - FileDescriptorAccessor.SetStream(fdo, vfsFile.Open(mode, access)); - return fdo; - } - - throw new global::java.lang.UnsupportedOperationException(); - } - else - { -#if NETFRAMEWORK - var fdo = FileDescriptorAccessor.Init(); - FileDescriptorAccessor.SetStream(fdo, new FileStream(path, mode, rights, share, bufferSize, options)); - return fdo; -#else - if (RuntimeUtil.IsWindows) - { - var fdo = FileDescriptorAccessor.Init(); - FileDescriptorAccessor.SetStream(fdo, new FileStream(path, mode, access, share, bufferSize, options)); - return fdo; - } - else - { - var flags = (OpenFlags)0; - if (mode == FileMode.Create) - flags |= OpenFlags.O_CREAT | OpenFlags.O_TRUNC; - if (mode == FileMode.Open) - flags |= OpenFlags.O_EXCL; - if (mode == FileMode.OpenOrCreate) - flags |= OpenFlags.O_CREAT; - if (mode == FileMode.Append) - flags |= OpenFlags.O_APPEND; - if (mode == FileMode.CreateNew) - flags |= OpenFlags.O_CREAT | OpenFlags.O_EXCL; - - if ((rights & FileSystemRights.Read) != 0 && (rights & FileSystemRights.Write) != 0) - flags |= OpenFlags.O_RDWR; - if ((rights & FileSystemRights.Read) != 0 && (rights & FileSystemRights.Write) == 0) - flags |= OpenFlags.O_RDONLY; - if ((rights & FileSystemRights.Read) == 0 && (rights & FileSystemRights.Write) != 0) - flags |= OpenFlags.O_WRONLY; - - if ((options & FileOptions.Asynchronous) != 0) - flags |= OpenFlags.O_ASYNC; - if ((options & FileOptions.WriteThrough) != 0) - flags |= OpenFlags.O_SYNC; - - var r = Syscall.open(path, flags, FilePermissions.DEFFILEMODE); - if (r == -1) - { - var error = Stdlib.GetLastError(); - if (error == Errno.EACCES) - throw new global::java.nio.file.AccessDeniedException(path); - if (error == Errno.EEXIST) - throw new global::java.nio.file.FileAlreadyExistsException(path); - if (error == Errno.ENOENT) - throw new global::java.nio.file.NoSuchFileException(path); - if (error == Errno.ENOTDIR) - throw new global::java.nio.file.NoSuchFileException(path); - if (error == Errno.EROFS) - throw new global::java.nio.file.FileAlreadyExistsException(path); - - throw new UnixIOException(error); - } - - var h = new SafeFileHandle((IntPtr)r, false); - - // .NET Core 5+ maintains an IsAsync property validated by FileStream - // this property isn't set properly on Unix - // https://github.com/dotnet/runtime/issues/85560 - if ((options & FileOptions.Asynchronous) != 0) - SafeFileHandleIsAsyncPropertySetter?.Invoke(h, true); - - var fdo = FileDescriptorAccessor.Init(); - FileDescriptorAccessor.SetStream(fdo, new FileStream(h, access, bufferSize, (options & FileOptions.Asynchronous) != 0)); - return fdo; - } -#endif - } - } - catch (ArgumentException e) - { - throw new global::java.nio.file.FileSystemException(path, null, e.Message); - } - catch (FileNotFoundException) - { - throw new global::java.nio.file.NoSuchFileException(path); - } - catch (DirectoryNotFoundException) - { - throw new global::java.nio.file.NoSuchFileException(path); - } - catch (PlatformNotSupportedException e) - { - throw new global::java.lang.UnsupportedOperationException(e.Message); - } - catch (IOException) when (mode == FileMode.CreateNew && File.Exists(path)) - { - throw new global::java.nio.file.FileAlreadyExistsException(path); - } - catch (IOException e) - { - throw new global::java.nio.file.FileSystemException(path, null, e.Message); - } - catch (SecurityException) - { - throw new global::java.nio.file.AccessDeniedException(path); - } - catch (UnauthorizedAccessException) - { - throw new global::java.nio.file.AccessDeniedException(path); - } -#endif - } - - /// - /// Invokes the MoveFileEx native function on Windows. - /// - /// - /// - /// - /// - [DllImport("Kernel32", SetLastError = true)] - static extern int MoveFileEx(string lpExistingFileName, string lpNewFileName, int dwFlags); - - /// - /// Implements the native functionality for rename0. - /// - /// - /// - /// - /// - /// - /// - /// - public static unsafe void rename0(string source, string target) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - const int MOVEFILE_REPLACE_EXISTING = 1; - if (MoveFileEx(source, target, MOVEFILE_REPLACE_EXISTING) == 0) - { - const int ERROR_FILE_NOT_FOUND = 2; - const int ERROR_PATH_NOT_FOUND = 3; - const int ERROR_ACCESS_DENIED = 5; - const int ERROR_NOT_SAME_DEVICE = 17; - const int ERROR_FILE_EXISTS = 80; - const int ERROR_ALREADY_EXISTS = 183; - - int lastError = Marshal.GetLastWin32Error(); - switch (lastError) - { - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - throw new global::java.nio.file.NoSuchFileException(source, target, null); - case ERROR_ACCESS_DENIED: - throw new global::java.nio.file.AccessDeniedException(source, target, null); - case ERROR_NOT_SAME_DEVICE: - throw new global::java.nio.file.AtomicMoveNotSupportedException(source, target, "Unsupported copy option"); - case ERROR_FILE_EXISTS: - case ERROR_ALREADY_EXISTS: - throw new global::java.nio.file.FileAlreadyExistsException(source, target, null); - default: - throw new global::java.nio.file.FileSystemException(source, target, "Error " + lastError); - } - } - - return; - } - else - { - try - { - __callerID ??= global::ikvm.@internal.CallerID.create(typeof(global::sun.nio.fs.DotNetFileSystemProvider).TypeHandle); - __jniPtr__rename0 ??= Marshal.GetDelegateForFunctionPointer<__jniDelegate__rename0>(JNIFrame.GetFuncPtr(__callerID, "sun/nio/fs/UnixNativeDispatcher", nameof(rename0), "(JJ)V")); - var jniFrm = new JNIFrame(); - var jniEnv = jniFrm.Enter(__callerID); - try - { - byte[] sourceBuf = null; - byte[] targetBuf = null; - - try - { - var sourceLen = Encoding.UTF8.GetByteCount(source) + 1; - sourceBuf = ArrayPool.Shared.Rent(sourceLen); - sourceBuf[sourceLen - 1] = 0; - Encoding.UTF8.GetBytes(source, 0, source.Length, sourceBuf, 0); - - var targetLen = Encoding.UTF8.GetByteCount(target) + 1; - targetBuf = ArrayPool.Shared.Rent(targetLen); - targetBuf[targetLen - 1] = 0; - Encoding.UTF8.GetBytes(target, 0, target.Length, targetBuf, 0); - - fixed (byte* sourcePtr = sourceBuf) - fixed (byte* targetPtr = targetBuf) - { - __jniPtr__rename0(jniEnv, jniFrm.MakeLocalRef(ClassLiteral.Value), (long)(IntPtr)sourcePtr, (long)(IntPtr)targetPtr); - } - } - finally - { - if (sourceBuf != null) - ArrayPool.Shared.Return(sourceBuf); - if (targetBuf != null) - ArrayPool.Shared.Return(targetBuf); - } - } - catch (Exception ex) - { - System.Console.WriteLine("*** exception in native code ***"); - System.Console.WriteLine(ex); - throw; - } - finally - { - jniFrm.Leave(); - } - } - catch (global::sun.nio.fs.UnixException e) - { - const int EXDEV = 18; - - if (e.errno() == EXDEV) - throw new global::java.nio.file.AtomicMoveNotSupportedException(source, target, e.errorString()); - - e.rethrowAsIOException(source, target); - } - } -#endif - } - - /// - /// Implements the native method 'newDirectoryStream'. - /// - /// - /// - /// - /// - public static object newDirectoryStream(object self, object dir, object filter) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - if (dir == null) - throw new global::java.lang.NullPointerException(); - if (filter == null) - throw new global::java.lang.NullPointerException(); - - var path = DotNetPathAccessor.GetPath(dir); - if (path == null) - throw new global::java.lang.NullPointerException(); - - var sm = SystemAccessor.InvokeGetSecurityManager(); - if (sm != null) - SecurityManagerAccessor.InvokeCheckRead(sm, path); - - try - { - if (JVM.Vfs.IsPath(path)) - { - if (JVM.Vfs.GetEntry(path) is not VfsDirectory vfsDirectory) - throw new global::java.nio.file.NotDirectoryException(path); - - return DotNetDirectoryStreamAccessor.Init(dir, vfsDirectory.List().Select(i => Path.Combine(path, i)), filter); - } - - if (File.Exists(path)) - throw new global::java.nio.file.NotDirectoryException(path); - - if (Directory.Exists(path) == false) - throw new global::java.nio.file.NotDirectoryException(path); - - return DotNetDirectoryStreamAccessor.Init(dir, Directory.EnumerateFileSystemEntries(path), filter); - } - catch (global::java.lang.Throwable) - { - throw; - } - catch (Exception) when (File.Exists(path)) - { - throw new global::java.nio.file.NotDirectoryException(path); - } - catch (Exception e) - { - throw new global::java.io.IOException(e.Message); - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetPath.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetPath.cs deleted file mode 100644 index d015a8dfbb..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetPath.cs +++ /dev/null @@ -1,95 +0,0 @@ -/* - Copyright (C) 2007-2015 Jeroen Frijters - Copyright (C) 2009 Volker Berlin (i-net software) - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; -using System.IO; -using System.Security; - -using IKVM.Runtime; -using IKVM.Runtime.Vfs; - -namespace IKVM.Java.Externs.sun.nio.fs -{ - - static class DotNetPath - { - - public static string toRealPathImpl(string path) - { -#if FIRST_PASS - return null; -#else - path = global::java.io.DefaultFileSystem.getFileSystem().canonicalize(path); - if (JVM.Vfs.IsPath(path)) - { - if (JVM.Vfs.GetEntry(path) is VfsFile file) - { - if (file.CanOpen(FileMode.Open, FileAccess.Read) == false) - throw new global::java.nio.file.AccessDeniedException(path); - - return path; - } - - throw new global::java.nio.file.NoSuchFileException(path); - } - - try - { - File.GetAttributes(path); - return path; - } - catch (FileNotFoundException) - { - throw new global::java.nio.file.NoSuchFileException(path); - } - catch (DirectoryNotFoundException) - { - throw new global::java.nio.file.NoSuchFileException(path); - } - catch (UnauthorizedAccessException) - { - throw new global::java.nio.file.AccessDeniedException(path); - } - catch (SecurityException) - { - throw new global::java.nio.file.AccessDeniedException(path); - } - catch (ArgumentException x) - { - throw new global::java.nio.file.FileSystemException(path, null, x.Message); - } - catch (NotSupportedException x) - { - throw new global::java.nio.file.FileSystemException(path, null, x.Message); - } - catch (IOException x) - { - throw new global::java.nio.file.FileSystemException(path, null, x.Message); - } -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetUnixUriUtils.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetUnixUriUtils.cs deleted file mode 100644 index 970aab4611..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetUnixUriUtils.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; - -using IKVM.Runtime; -using IKVM.Runtime.Vfs; - -namespace IKVM.Java.Externs.sun.nio.fs -{ - - /// - /// Implements the native methods for 'DotNetUnixUriUtils'. - /// - static class DotNetUnixUriUtils - { - - /// - /// Implements the native method 'isVfsDirectory'. - /// - /// - /// - public static bool isVfsDirectory(string path) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return JVM.Vfs.GetEntry(path) is VfsDirectory; -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetWindowsUriSupport.cs b/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetWindowsUriSupport.cs deleted file mode 100644 index 2bd0b68961..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/nio/fs/DotNetWindowsUriSupport.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; - -using IKVM.Runtime; -using IKVM.Runtime.Vfs; - -namespace IKVM.Java.Externs.sun.nio.fs -{ - - /// - /// Implements the native methods for 'DotNetWindowsUriSupport'. - /// - static class DotNetWindowsUriSupport - { - - /// - /// Implements the native method 'isVfsDirectory'. - /// - /// - /// - public static bool isVfsDirectory(string path) - { -#if FIRST_PASS - throw new NotImplementedException(); -#else - return JVM.Vfs.GetEntry(path) is VfsDirectory; -#endif - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/security/krb5/Config.cs b/src/IKVM.Runtime/Java/Externs/sun/security/krb5/Config.cs deleted file mode 100644 index 82d7b517ea..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/security/krb5/Config.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright (C) 2007-2011 Jeroen Frijters - Copyright (C) 2011 Trevor Bell (Siemens Energy, Inc.) - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; - -namespace IKVM.Java.Externs.sun.security.krb5 -{ - - static class Config - { - - public static string getWindowsDirectory(bool isSystem) - { - if (isSystem) - return Environment.SystemDirectory; - - return Environment.GetEnvironmentVariable("SystemRoot"); - } - - } - -} diff --git a/src/IKVM.Runtime/Java/Externs/sun/security/krb5/Credentials.cs b/src/IKVM.Runtime/Java/Externs/sun/security/krb5/Credentials.cs deleted file mode 100644 index 7dda494d1c..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/security/krb5/Credentials.cs +++ /dev/null @@ -1,339 +0,0 @@ -/* - Copyright (C) 2007-2011 Jeroen Frijters - Copyright (C) 2011 Trevor Bell (Siemens Energy, Inc.) - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; -using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Security; - -namespace IKVM.Java.Externs.sun.security.krb5 -{ - - static class Credentials - { - -#if !FIRST_PASS - - private static global::java.util.Date ToJavaDate(long time) - { - // convert 100-nanosecond intervals to milliseconds offset milliseconds from Jan 1, 1601 to Jan 1, 1970 - const long DIFF_IN_MILLIS = 11644473600000L; - return new global::java.util.Date((time / 10000) - DIFF_IN_MILLIS); - } - -#endif - - public static object acquireDefaultNativeCreds(int[] eTypes) - { -#if FIRST_PASS - return null; -#else - Ticket ticket; - try - { - ticket = Win32KerberosSupport.GetTicket(); - } - catch (Win32Exception) - { - // there's no way to return more specific error information - return null; - } - // we use reflection to instantiate the Credentials object, - // because we don't want a static dependency on IKVM.Java.Security.dll - return global::java.lang.Class.forName("sun.security.krb5.Credentials") - .getConstructor(typeof(byte[]), - typeof(string), - typeof(string), - typeof(byte[]), - typeof(int), - typeof(bool[]), - typeof(global::java.util.Date), - typeof(global::java.util.Date), - typeof(global::java.util.Date), - typeof(global::java.util.Date), - typeof(global::java.net.InetAddress[])) - .newInstance(ticket.EncodedTicket, - ticket.ClientNames[0], - ticket.TargetNames[0], - ticket.SessionKey, - global::java.lang.Integer.valueOf(ticket.SessionKeyType), - null, - ToJavaDate(ticket.StartTime), - ToJavaDate(ticket.StartTime), - ToJavaDate(ticket.EndTime), - ToJavaDate(ticket.RenewUntil), - null); -#endif - } - - sealed class Ticket - { - public byte[] EncodedTicket; - public string[] ClientNames; - public string[] TargetNames; - public byte[] SessionKey; - public int SessionKeyType; - public long StartTime; - public long EndTime; - public long RenewUntil; - } - - static class Win32KerberosSupport - { - const int STATUS_SUCCESS = 0; - - [SecurityCritical] - sealed class LsaSafeHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid - { - internal LsaSafeHandle() - : base(true) - { - } - - [SecurityCritical] - override protected bool ReleaseHandle() - { - return LsaDeregisterLogonProcess(handle) == STATUS_SUCCESS; - } - } - - enum KERB_PROTOCOL_MESSAGE_TYPE - { - KerbRetrieveTicketMessage = 4 - } - - [StructLayout(LayoutKind.Sequential)] - struct LsaString - { - public ushort Length; - public ushort MaximumLength; - [MarshalAs(UnmanagedType.LPStr)] - public string Buffer; - } - - [StructLayout(LayoutKind.Sequential)] - struct LUID - { - public uint LowPart; - public int HighPart; - } - - [StructLayout(LayoutKind.Sequential)] - struct KERB_QUERY_TKT_CACHE_REQUEST - { - public KERB_PROTOCOL_MESSAGE_TYPE MessageType; - public LUID LoginId; - } - - [StructLayout(LayoutKind.Sequential)] - struct UNICODE_STRING - { - public ushort Length; - public ushort MaximumLength; - public IntPtr Buffer; - } - - [StructLayout(LayoutKind.Sequential)] - struct KERB_CRYPTO_KEY - { - public int KeyType; - public int Length; - public IntPtr Value; - } - - [StructLayout(LayoutKind.Sequential)] - sealed class KERB_RETRIEVE_TKT_RESPONSE - { - public KERB_EXTERNAL_TICKET Ticket; - } - - [StructLayout(LayoutKind.Sequential)] - struct KERB_EXTERNAL_TICKET - { - public IntPtr ServiceName; - public IntPtr TargetName; - public IntPtr ClientName; - public UNICODE_STRING DomainName; - public UNICODE_STRING TargetDomainName; - public UNICODE_STRING AltTargetDomainName; - public KERB_CRYPTO_KEY SessionKey; - public uint TicketFlags; - public uint Flags; - public long KeyExpirationTime; - public long StartTime; - public long EndTime; - public long RenewUntil; - public long TimeSkew; - public int EncodedTicketSize; - public IntPtr EncodedTicket; - } - - [DllImport("secur32.dll")] - static extern int LsaDeregisterLogonProcess(IntPtr handle); - - [DllImport("secur32.dll")] - static extern int LsaConnectUntrusted(out LsaSafeHandle LsaHandle); - - [DllImport("secur32.dll")] - static extern int LsaCallAuthenticationPackage( - LsaSafeHandle LsaHandle, - uint AuthenticationPackage, - ref KERB_QUERY_TKT_CACHE_REQUEST ProtocolSubmitBuffer, - int SubmitBufferLength, - out IntPtr ProtocolReturnBuffer, - out int ReturnBufferLength, - out int ProtocolStatus); - - [DllImport("secur32.dll")] - static extern int LsaLookupAuthenticationPackage( - LsaSafeHandle LsaHandle, - ref LsaString PackageName, - out uint AuthenticationPackage); - - [DllImport("advapi32.dll")] - static extern int LsaNtStatusToWinError(int status); - - [DllImport("secur32.dll")] - static extern int LsaFreeReturnBuffer(IntPtr buffer); - - static void Check(int ntstatus) - { - if (ntstatus != STATUS_SUCCESS) - { - throw new Win32Exception(LsaNtStatusToWinError(ntstatus)); - } - } - - [SecuritySafeCritical] - internal static Ticket GetTicket() - { - LsaSafeHandle lsaHandle = null; - try - { - // connect to the LSA outside the TCB - Check(LsaConnectUntrusted(out lsaHandle)); - - string kerberos = "Kerberos"; - LsaString lsaString = new LsaString(); - lsaString.Length = (ushort)kerberos.Length; - lsaString.MaximumLength = (ushort)kerberos.Length; - lsaString.Buffer = kerberos; - - uint authenticationPackage = 0; - - // lookup the index for the Kerberos authentication package - Check(LsaLookupAuthenticationPackage(lsaHandle, ref lsaString, out authenticationPackage)); - - KERB_QUERY_TKT_CACHE_REQUEST request = new KERB_QUERY_TKT_CACHE_REQUEST(); - request.MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbRetrieveTicketMessage; - request.LoginId.LowPart = 0; - request.LoginId.HighPart = 0; - - int submitBufferLength = Marshal.SizeOf(typeof(KERB_QUERY_TKT_CACHE_REQUEST)); - IntPtr responsePointer = IntPtr.Zero; - int returnBufferLength = 0; - int protocolStatus = 0; - - try - { - // send the request to Kerberos and get a response - Check(LsaCallAuthenticationPackage(lsaHandle, - authenticationPackage, - ref request, - submitBufferLength, - out responsePointer, - out returnBufferLength, - out protocolStatus)); - - Check(protocolStatus); - - if (responsePointer == IntPtr.Zero || returnBufferLength < Marshal.SizeOf(typeof(KERB_RETRIEVE_TKT_RESPONSE))) - { - throw new InvalidOperationException(); - } - - KERB_RETRIEVE_TKT_RESPONSE response = new KERB_RETRIEVE_TKT_RESPONSE(); - Marshal.PtrToStructure(responsePointer, response); - - Ticket ticket = new Ticket(); - ticket.EncodedTicket = ReadBytes(response.Ticket.EncodedTicket, response.Ticket.EncodedTicketSize); - ticket.ClientNames = ReadExternalName(response.Ticket.ClientName); - ticket.TargetNames = ReadExternalName(response.Ticket.TargetName); - ticket.SessionKey = ReadBytes(response.Ticket.SessionKey.Value, response.Ticket.SessionKey.Length); - ticket.SessionKeyType = response.Ticket.SessionKey.KeyType; - ticket.StartTime = response.Ticket.StartTime; - ticket.EndTime = response.Ticket.EndTime; - ticket.RenewUntil = response.Ticket.RenewUntil; - return ticket; - } - finally - { - if (responsePointer != IntPtr.Zero) - { - Check(LsaFreeReturnBuffer(responsePointer)); - } - } - } - finally - { - if (lsaHandle != null) - { - lsaHandle.Close(); - } - } - } - - [SecurityCritical] - private static string[] ReadExternalName(IntPtr ptr) - { - int nameCount = (ushort)Marshal.ReadInt16(ptr, 2); - ptr = (IntPtr)((long)ptr + 4 + IntPtr.Size - 4); - string[] names = new string[nameCount]; - for (int i = 0; i < nameCount; i++) - { - names[i] = ReadUnicodeString(ref ptr); - } - return names; - } - - [SecurityCritical] - private static string ReadUnicodeString(ref IntPtr ptr) - { - UNICODE_STRING str = (UNICODE_STRING)Marshal.PtrToStructure(ptr, typeof(UNICODE_STRING)); - ptr = (IntPtr)((long)ptr + Marshal.SizeOf(typeof(UNICODE_STRING))); - return Marshal.PtrToStringUni(str.Buffer, str.Length / 2); - } - - [SecurityCritical] - private static byte[] ReadBytes(IntPtr ptr, int length) - { - byte[] buf = new byte[length]; - Marshal.Copy(ptr, buf, 0, length); - return buf; - } - } - - } - -} \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/sun/security/krb5/SCDynamicStoreConfig.cs b/src/IKVM.Runtime/Java/Externs/sun/security/krb5/SCDynamicStoreConfig.cs deleted file mode 100644 index 05374ce3b2..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/security/krb5/SCDynamicStoreConfig.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright (C) 2007-2011 Jeroen Frijters - Copyright (C) 2011 Trevor Bell (Siemens Energy, Inc.) - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.Java.Externs.sun.security.krb5 -{ - - static class SCDynamicStoreConfig - { - - public static void installNotificationCallback() - { - - } - - public static object getKerberosConfig() - { - return null; - } - - } - -} \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/sun/util/locale/provider/HostLocaleProviderAdapterImpl.cs b/src/IKVM.Runtime/Java/Externs/sun/util/locale/provider/HostLocaleProviderAdapterImpl.cs deleted file mode 100644 index c9bb4c9385..0000000000 --- a/src/IKVM.Runtime/Java/Externs/sun/util/locale/provider/HostLocaleProviderAdapterImpl.cs +++ /dev/null @@ -1,552 +0,0 @@ -/* - Copyright (C) 2014 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; -using System.Globalization; - -namespace IKVM.Java.Externs.sun.util.locale.provider -{ - - static class HostLocaleProviderAdapterImpl - { - - private static string[][] positivePatterns = new string[][] { - // NF_NUMBER - new string[] { "{0}" }, - // NF_CURRENCY - new string[] { "\xA4{0}", "{0}\xA4", "\xA4 {0}", "{0} \xA4" }, - // NF_PERCENT - new string[] { "{0} %", "{0}%", "%{0}", "% {0}" }, - }; - - private static string[][] negativePatterns = new string[][] { - // NF_NUMBER - new string[] { "({0})", "-{0}", "- {0}", "{0}-", "{0} -" }, - // NF_CURRENCY - new string[] { "(\xA4{0})", "-\xA4{0}", "\xA4-{0}", "\xA4{0}-", "({0}\xA4)", "-{0}\xA4", "{0}-\xA4", "{0}\xA4-", "-{0} \xA4", "-\xA4 {0}", "{0} \xA4-", "\xA4 {0}-", "\xA4 -{0}", "{0}- \xA4", "(\xA4 {0})", "({0} \xA4)" }, - // NF_PERCENT - new string[] { "-{0} %", "-{0}%", "-%{0}", "%-{0}", "%{0}-", "{0}-%", "{0}%-", "-% {0}", "{0} %-", "% {0}-", "% -{0}", "{0}- %" }, - }; - - public static bool initialize() - { - return true; - } - - public static string getDefaultLocale(int cat) - { - const int CAT_DISPLAY = 0; - const int CAT_FORMAT = 1; - switch (cat) - { - case CAT_DISPLAY: - return CultureInfo.CurrentUICulture.IetfLanguageTag; - case CAT_FORMAT: - return CultureInfo.CurrentCulture.IetfLanguageTag; - default: - throw new NotSupportedException(); - } - } - - public static string getDateTimePattern(int dateStyle, int timeStyle, string langTag) - { - CultureInfo ci; - if (TryGetCultureInfoFromLangTag(langTag, out ci)) - { - switch (timeStyle) - { - case 0: - case 1: - return ci.DateTimeFormat.LongTimePattern; - case 2: - case 3: - // NOTE prior to .NET 4.0 this does not return the user's customized time pattern - return ci.DateTimeFormat.ShortTimePattern; - } - - switch (dateStyle) - { - case 0: - case 1: - return ci.DateTimeFormat.LongDatePattern; - case 2: - case 3: - return ci.DateTimeFormat.ShortDatePattern; - } - } - return ""; - } - - public static int getCalendarID(string langTag) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return 0; - } - // this mapping is based on the CAL_* constants defined in - // http://referencesource.microsoft.com/#mscorlib/system/globalization/calendar.cs#70 - Calendar cal = ci.Calendar; - if (cal is GregorianCalendar) - { - switch (((GregorianCalendar)cal).CalendarType) - { - case GregorianCalendarTypes.Localized: - return 1; - case GregorianCalendarTypes.USEnglish: - return 2; - case GregorianCalendarTypes.MiddleEastFrench: - return 9; - case GregorianCalendarTypes.Arabic: - return 10; - case GregorianCalendarTypes.TransliteratedEnglish: - return 11; - case GregorianCalendarTypes.TransliteratedFrench: - return 12; - default: - return 0; - } - } - else if (cal is JapaneseCalendar) - { - return 3; - } - else if (cal is TaiwanCalendar) - { - return 4; - } - else if (cal is KoreanCalendar) - { - return 5; - } - else if (cal is HijriCalendar) - { - return 6; - } - else if (cal is ThaiBuddhistCalendar) - { - return 7; - } - else if (cal is HebrewCalendar) - { - return 8; - } - else if (cal is JulianCalendar) - { - return 13; - } - else if (cal is JapaneseLunisolarCalendar) - { - return 14; - } - else if (cal is ChineseLunisolarCalendar) - { - return 15; - } - else if (cal is KoreanLunisolarCalendar) - { - return 20; - } - else if (cal is TaiwanLunisolarCalendar) - { - return 21; - } - else if (cal is PersianCalendar) - { - return 22; - } - else if (cal is UmAlQuraCalendar) - { - return 23; - } - else - { - return 0; - } - } - - public static string[] getAmPmStrings(string langTag, string[] ampm) - { - CultureInfo ci; - if (TryGetCultureInfoFromLangTag(langTag, out ci)) - { - DateTimeFormatInfo info = ci.DateTimeFormat; - ampm[0] = info.AMDesignator; - ampm[1] = info.PMDesignator; - } - return ampm; - } - - public static string[] getEras(string langTag, string[] eras) - { - CultureInfo ci; - if (TryGetCultureInfoFromLangTag(langTag, out ci)) - { - eras[1] = ci.DateTimeFormat.GetAbbreviatedEraName(ci.Calendar.GetEra(DateTime.Now)); - } - return eras; - } - - public static string[] getMonths(string langTag, string[] months) - { - CultureInfo ci; - if (TryGetCultureInfoFromLangTag(langTag, out ci)) - { - DateTimeFormatInfo dtfi = ci.DateTimeFormat; - for (int i = 1; i <= 13; i++) - { - months[i - 1] = dtfi.GetMonthName(i); - } - } - return months; - } - - public static string[] getShortMonths(string langTag, string[] smonths) - { - CultureInfo ci; - if (TryGetCultureInfoFromLangTag(langTag, out ci)) - { - DateTimeFormatInfo dtfi = ci.DateTimeFormat; - for (int i = 1; i <= 13; i++) - { - smonths[i - 1] = dtfi.GetAbbreviatedMonthName(i); - } - } - return smonths; - } - - public static string[] getWeekdays(string langTag, string[] wdays) - { - CultureInfo ci; - if (TryGetCultureInfoFromLangTag(langTag, out ci)) - { - DateTimeFormatInfo dtfi = ci.DateTimeFormat; - for (int i = 0; i < 7; i++) - { - wdays[i + 1] = dtfi.GetDayName((DayOfWeek)i); - } - } - return wdays; - } - - public static string[] getShortWeekdays(string langTag, string[] swdays) - { - CultureInfo ci; - if (TryGetCultureInfoFromLangTag(langTag, out ci)) - { - DateTimeFormatInfo dtfi = ci.DateTimeFormat; - for (int i = 0; i < 7; i++) - { - swdays[i + 1] = dtfi.GetAbbreviatedDayName((DayOfWeek)i); - } - } - return swdays; - } - - public static string getNumberPattern(int numberStyle, string langTag) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - ci = CultureInfo.InvariantCulture; - } - NumberFormatInfo nfi = ci.NumberFormat; - const int NF_NUMBER = 0; - const int NF_CURRENCY = 1; - const int NF_PERCENT = 2; - const int NF_INTEGER = 3; - int digits; - int[] groupSizes; - int positivePattern; - int negativePattern; - switch (numberStyle) - { - case NF_NUMBER: - digits = nfi.NumberDecimalDigits; - groupSizes = nfi.NumberGroupSizes; - positivePattern = 0; - negativePattern = nfi.NumberNegativePattern; - break; - case NF_CURRENCY: - digits = nfi.CurrencyDecimalDigits; - groupSizes = nfi.CurrencyGroupSizes; - positivePattern = nfi.CurrencyPositivePattern; - negativePattern = nfi.CurrencyNegativePattern; - break; - case NF_PERCENT: - digits = nfi.PercentDecimalDigits; - groupSizes = nfi.PercentGroupSizes; - positivePattern = nfi.PercentPositivePattern; - negativePattern = nfi.PercentNegativePattern; - break; - case NF_INTEGER: - digits = 0; - groupSizes = nfi.NumberGroupSizes; - positivePattern = 0; - negativePattern = nfi.NumberNegativePattern; - break; - default: - throw new NotSupportedException(); - } - string number = ""; - foreach (int group in groupSizes) - { - if (group > 0) - { - number += "#," + new String('#', group - 1); - } - } - number += "0"; - if (digits > 0) - { - number += "." + new String('0', digits); - } - return String.Format(positivePatterns[numberStyle % 3][positivePattern] + ";" + negativePatterns[numberStyle % 3][negativePattern], number); - } - - public static bool isNativeDigit(string langTag) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return false; - } - return ci.NumberFormat.DigitSubstitution == DigitShapes.NativeNational; - } - - public static string getCurrencySymbol(string langTag, string currencySymbol) - { - RegionInfo ri; - if (!TryGetRegionInfoFromLangTag(langTag, out ri)) - { - return currencySymbol; - } - return ri.CurrencySymbol; - } - - public static char getDecimalSeparator(string langTag, char decimalSeparator) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return decimalSeparator; - } - return ci.NumberFormat.NumberDecimalSeparator[0]; - } - - public static char getGroupingSeparator(string langTag, char groupingSeparator) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return groupingSeparator; - } - return ci.NumberFormat.NumberGroupSeparator[0]; - } - - public static string getInfinity(string langTag, string infinity) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return infinity; - } - return ci.NumberFormat.PositiveInfinitySymbol; - } - - public static string getInternationalCurrencySymbol(string langTag, string internationalCurrencySymbol) - { - RegionInfo ri; - if (!TryGetRegionInfoFromLangTag(langTag, out ri)) - { - return internationalCurrencySymbol; - } - return ri.ISOCurrencySymbol; - } - - public static char getMinusSign(string langTag, char minusSign) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return minusSign; - } - return ci.NumberFormat.NegativeSign[0]; - } - - public static char getMonetaryDecimalSeparator(string langTag, char monetaryDecimalSeparator) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return monetaryDecimalSeparator; - } - return ci.NumberFormat.CurrencyDecimalSeparator[0]; - } - - public static string getNaN(string langTag, string nan) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return nan; - } - return ci.NumberFormat.NaNSymbol; - } - - public static char getPercent(string langTag, char percent) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return percent; - } - return ci.NumberFormat.PercentSymbol[0]; - } - - public static char getPerMill(string langTag, char perMill) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return perMill; - } - return ci.NumberFormat.PerMilleSymbol[0]; - } - - public static char getZeroDigit(string langTag, char zeroDigit) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return zeroDigit; - } - return ci.NumberFormat.NativeDigits[0][0]; - } - - public static int getCalendarDataValue(string langTag, int type) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(langTag, out ci)) - { - return -1; - } - const int CD_FIRSTDAYOFWEEK = 0; - switch (type) - { - case CD_FIRSTDAYOFWEEK: - return (((int)ci.DateTimeFormat.FirstDayOfWeek) + 6) % 7; - default: - throw new NotSupportedException(); - } - } - - public static string getDisplayString(string langTag, int key, string value) - { - const int DN_CURRENCY_NAME = 0; - const int DN_CURRENCY_SYMBOL = 1; - const int DN_LOCALE_LANGUAGE = 2; - const int DN_LOCALE_REGION = 4; - - if (key == DN_LOCALE_LANGUAGE) - { - CultureInfo ci; - if (!TryGetCultureInfoFromLangTag(value, out ci)) - { - return null; - } - while (ci.Parent != CultureInfo.InvariantCulture) - { - ci = ci.Parent; - } - return ci.DisplayName; - } - else if (key == DN_LOCALE_REGION) - { - RegionInfo ri; - if (!TryGetRegionInfoFromLangTag(value, out ri)) - { - return null; - } - return ri.DisplayName; - } - else - { - RegionInfo ri; - if (!TryGetRegionInfoFromLangTag(langTag, out ri)) - { - return null; - } - switch (key) - { - case DN_CURRENCY_NAME: - return ri.CurrencyNativeName; - case DN_CURRENCY_SYMBOL: - return ri.CurrencySymbol; - default: - throw new NotSupportedException(); - } - } - } - - private static bool TryGetCultureInfoFromLangTag(string langTag, out CultureInfo ci) - { - try - { - // we can't use CultureInfo.GetCultureInfo() here, because we want the UseUserOverride = true behavior - ci = new CultureInfo(NormalizeLangTag(langTag)); - return true; - } - catch (ArgumentException) // .NET 2.0 throws an ArgumentException and .NET 4.0 throws CultureNotFoundException (a subclass of ArgumentException) - { - ci = null; - return false; - } - } - - private static bool TryGetRegionInfoFromLangTag(string langTag, out RegionInfo ri) - { - try - { - ri = new RegionInfo(NormalizeLangTag(langTag)); - return true; - } - catch (ArgumentException) // .NET 2.0 throws an ArgumentException and .NET 4.0 throws CultureNotFoundException (a subclass of ArgumentException) - { - ri = null; - return false; - } - } - - private static string NormalizeLangTag(string langTag) - { - if (langTag == "und") - { - langTag = "en-US"; - } - return langTag; - } - - } - -} \ No newline at end of file diff --git a/src/IKVM.Runtime/LibIkvm.cs b/src/IKVM.Runtime/LibIkvm.cs index 2c75606b22..528e3b6527 100644 --- a/src/IKVM.Runtime/LibIkvm.cs +++ b/src/IKVM.Runtime/LibIkvm.cs @@ -26,7 +26,7 @@ static class Externs /// /// [DllImport("ikvm", SetLastError = false)] - internal static extern nint IKVM_dl_open(string path); + internal static extern nint IKVM_dl_open([MarshalAs(UnmanagedType.LPUTF8Str)] string path); /// /// Invokes the native 'IKVM_dl_sym' function. @@ -35,7 +35,7 @@ static class Externs /// /// [DllImport("ikvm", SetLastError = false)] - internal static extern nint IKVM_dl_sym(nint handle, string symbol); + internal static extern nint IKVM_dl_sym(nint handle, [MarshalAs(UnmanagedType.LPStr)] string symbol); /// /// Invokes the native 'IKVM_dl_close' function. @@ -101,7 +101,7 @@ static class Externs /// /// [DllImport("ikvm", SetLastError = false)] - internal static extern int IKVM_io_lstat(string pathname, out long st_ino, out long st_dev); + internal static extern int IKVM_io_lstat([MarshalAs(UnmanagedType.LPUTF8Str)] string pathname, out long st_ino, out long st_dev); /// /// Invokes the native 'IKVM_sig_get_size_sigaction' function. @@ -219,7 +219,7 @@ static nint Load() // start looking at assembly path, or path given by environmental variable var asml = typeof(NativeLibrary).Assembly.Location is string s ? Path.GetDirectoryName(s) : null; - var root = Environment.GetEnvironmentVariable("IKVM_LIBRARY_PATH") ?? asml; + var root = Environment.GetEnvironmentVariable("IKVM_LIBRARY_PATH") ?? asml ?? AppContext.BaseDirectory; // assembly possible loaded in memory: we have no available search path if (string.IsNullOrEmpty(root)) diff --git a/src/IKVM.Runtime/LibJVM.cs b/src/IKVM.Runtime/LibJVM.cs index eed1cef54e..eb434cdd01 100644 --- a/src/IKVM.Runtime/LibJVM.cs +++ b/src/IKVM.Runtime/LibJVM.cs @@ -1,8 +1,6 @@ using System; using System.IO; using System.Runtime.InteropServices; -using System.Text; -using System.Threading; using IKVM.Runtime.JNI; @@ -17,26 +15,48 @@ namespace IKVM.Runtime internal unsafe class LibJvm { + /// + /// Structure of callbacks passed to libjvm. + /// + [StructLayout(LayoutKind.Sequential)] + unsafe struct JVMInvokeInterface + { + + public nint JNI_GetDefaultJavaVMInitArgs; + public nint JNI_GetCreatedJavaVMs; + public nint JNI_CreateJavaVM; + + public nint JVM_ThrowException; + public nint JVM_GetThreadInterruptEvent; + public nint JVM_ActiveProcessorCount; + + } + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int JNI_GetDefaultJavaVMInitArgsFunc(void* vm_args); + delegate int JNI_GetDefaultJavaVMInitArgsDelegate(void* vm_args); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int JNI_GetCreatedJavaVMsFunc(JavaVM** vmBuf, int bufLen, int* nVMs); + delegate int JNI_GetCreatedJavaVMsDelegate(JavaVM** vmBuf, int bufLen, int* nVMs); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int JNI_CreateJavaVMFunc(JavaVM** p_vm, void** p_env, void* vm_args); + delegate int JNI_CreateJavaVMDelegate(JavaVM** p_vm, void** p_env, void* vm_args); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void IKVM_ThrowExceptionFunc([MarshalAs(UnmanagedType.LPUTF8Str)] string name, [MarshalAs(UnmanagedType.LPUTF8Str)] string message); + delegate void JVM_ThrowExceptionDelegate([MarshalAs(UnmanagedType.LPUTF8Str)] string name, [MarshalAs(UnmanagedType.LPUTF8Str)] string message); - delegate void Set_JNI_GetDefaultJavaVMInitArgsDelegate(JNI_GetDefaultJavaVMInitArgsFunc func); - delegate void Set_JNI_GetCreatedJavaVMsDelegate(JNI_GetCreatedJavaVMsFunc func); - delegate void Set_JNI_CreateJavaVMDelegate(JNI_CreateJavaVMFunc func); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + delegate nint JVM_GetThreadInterruptEventDelegate(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + delegate int JVM_ActiveProcessorCountDelegate(); + + delegate void JVM_InitDelegate(JVMInvokeInterface* iface); + + delegate nint JVM_LoadLibraryDelegate([MarshalAs(UnmanagedType.LPUTF8Str)] string name); - delegate void Set_IKVM_ThrowExceptionDelegate(IKVM_ThrowExceptionFunc func); - delegate nint JVM_LoadLibraryDelegate(string name); delegate void JVM_UnloadLibraryDelegate(nint handle); - delegate nint JVM_FindLibraryEntryDelegate(nint handle, string name); + + delegate nint JVM_FindLibraryEntryDelegate(nint handle, [MarshalAs(UnmanagedType.LPStr)] string name); /// /// Gets the default instance. @@ -44,17 +64,19 @@ internal unsafe class LibJvm public static readonly LibJvm Instance = new(); readonly ikvm.@internal.CallerID callerID = ikvm.@internal.CallerID.create(typeof(LibJvm).TypeHandle); + readonly JVMInvokeInterface* jvmii; - readonly Set_JNI_GetDefaultJavaVMInitArgsDelegate _Set_JNI_GetDefaultJavaVMInitArgs; - readonly Set_JNI_GetCreatedJavaVMsDelegate _Set_JNI_GetCreatedJavaVMs; - readonly Set_JNI_CreateJavaVMDelegate _Set_JNI_CreateJavaVM; - - readonly Set_IKVM_ThrowExceptionDelegate _Set_IKVM_ThrowException; + readonly JVM_InitDelegate _JVM_Init; readonly JVM_LoadLibraryDelegate _JVM_LoadLibrary; readonly JVM_UnloadLibraryDelegate _JVM_UnloadLibrary; readonly JVM_FindLibraryEntryDelegate _JVM_FindLibraryEntry; - readonly IKVM_ThrowExceptionFunc _IKVM_ThrowException; + readonly JNI_GetDefaultJavaVMInitArgsDelegate _JNI_GetDefaultJavaVMInitArgs; + readonly JNI_GetCreatedJavaVMsDelegate _JNI_GetCreatedJavaVMs; + readonly JNI_CreateJavaVMDelegate _JNI_CreateJavaVM; + readonly JVM_ThrowExceptionDelegate _JVM_ThrowException; + readonly JVM_GetThreadInterruptEventDelegate _JVM_GetThreadInterruptEvent; + readonly JVM_ActiveProcessorCountDelegate _JVM_ActiveProcessorCount; /// /// Initializes a new instance. @@ -64,17 +86,21 @@ internal unsafe class LibJvm // load libjvm through IKVM native library functionality if ((Handle = NativeLibrary.Load(Path.Combine(JVM.Properties.HomePath, "bin", NativeLibrary.MapLibraryName("jvm")))) == null) throw new InternalException("Could not load libjvm."); - - _Set_JNI_GetDefaultJavaVMInitArgs = Marshal.GetDelegateForFunctionPointer(Handle.GetExport("Set_JNI_GetDefaultJavaVMInitArgs", sizeof(nint)).Handle); - _Set_JNI_GetCreatedJavaVMs = Marshal.GetDelegateForFunctionPointer(Handle.GetExport("Set_JNI_GetCreatedJavaVMs", sizeof(nint)).Handle); - _Set_JNI_CreateJavaVM = Marshal.GetDelegateForFunctionPointer(Handle.GetExport("Set_JNI_CreateJavaVM", sizeof(nint)).Handle); - - _Set_IKVM_ThrowException = Marshal.GetDelegateForFunctionPointer(Handle.GetExport("Set_IKVM_ThrowException", sizeof(nint)).Handle); + // obtain delegates to functions declared in libjvm + _JVM_Init = Marshal.GetDelegateForFunctionPointer(Handle.GetExport("JVM_Init", sizeof(nint)).Handle); _JVM_LoadLibrary = Marshal.GetDelegateForFunctionPointer(Handle.GetExport("JVM_LoadLibrary", sizeof(nint)).Handle); _JVM_UnloadLibrary = Marshal.GetDelegateForFunctionPointer(Handle.GetExport("JVM_UnloadLibrary", sizeof(nint)).Handle); _JVM_FindLibraryEntry = Marshal.GetDelegateForFunctionPointer(Handle.GetExport("JVM_FindLibraryEntry", sizeof(nint) + sizeof(nint)).Handle); - Set_IKVM_ThrowException(_IKVM_ThrowException = IKVM_ThrowException); + // initialize invoke interface for calls from libjvm to IKVM + jvmii = (JVMInvokeInterface*)Marshal.AllocHGlobal(sizeof(JVMInvokeInterface)); + jvmii->JNI_GetDefaultJavaVMInitArgs = Marshal.GetFunctionPointerForDelegate(_JNI_GetDefaultJavaVMInitArgs = JNIVM.GetDefaultJavaVMInitArgs); + jvmii->JNI_GetCreatedJavaVMs = Marshal.GetFunctionPointerForDelegate(_JNI_GetCreatedJavaVMs = JNIVM.GetCreatedJavaVMs); + jvmii->JNI_CreateJavaVM = Marshal.GetFunctionPointerForDelegate(_JNI_CreateJavaVM = JNIVM.CreateJavaVM); + jvmii->JVM_ThrowException = Marshal.GetFunctionPointerForDelegate(_JVM_ThrowException = JVM_ThrowException); + jvmii->JVM_GetThreadInterruptEvent = Marshal.GetFunctionPointerForDelegate(_JVM_GetThreadInterruptEvent = JVM_GetThreadInterruptEvent); + jvmii->JVM_ActiveProcessorCount = Marshal.GetFunctionPointerForDelegate(_JVM_ActiveProcessorCount = JVM_ActiveProcessorCount); + _JVM_Init(jvmii); } /// @@ -82,77 +108,80 @@ internal unsafe class LibJvm /// public NativeLibraryHandle Handle { get; private set; } - /// - /// Invokes the 'Set_JNI_GetDefaultJavaVMInitArgs' method from libjvm. - /// - /// - public void Set_JNI_GetDefaultJavaVMInitArgs(JNI_GetDefaultJavaVMInitArgsFunc func) => _Set_JNI_GetDefaultJavaVMInitArgs(func); - - /// - /// Invokes the 'Set_JNI_GetCreatedJavaVMs' method from libjvm. - /// - /// - public void Set_JNI_GetCreatedJavaVMs(JNI_GetCreatedJavaVMsFunc func) => _Set_JNI_GetCreatedJavaVMs(func); - - /// - /// Invokes the 'Set_JNI_CreateJavaVM' method from libjvm. - /// - /// - public void Set_JNI_CreateJavaVM(JNI_CreateJavaVMFunc func) => _Set_JNI_CreateJavaVM(func); - - /// - /// Invokes the 'Set_IKVM_ThrowException' method from libjvm. - /// - /// - public void Set_IKVM_ThrowException(IKVM_ThrowExceptionFunc func) => _Set_IKVM_ThrowException(func); - /// /// Invoked by the native code to register an exception to be thrown. /// /// /// /// - void IKVM_ThrowException(string name, string msg) + void JVM_ThrowException(string name, string msg) { - if (name == null) + try { - Tracer.Error(Tracer.Runtime, $"{nameof(LibJvm)}.{nameof(IKVM_ThrowException)}: Missing name argument."); - return; - } + if (name == null) + { + Tracer.Error(Tracer.Runtime, $"{nameof(LibJvm)}.{nameof(JVM_ThrowException)}: Missing name argument."); + return; + } + + // find requested exception class + var exceptionClass = RuntimeClassLoader.FromCallerID(callerID).TryLoadClassByName(name.Replace('/', '.')); + if (exceptionClass == null) + { + Tracer.Error(Tracer.Runtime, $"{nameof(LibJvm)}.{nameof(JVM_ThrowException)}: Could not find exception class {{0}}.", name); + return; + } + + // find constructor + var ctor = exceptionClass.GetMethodWrapper("", msg == null ? "()V" : "(Ljava.lang.String;)V", false); + if (ctor == null) + { + Tracer.Error(Tracer.Runtime, $"{nameof(LibJvm)}.{nameof(JVM_ThrowException)}: Exception {{0}} missing constructor.", name); + return; + } + + // invoke the constructor + exceptionClass.Finish(); - // find requested exception class - var exceptionClass = RuntimeClassLoader.FromCallerID(callerID).TryLoadClassByName(name.Replace('/', '.')); - if (exceptionClass == null) - { - Tracer.Error(Tracer.Runtime, $"{nameof(LibJvm)}.{nameof(IKVM_ThrowException)}: Could not find exception class {{0}}.", name); - return; + var ctorMember = (java.lang.reflect.Constructor)ctor.ToMethodOrConstructor(false); + var exception = (Exception)ctorMember.newInstance(msg == null ? Array.Empty() : new object[] { msg }, callerID); + Tracer.Verbose(Tracer.Runtime, $"{nameof(LibJvm)}.{nameof(JVM_ThrowException)}: Created exception {{0}} from libjvm.", name); + JVM.SetPendingException(exception); } - - // find constructor - var ctor = exceptionClass.GetMethodWrapper("", msg == null ? "()V" : "(Ljava.lang.String;)V", false); - if (ctor == null) + catch (Exception e) { - Tracer.Error(Tracer.Runtime, $"{nameof(LibJvm)}.{nameof(IKVM_ThrowException)}: Exception {{0}} missing constructor.", name); - return; + Tracer.Error(Tracer.Runtime, $"{nameof(LibJvm)}.{nameof(JVM_ThrowException)}: Exception occurred creating exception {{0}}: {{1}}", name, e.Message); + JVM.SetPendingException(e); } + } - // invoke the constructor - exceptionClass.Finish(); - + /// + /// Invoked by the native code to get an event handle to wait on for thread interruption. + /// + /// + nint JVM_GetThreadInterruptEvent() + { try { - var ctorMember = (java.lang.reflect.Constructor)ctor.ToMethodOrConstructor(false); - var exception = (Exception)ctorMember.newInstance(msg == null ? Array.Empty() : new object[] { msg }, callerID); - Tracer.Verbose(Tracer.Runtime, $"{nameof(LibJvm)}.{nameof(IKVM_ThrowException)}: Created exception {{0}} from libjvm.", name); - JVM.SetPendingException(exception); + return global::java.lang.Thread.currentThread().interruptEvent.SafeWaitHandle.DangerousGetHandle(); } catch (Exception e) { - Tracer.Error(Tracer.Runtime, $"{nameof(LibJvm)}.{nameof(IKVM_ThrowException)}: Exception occurred creating exception {{0}}: {{1}}", name, e.Message); + Tracer.Error(Tracer.Runtime, $"{nameof(LibJvm)}.{nameof(JVM_GetThreadInterruptEvent)}: Exception occurred: {{0}}", e.Message); JVM.SetPendingException(e); + return 0; } } + /// + /// Invoked by the native code to get the active number of processors. + /// + /// + int JVM_ActiveProcessorCount() + { + return Environment.ProcessorCount; + } + /// /// Invokes the 'JVM_LoadLibrary' method from libjvm. /// @@ -212,8 +241,17 @@ public nint JVM_FindLibraryEntry(nint handle, string name) } } + /// + /// Finalizes the instance. + /// + ~LibJvm() + { + if (jvmii != null) + Marshal.FreeHGlobal((IntPtr)jvmii); + } + } #endif -} +} \ No newline at end of file diff --git a/src/IKVM.Runtime/MemberFlags.cs b/src/IKVM.Runtime/MemberFlags.cs index 77efa0609f..78c395b3c1 100644 --- a/src/IKVM.Runtime/MemberFlags.cs +++ b/src/IKVM.Runtime/MemberFlags.cs @@ -26,23 +26,58 @@ Jeroen Frijters namespace IKVM.Runtime { + /// + /// Describes various options applied to a member. + /// [Flags] enum MemberFlags : short { None = 0, + + /// + /// Member should be hidden from Java reflection. + /// HideFromReflection = 1, + ExplicitOverride = 2, + + /// + /// Member is a Java miranda method. + /// MirandaMethod = 8, + AccessStub = 16, - InternalAccess = 32, // member has "internal" access (@ikvm.lang.Internal) + + /// + /// Member should be generated with "internal" .NET access. + /// + InternalAccess = 32, + + /// + /// Method represents a property accessor. + /// PropertyAccessor = 64, + Intrinsic = 128, + CallerID = 256, + NonPublicTypeInSignature = 512, // this flag is only available after linking and is not set for access stubs + DelegateInvokeWithByRefParameter = 1024, + Type2FinalField = 2048, - NoOp = 4096, // empty static initializer + + /// + /// Member is an empty static initializer. + /// + NoOp = 4096, + + /// + /// Member is a module initializer method. + /// + ModuleInitializer = 8192, } diff --git a/src/IKVM.Runtime/RuntimeAssemblyClassLoader.cs b/src/IKVM.Runtime/RuntimeAssemblyClassLoader.cs index 0fc236e1d0..49caa624f9 100644 --- a/src/IKVM.Runtime/RuntimeAssemblyClassLoader.cs +++ b/src/IKVM.Runtime/RuntimeAssemblyClassLoader.cs @@ -497,7 +497,7 @@ void DoInitializeExports() { if (delegates == null) { - if (!ReflectUtil.IsDynamicAssembly(assemblyLoader.Assembly) && assemblyLoader.Assembly.GetManifestResourceInfo("ikvm.exports") != null) + if (ReflectUtil.IsDynamicAssembly(assemblyLoader.Assembly) == false && assemblyLoader.Assembly.GetManifestResourceInfo("ikvm.exports") != null) { var wildcardExports = new List(); @@ -521,27 +521,25 @@ void DoInitializeExports() for (int j = 0; j < typeCount; j++) { int hash = rdr.ReadInt32(); - if (!exports.TryGetValue(hash, out List assemblies)) + if (exports.TryGetValue(hash, out List assemblies) == false) { assemblies = new List(); exports.Add(hash, assemblies); } + assemblies.Add(i); } } } - if (references == null) - references = wildcardExports.ToArray(); + references ??= wildcardExports.ToArray(); } else { - AssemblyName[] refNames = assemblyLoader.Assembly.GetReferencedAssemblies(); + var refNames = assemblyLoader.Assembly.GetReferencedAssemblies(); references = new string[refNames.Length]; for (int i = 0; i < references.Length; i++) - { references[i] = refNames[i].FullName; - } } Interlocked.Exchange(ref delegates, new RuntimeAssemblyClassLoader[references.Length]); @@ -925,12 +923,14 @@ static java.net.URL MakeResourceURL(Assembly asm, string name) loader = exportedAssemblies[index] = GetLoaderForExportedAssembly(asm); } + urls = loader.FindResources(unmangledName); while (urls.hasMoreElements()) { found = true; yield return (java.net.URL)urls.nextElement(); } + if (loader.Assembly.GetManifestResourceInfo(name) != null) { found = true; @@ -940,15 +940,13 @@ static java.net.URL MakeResourceURL(Assembly asm, string name) } // if asked for a '.class' resource, we can return the appropriate stub - if (!found && unmangledName.EndsWith(".class", StringComparison.Ordinal) && unmangledName.IndexOf('.') == unmangledName.Length - 6) + if (found == false && unmangledName.EndsWith(".class", StringComparison.Ordinal) && unmangledName.IndexOf('.') == unmangledName.Length - 6) { var tw = FindLoadedClass(unmangledName.Substring(0, unmangledName.Length - 6).Replace('/', '.')); if (tw != null && tw.GetClassLoader() == this && !tw.IsArray && !tw.IsDynamic) yield return new java.io.File(Path.Combine(VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, assemblyLoader.Assembly, JVM.Properties.HomePath), unmangledName)).toURI().toURL(); } - #endif - } protected struct Resource diff --git a/src/IKVM.Runtime/RuntimeByteCodeJavaType.JavaTypeImpl.cs b/src/IKVM.Runtime/RuntimeByteCodeJavaType.JavaTypeImpl.cs index 4ce41775db..29dd44b081 100644 --- a/src/IKVM.Runtime/RuntimeByteCodeJavaType.JavaTypeImpl.cs +++ b/src/IKVM.Runtime/RuntimeByteCodeJavaType.JavaTypeImpl.cs @@ -108,10 +108,16 @@ internal void CreateStep1() if (m.IsInternal) flags |= MemberFlags.InternalAccess; + #if IMPORTER if (m.IsCallerSensitive && SupportsCallerID(m)) flags |= MemberFlags.CallerID; + + // set as module initializer + if (m.IsModuleInitializer) + flags |= MemberFlags.ModuleInitializer; #endif + if (wrapper.IsGhost && m.IsVirtual) { // note that a GhostMethodWrapper can also represent a default interface method @@ -193,8 +199,7 @@ internal void CreateStep1() bool SupportsCallerID(ClassFile.Method method) { - if ((classFile.Name == "sun.reflect.Reflection" && method.Name == "getCallerClass") - || (classFile.Name == "java.lang.SecurityManager" && method.Name == "checkMemberAccess")) + if ((classFile.Name == "sun.reflect.Reflection" && method.Name == "getCallerClass") || (classFile.Name == "java.lang.SecurityManager" && method.Name == "checkMemberAccess")) { // ignore CallerSensitive on methods that don't need CallerID parameter return false; @@ -203,9 +208,7 @@ bool SupportsCallerID(ClassFile.Method method) { return true; } - else if ((classFile.IsFinal || classFile.Name == "java.lang.Runtime" || classFile.Name == "java.io.ObjectStreamClass") - && wrapper.BaseTypeWrapper.GetMethodWrapper(method.Name, method.Signature, true) == null - && !HasInterfaceMethod(wrapper, method.Name, method.Signature)) + else if ((classFile.IsFinal || classFile.Name == "java.lang.Runtime" || classFile.Name == "java.io.ObjectStreamClass") && wrapper.BaseTypeWrapper.GetMethodWrapper(method.Name, method.Signature, true) == null && !HasInterfaceMethod(wrapper, method.Name, method.Signature)) { // We only support CallerID instance methods on final or effectively final types, // because we don't support interface stubs with CallerID. @@ -231,7 +234,7 @@ static bool HasInterfaceMethod(RuntimeJavaType tw, string name, string signature { for (; tw != null; tw = tw.BaseTypeWrapper) { - foreach (RuntimeJavaType iface in tw.Interfaces) + foreach (var iface in tw.Interfaces) { if (iface.GetMethodWrapper(name, signature, false) != null) { @@ -243,6 +246,7 @@ static bool HasInterfaceMethod(RuntimeJavaType tw, string name, string signature } } } + return false; } #endif @@ -259,26 +263,23 @@ internal void CreateStep2() return; } #endif + // this method is not allowed to throw exceptions (if it does, the runtime will abort) var hasclinit = wrapper.HasStaticInitializer; var mangledTypeName = wrapper.classLoader.GetTypeWrapperFactory().AllocMangledName(wrapper); var f = classFile; + try { TypeAttributes typeAttribs = 0; if (f.IsAbstract) - { typeAttribs |= TypeAttributes.Abstract; - } if (f.IsFinal) - { typeAttribs |= TypeAttributes.Sealed; - } if (!hasclinit) - { typeAttribs |= TypeAttributes.BeforeFieldInit; - } #if IMPORTER + bool cantNest = false; bool setModifiers = false; TypeBuilder enclosing = null; @@ -295,6 +296,7 @@ internal void CreateStep2() { enclosingClassName = f.EnclosingMethod[0]; } + if (enclosingClassName != null) { if (!CheckInnerOuterNames(f.Name, enclosingClassName)) @@ -311,24 +313,25 @@ internal void CreateStep2() { Tracer.Warning(Tracer.Compiler, "Unable to load outer class {0} for inner class {1} ({2}: {3})", enclosingClassName, f.Name, x.GetType().Name, x.Message); } + if (enclosingClassWrapper != null) { // make sure the relationship is reciprocal (otherwise we run the risk of // baking the outer type before the inner type) and that the inner and outer // class live in the same class loader (when doing a multi target compilation, // it is possible to split the two classes across assemblies) - JavaTypeImpl oimpl = enclosingClassWrapper.impl as JavaTypeImpl; + var oimpl = enclosingClassWrapper.impl as JavaTypeImpl; if (oimpl != null && enclosingClassWrapper.GetClassLoader() == wrapper.GetClassLoader()) { - ClassFile outerClassFile = oimpl.classFile; - ClassFile.InnerClass[] outerInnerClasses = outerClassFile.InnerClasses; + var outerClassFile = oimpl.classFile; + var outerInnerClasses = outerClassFile.InnerClasses; if (outerInnerClasses == null) { enclosingClassWrapper = null; } else { - bool ok = false; + var ok = false; for (int i = 0; i < outerInnerClasses.Length; i++) { if (((outerInnerClasses[i].outerClass != 0 && outerClassFile.GetConstantPoolClass(outerInnerClasses[i].outerClass) == outerClassFile.Name) @@ -340,6 +343,7 @@ internal void CreateStep2() break; } } + if (!ok) { enclosingClassWrapper = null; @@ -350,6 +354,7 @@ internal void CreateStep2() { enclosingClassWrapper = null; } + if (enclosingClassWrapper != null) { enclosingClassWrapper.CreateStep2(); @@ -367,6 +372,7 @@ internal void CreateStep2() } } } + if (f.IsPublic) { if (enclosing != null) @@ -414,6 +420,7 @@ internal void CreateStep2() // as inner classes throw new NotImplementedException(); } + // LAMESPEC the CLI spec says interfaces cannot contain nested types (Part.II, 9.6), but that rule isn't enforced // (and broken by J# as well), so we'll just ignore it too. typeBuilder = enclosing.DefineNestedType(AllocNestedTypeName(enclosingClassWrapper.Name, f.Name), typeAttribs); @@ -453,10 +460,12 @@ internal void CreateStep2() typeBuilder = wrapper.classLoader.GetTypeWrapperFactory().ModuleBuilder.DefineType(mangledTypeName, typeAttribs); } } + #if IMPORTER // When we're statically compiling, we associate the typeBuilder with the wrapper. This enables types in referenced assemblies to refer back to // types that we're currently compiling (i.e. a cyclic dependency between the currently assembly we're compiling and a referenced assembly). wrapper.Context.ClassLoaderFactory.SetWrapperForType(typeBuilder, wrapper); + if (outerClass.outerClass != 0) { if (enclosing != null && cantNest) @@ -468,44 +477,54 @@ internal void CreateStep2() wrapper.Context.AttributeHelper.SetNonNestedOuterClass(typeBuilder, enclosingClassName); } } + if (classFile.InnerClasses != null) { - foreach (ClassFile.InnerClass inner in classFile.InnerClasses) + foreach (var inner in classFile.InnerClasses) { - string name = classFile.GetConstantPoolClass(inner.innerClass); - bool exists = false; + var name = classFile.GetConstantPoolClass(inner.innerClass); + var exists = false; + try { exists = wrapper.GetClassLoader().TryLoadClassByName(name) != null; } - catch (RetargetableJavaException) { } + catch (RetargetableJavaException) + { + + } + if (!exists) { wrapper.Context.AttributeHelper.SetNonNestedInnerClass(typeBuilder, name); } } } - if (typeBuilder.FullName != wrapper.Name - && wrapper.Name.Replace('$', '+') != typeBuilder.FullName) + + if (typeBuilder.FullName != wrapper.Name && wrapper.Name.Replace('$', '+') != typeBuilder.FullName) { wrapper.classLoader.AddNameMapping(wrapper.Name, typeBuilder.FullName); } + if (f.IsAnnotation && Annotation.HasRetentionPolicyRuntime(f.Annotations)) { annotationBuilder = new AnnotationBuilder(wrapper.Context, this, enclosing); wrapper.SetAnnotation(annotationBuilder); } + // For Java 5 Enum types, we generate a nested .NET enum. // This is primarily to support annotations that take enum parameters. if (f.IsEnum && f.IsPublic) { AddCliEnum(); } + AddInnerClassAttribute(enclosing != null, outerClass.innerClass != 0, mangledTypeName, outerClass.accessFlags); if (classFile.DeprecatedAttribute && !Annotation.HasObsoleteAttribute(classFile.Annotations)) { wrapper.Context.AttributeHelper.SetDeprecatedAttribute(typeBuilder); } + if (classFile.GenericSignature != null) { wrapper.Context.AttributeHelper.SetSignatureAttribute(typeBuilder, classFile.GenericSignature); @@ -2358,16 +2377,18 @@ MethodAttributes GetPropertyAccess(RuntimeJavaMethod mw) internal override MethodBase LinkMethod(RuntimeJavaMethod mw) { Debug.Assert(mw != null); + if (mw is DelegateConstructorMethodWrapper dcmw) { dcmw.DoLink(typeBuilder); return null; } - if (mw is DelegateInvokeStubMethodWrapper) + if (mw is DelegateInvokeStubMethodWrapper stub) { - return ((DelegateInvokeStubMethodWrapper)mw).DoLink(typeBuilder); + return stub.DoLink(typeBuilder); } + if (mw.IsClassInitializer && mw.IsNoOp && (!wrapper.IsSerializable || HasSerialVersionUID)) { // we don't need to emit the , because it is empty and we're not serializable or have an explicit serialVersionUID @@ -2375,30 +2396,38 @@ internal override MethodBase LinkMethod(RuntimeJavaMethod mw) // we cannot do this optimization if the class is serializable but doesn't have a serialVersionUID) return null; } + int index = GetMethodIndex(mw); if (baseMethods[index] != null) { - foreach (RuntimeJavaMethod baseMethod in baseMethods[index]) + foreach (var baseMethod in baseMethods[index]) { baseMethod.Link(); CheckLoaderConstraints(mw, baseMethod); } } + Debug.Assert(mw.GetMethod() == null); methods[index].AssertLinked(); Profiler.Enter("JavaTypeImpl.GenerateMethod"); + try { + // index is outside the range of methods declared on class file if (index >= classFile.Methods.Length) { + // method is a miranda method if (methods[index].IsMirandaMethod) { - // We're a Miranda method or we're an inherited default interface method + // we're a Miranda method or we're an inherited default interface method Debug.Assert(baseMethods[index].Length == 1 && baseMethods[index][0].DeclaringType.IsInterface); - RuntimeMirandaJavaMethod mmw = (RuntimeMirandaJavaMethod)methods[index]; - MethodAttributes attr = MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.CheckAccessOnOverride; + + var mmw = (RuntimeMirandaJavaMethod)methods[index]; + var attr = MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.CheckAccessOnOverride; + RuntimeJavaMethod baseMiranda = null; bool baseMirandaOverrideStub = false; + if (wrapper.BaseTypeWrapper == null || (baseMiranda = wrapper.BaseTypeWrapper.GetMethodWrapper(mw.Name, mw.Signature, true)) == null || !baseMiranda.IsMirandaMethod) { // we're not overriding a miranda method in a base class, so can we set the newslot flag @@ -2413,20 +2442,24 @@ internal override MethodBase LinkMethod(RuntimeJavaMethod mw) attr |= MethodAttributes.NewSlot; } } + if (wrapper.IsInterface || (wrapper.IsAbstract && mmw.BaseMethod.IsAbstract && mmw.Error == null)) { attr |= MethodAttributes.Abstract; } - MethodBuilder mb = methods[index].GetDefineMethodHelper().DefineMethod(wrapper, typeBuilder, methods[index].Name, attr); + + var mb = methods[index].GetDefineMethodHelper().DefineMethod(wrapper, typeBuilder, methods[index].Name, attr); wrapper.Context.AttributeHelper.HideFromReflection(mb); + if (baseMirandaOverrideStub) { wrapper.GenerateOverrideStub(typeBuilder, baseMiranda, mb, methods[index]); } + if ((!wrapper.IsAbstract && mmw.BaseMethod.IsAbstract) || (!wrapper.IsInterface && mmw.Error != null)) { - string message = mmw.Error ?? (wrapper.Name + "." + methods[index].Name + methods[index].Signature); - CodeEmitter ilgen = wrapper.Context.CodeEmitterFactory.Create(mb); + var message = mmw.Error ?? (wrapper.Name + "." + methods[index].Name + methods[index].Signature); + var ilgen = wrapper.Context.CodeEmitterFactory.Create(mb); ilgen.EmitThrow(mmw.IsConflictError ? "java.lang.IncompatibleClassChangeError" : "java.lang.AbstractMethodError", message); ilgen.DoEmit(); wrapper.EmitLevel4Warning(mmw.IsConflictError ? HardError.IncompatibleClassChangeError : HardError.AbstractMethodError, message); @@ -2434,7 +2467,7 @@ internal override MethodBase LinkMethod(RuntimeJavaMethod mw) #if IMPORTER if (wrapper.IsInterface && !mmw.IsAbstract) { - // even though we're not visible to reflection., we need to record the fact that we have a default implementation + // even though we're not visible to reflection we need to record the fact that we have a default implementation wrapper.Context.AttributeHelper.SetModifiers(mb, mmw.Modifiers, false); } #endif @@ -2445,23 +2478,25 @@ internal override MethodBase LinkMethod(RuntimeJavaMethod mw) throw new InvalidOperationException(); } } - ClassFile.Method m = classFile.Methods[index]; + + var m = classFile.Methods[index]; MethodBuilder method; bool setModifiers = false; + if (methods[index].HasCallerID && (m.Modifiers & Modifiers.VarArgs) != 0) { // the implicit callerID parameter was added at the end so that means we shouldn't use ParamArrayAttribute, // so we need to explicitly record that the method is varargs setModifiers = true; } + if (m.IsConstructor) { method = GenerateConstructor(methods[index]); + // strictfp is the only modifier that a constructor can have if (m.IsStrictfp) - { setModifiers = true; - } } else if (m.IsClassInitializer) { @@ -2471,30 +2506,36 @@ internal override MethodBase LinkMethod(RuntimeJavaMethod mw) { method = GenerateMethod(index, m, ref setModifiers); } - string[] exceptions = m.ExceptionsAttribute; + + // apply 'throws' Exceptions as attributes + var exceptions = m.ExceptionsAttribute; methods[index].SetDeclaredExceptions(exceptions); + #if IMPORTER wrapper.Context.AttributeHelper.SetThrowsAttribute(method, exceptions); + if (setModifiers || m.IsInternal || (m.Modifiers & (Modifiers.Synthetic | Modifiers.Bridge)) != 0) - { wrapper.Context.AttributeHelper.SetModifiers(method, m.Modifiers, m.IsInternal); - } - if ((m.Modifiers & (Modifiers.Synthetic | Modifiers.Bridge)) != 0 - && (m.IsPublic || m.IsProtected) - && wrapper.IsPublic - && !IsAccessBridge(classFile, m)) + + // synthetic and bridge methods should not be visible to the user and set as compiler generated + if ((m.Modifiers & (Modifiers.Synthetic | Modifiers.Bridge)) != 0 && (m.IsPublic || m.IsProtected) && wrapper.IsPublic && !IsAccessBridge(classFile, m)) { + wrapper.Context.AttributeHelper.SetCompilerGenerated(method); wrapper.Context.AttributeHelper.SetEditorBrowsableNever(method); - // TODO on WHIDBEY apply CompilerGeneratedAttribute } + + // ensure deprecated attribute appears on method if obsolete not specified if (m.DeprecatedAttribute && !Annotation.HasObsoleteAttribute(m.Annotations)) { wrapper.Context.AttributeHelper.SetDeprecatedAttribute(method); } + + // apply .NET attribute to record Java generic signature if (m.GenericSignature != null) { wrapper.Context.AttributeHelper.SetSignatureAttribute(method, m.GenericSignature); } + if (wrapper.GetClassLoader().NoParameterReflection) { // ignore MethodParameters (except to extract parameter names) @@ -2505,23 +2546,28 @@ internal override MethodBase LinkMethod(RuntimeJavaMethod mw) } else if (m.MethodParameters != null) { - Modifiers[] modifiers = new Modifiers[m.MethodParameters.Length]; + var modifiers = new Modifiers[m.MethodParameters.Length]; for (int i = 0; i < modifiers.Length; i++) - { modifiers[i] = (Modifiers)m.MethodParameters[i].accessFlags; - } + wrapper.Context.AttributeHelper.SetMethodParametersAttribute(method, modifiers); } + + // copy runtime visible annotations as attributes if (m.RuntimeVisibleTypeAnnotations != null) { wrapper.Context.AttributeHelper.SetRuntimeVisibleTypeAnnotationsAttribute(method, m.RuntimeVisibleTypeAnnotations); } + #else // IMPORTER + if (setModifiers) { // shut up the compiler } + #endif // IMPORTER + return method; } finally diff --git a/src/IKVM.Runtime/RuntimeJavaField.cs b/src/IKVM.Runtime/RuntimeJavaField.cs index 4f9e945b78..5bb28744f8 100644 --- a/src/IKVM.Runtime/RuntimeJavaField.cs +++ b/src/IKVM.Runtime/RuntimeJavaField.cs @@ -74,14 +74,14 @@ internal RuntimeJavaField(RuntimeJavaType declaringType, RuntimeJavaType fieldTy UpdateNonPublicTypeInSignatureFlag(); #if IMPORTER - if (IsFinal - && DeclaringType.IsPublic - && !DeclaringType.IsInterface - && (IsPublic || (IsProtected && !DeclaringType.IsFinal)) - && !DeclaringType.GetClassLoader().StrictFinalFieldSemantics - && DeclaringType.IsDynamic - && this is not RuntimeConstantJavaField - && this is not RuntimeByteCodePropertyJavaField) + if (IsFinal && + DeclaringType.IsPublic && + !DeclaringType.IsInterface && + (IsPublic || (IsProtected && !DeclaringType.IsFinal)) && + !DeclaringType.GetClassLoader().StrictFinalFieldSemantics && + DeclaringType.IsDynamic && + this is not RuntimeConstantJavaField && + this is not RuntimeByteCodePropertyJavaField) { SetType2FinalField(); } diff --git a/src/IKVM.Runtime/RuntimeJavaMember.cs b/src/IKVM.Runtime/RuntimeJavaMember.cs index c786462d92..b71f31ab49 100644 --- a/src/IKVM.Runtime/RuntimeJavaMember.cs +++ b/src/IKVM.Runtime/RuntimeJavaMember.cs @@ -42,30 +42,56 @@ namespace IKVM.Runtime abstract class RuntimeJavaMember { - readonly RuntimeJavaType declaringType; - readonly string name; - readonly string sig; - protected readonly Modifiers modifiers; - HandleWrapper handle; - MemberFlags flags; - - sealed class HandleWrapper + /// + /// Holds a for the member and ensures it is released on finalization. + /// + class HandleManager { - internal readonly IntPtr Value; + /// + /// Gets the associated with the specified cookie. + /// + /// + /// + public static RuntimeJavaMember FromCookie(IntPtr cookie) + { + return (RuntimeJavaMember)GCHandle.FromIntPtr(cookie).Target; + } + + GCHandle handle; /// /// Initializes a new instance. /// - /// - [System.Security.SecurityCritical] - internal HandleWrapper(RuntimeJavaMember obj) + /// + public HandleManager(RuntimeJavaMember member) { - Value = (IntPtr)GCHandle.Alloc(obj, GCHandleType.WeakTrackResurrection); + handle = GCHandle.Alloc(member, GCHandleType.WeakTrackResurrection); + } + + /// + /// Gets the value. + /// + public IntPtr Cookie => GCHandle.ToIntPtr(handle); + + /// + /// Disposes of the handle. + /// + ~HandleManager() + { + handle.Free(); } } + readonly RuntimeJavaType declaringType; + readonly string name; + readonly string sig; + protected readonly Modifiers modifiers; + MemberFlags flags; + + HandleManager handle; + /// /// Initializes a new instance. /// @@ -84,21 +110,30 @@ protected RuntimeJavaMember(RuntimeJavaType declaringType, string name, string s this.flags = flags; } + /// + /// Gets the cookie for this member. A cookie is a unique platform sized pointer that can be resolved to the member info. + /// internal nint Cookie { get { + // synchronize the creation of a handle lock (this) - handle ??= new HandleWrapper(this); + handle ??= new HandleManager(this); - return handle.Value; + return handle.Cookie; } } + /// + /// Finds the represented by the specied cookie. + /// + /// + /// [System.Security.SecurityCritical] internal static RuntimeJavaMember FromCookieImpl(nint cookie) { - return (RuntimeJavaMember)GCHandle.FromIntPtr(cookie).Target; + return (RuntimeJavaMember)HandleManager.FromCookie(cookie); } internal RuntimeJavaType DeclaringType => declaringType; @@ -217,6 +252,11 @@ protected void SetType2FinalField() internal bool IsFinal => (modifiers & Modifiers.Final) != 0; + /// + /// Gets whether or not this method is marked as a module initializer. + /// + internal bool IsModuleInitializer => IsStatic && IsPrivate == false && (flags & MemberFlags.ModuleInitializer) != 0; + } } diff --git a/src/IKVM.Runtime/RuntimeJavaMethod.cs b/src/IKVM.Runtime/RuntimeJavaMethod.cs index 882a49d12a..14e5d49e1e 100644 --- a/src/IKVM.Runtime/RuntimeJavaMethod.cs +++ b/src/IKVM.Runtime/RuntimeJavaMethod.cs @@ -132,15 +132,19 @@ void UpdateNonPublicTypeInSignatureFlag() } } + /// + /// Sets the declared exceptions for the method. + /// + /// internal void SetDeclaredExceptions(string[] exceptions) { - if (exceptions == null) - { - exceptions = new string[0]; - } - this.declaredExceptions = (string[])exceptions.Clone(); + declaredExceptions = exceptions != null && exceptions.Length > 0 ? (string[])exceptions.Clone() : Array.Empty(); } - + + /// + /// Gest the declared exceptions for the method. + /// + /// internal string[] GetDeclaredExceptions() { return declaredExceptions; @@ -269,6 +273,11 @@ internal static RuntimeJavaMethod FromExecutable(java.lang.reflect.Executable ex } #endif // !IMPORTER && !EXPORTER + /// + /// Finds the represented by the specified cookie. + /// + /// + /// [System.Security.SecurityCritical] internal static RuntimeJavaMethod FromCookie(IntPtr cookie) { diff --git a/src/IKVM.Runtime/RuntimeJavaType.cs b/src/IKVM.Runtime/RuntimeJavaType.cs index b57ea603f8..c79d8cabdc 100644 --- a/src/IKVM.Runtime/RuntimeJavaType.cs +++ b/src/IKVM.Runtime/RuntimeJavaType.cs @@ -828,12 +828,13 @@ internal RuntimeJavaMethod GetMethodWrapper(string name, string sig, bool inheri internal RuntimeJavaMethod GetInterfaceMethod(string name, string sig) { - RuntimeJavaMethod method = GetMethodWrapper(name, sig, false); + var method = GetMethodWrapper(name, sig, false); if (method != null) { return method; } - RuntimeJavaType[] interfaces = Interfaces; + + var interfaces = Interfaces; for (int i = 0; i < interfaces.Length; i++) { method = interfaces[i].GetInterfaceMethod(name, sig); @@ -842,6 +843,7 @@ internal RuntimeJavaMethod GetInterfaceMethod(string name, string sig) return method; } } + return null; } diff --git a/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj b/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj index 7dba38c7bf..31684710cb 100644 --- a/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj +++ b/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj @@ -5,7 +5,8 @@ - + + diff --git a/src/IKVM.Tests/IKVM.Tests.csproj b/src/IKVM.Tests/IKVM.Tests.csproj index 938fabc25d..b3abc32aec 100644 --- a/src/IKVM.Tests/IKVM.Tests.csproj +++ b/src/IKVM.Tests/IKVM.Tests.csproj @@ -1,4 +1,8 @@ - + + + + + net472;net6.0;net7.0;net8.0 true @@ -44,7 +48,7 @@ - <_ReferencedClangProjects Include="$(MSBuildThisFileDirectory)..\libikvm-tests\libikvm-tests.clangproj " /> + @@ -190,4 +194,8 @@ + + + + diff --git a/src/IKVM.Tests/Java/com/sun/management/OperatingSystemMXBeanTests.cs b/src/IKVM.Tests/Java/com/sun/management/OperatingSystemMXBeanTests.cs index 2070ea0925..3fd78161de 100644 --- a/src/IKVM.Tests/Java/com/sun/management/OperatingSystemMXBeanTests.cs +++ b/src/IKVM.Tests/Java/com/sun/management/OperatingSystemMXBeanTests.cs @@ -30,67 +30,49 @@ public void CanGetAvailableProcessors() [TestMethod] public void CanGetProcessCpuLoad() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - mbean.getProcessCpuLoad().Should().Be(-1); + mbean.getProcessCpuLoad().Should().BeGreaterThanOrEqualTo(0); } [TestMethod] public void CanGetProcessCpuTime() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - mbean.getProcessCpuTime().Should().BeGreaterOrEqualTo(1); + mbean.getProcessCpuTime().Should().BeGreaterOrEqualTo(0); } [TestMethod] public void CanGetSystemLoadAverage() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - mbean.getProcessCpuLoad().Should().Be(-1); + mbean.getProcessCpuLoad().Should().BeGreaterOrEqualTo(0); } [TestMethod] public void CanGetTotalPhysicalMemorySize() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - return; - - mbean.getTotalPhysicalMemorySize().Should().BeGreaterOrEqualTo(1); + mbean.getTotalPhysicalMemorySize().Should().BeGreaterOrEqualTo(0); } [TestMethod] public void CanGetFreePhysicalMemorySize() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - return; - - mbean.getFreePhysicalMemorySize().Should().BeGreaterOrEqualTo(1); + mbean.getFreePhysicalMemorySize().Should().BeGreaterOrEqualTo(0); } [TestMethod] public void CanGetTotalSwapSpaceSize() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - return; - - mbean.getTotalSwapSpaceSize().Should().BeGreaterOrEqualTo(1); + mbean.getTotalSwapSpaceSize().Should().BeGreaterOrEqualTo(0); } [TestMethod] public void CanGetFreeSwapSpaceSize() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - return; - - mbean.getFreeSwapSpaceSize().Should().BeGreaterOrEqualTo(1); + mbean.getFreeSwapSpaceSize().Should().BeGreaterOrEqualTo(0); } [TestMethod] public void CanGetCommittedVirtualMemorySize() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - return; - - mbean.getCommittedVirtualMemorySize().Should().BeGreaterOrEqualTo(1); + mbean.getCommittedVirtualMemorySize().Should().BeGreaterOrEqualTo(0); } } diff --git a/src/IKVM.Tests/Java/java/io/FileTests.cs b/src/IKVM.Tests/Java/java/io/FileTests.cs index 17dcfc461e..2b2b643a38 100644 --- a/src/IKVM.Tests/Java/java/io/FileTests.cs +++ b/src/IKVM.Tests/Java/java/io/FileTests.cs @@ -3,6 +3,11 @@ using FluentAssertions; +using IKVM.Runtime; +using IKVM.Runtime.Vfs; + +using java.io; + using Microsoft.VisualStudio.TestTools.UnitTesting; namespace IKVM.Tests.Java.java.io @@ -48,6 +53,16 @@ public void CanReadFile() r.close(); } + [TestMethod] + public void CanSetReadOnly() + { + var f = new global::java.io.File(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())); + f.createNewFile().Should().BeTrue(); + f.canWrite().Should().BeTrue(); + f.setReadOnly().Should().BeTrue(); + f.canWrite().Should().BeFalse(); + } + [TestMethod] public void ShouldRemoveDotFromCanonicalizedPath() { @@ -81,6 +96,40 @@ public void CanGetPathSeparator() global::java.io.File.pathSeparator.Should().Be(":"); } + [TestMethod] + public void VfsAssemblyClassesDirectoryShouldBeDirectory() + { + var d = VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, typeof(object).Assembly, JVM.Properties.HomePath); + new global::java.io.File(d).isDirectory().Should().BeTrue(); + } + + [TestMethod] + public void VfsAssemblyClassesDirectoryCanBeListed() + { + var d = VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, typeof(object).Assembly, JVM.Properties.HomePath); + var l = new global::java.io.File(d).list(); + foreach (var s in l) + System.Console.WriteLine(s); + } + + [TestMethod] + public void VfsAssemblyClassCanBeRead() + { + var f = System.IO.Path.Combine(VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, typeof(global::java.lang.Object).Assembly, JVM.Properties.HomePath), "java", "lang", "Class.class"); + var s = new global::java.io.FileInputStream(f); + var b = new byte[new global::java.io.File(f).length()]; + s.read(b); + b.Length.Should().BeGreaterOrEqualTo(32); + } + + [TestMethod] + [ExpectedException(typeof(global::java.io.FileNotFoundException))] + public void VfsAssemblyClassCanNotBeWritten() + { + var f = System.IO.Path.Combine(VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, typeof(global::java.lang.Object).Assembly, JVM.Properties.HomePath), "java", "lang", "Class.class"); + new global::java.io.FileOutputStream(f).write(0); + } + } } diff --git a/src/IKVM.Tests/Java/java/lang/ClassTests.cs b/src/IKVM.Tests/Java/java/lang/ClassTests.cs index e5e26d37ee..9cae216be5 100644 --- a/src/IKVM.Tests/Java/java/lang/ClassTests.cs +++ b/src/IKVM.Tests/Java/java/lang/ClassTests.cs @@ -39,7 +39,7 @@ public void CanGetMethodAndInvoke() public void CanSetFieldSetAccessibleOnBase() { var bcp = global::java.lang.System.getProperty("sun.boot.class.path").Split(global::java.io.File.pathSeparatorChar); - var all = bcp.SelectMany(i => EnumerateClassFiles(Paths.get(i))).ToList(); + var all = bcp.SelectMany(EnumerateClassFiles).ToList(); if (all.Count < 100) throw new Exception("Expected more classes."); @@ -49,7 +49,7 @@ public void CanSetFieldSetAccessibleOnBase() if (file.StartsWith("WrapperGenerator")) continue; - var c = global::java.lang.Class.forName(file.Replace('/', '.').Substring(0, file.Length - 6), false, null); + var c = global::java.lang.Class.forName(file.Replace(global::java.io.File.separator, ".").Substring(0, file.Length - 6), false, null); if (c == null) throw new Exception("Could not load BCP class by name."); @@ -64,19 +64,45 @@ public void CanSetFieldSetAccessibleOnBase() /// /// Returns an enumerable over all of the class files within the specified root path. /// + /// + /// + IEnumerable EnumerateClassFiles(string root) + { + return EnumerateClassFiles(root, null); + } + + /// + /// + /// + /// /// /// - IEnumerable EnumerateClassFiles(global::java.nio.file.Path path) + private IEnumerable EnumerateClassFiles(string root, string path) + { + foreach (var file in new global::java.io.File(JoinPath(root, path)).listFiles()) + { + if (file.isFile()) + yield return JoinPath(path, file.getName()); + else if (file.isDirectory()) + foreach (var i in EnumerateClassFiles(root, JoinPath(path, file.getName()))) + yield return i; + } + } + + /// + /// Combines two paths. + /// + /// + /// + /// + string JoinPath(string path1, string path2) { - var file = path.toFile(); - if (file.canRead() == false || file.isDirectory() == false) - return Enumerable.Empty(); - - return Files.walk(path) - .filter(new DelegatePredicate(p => p.getFileName().toString().EndsWith(".class"))) - .map(new DelegateFunction(p => path.relativize(p))) - .map(new DelegateFunction(p => p.toString().Replace(global::java.io.File.separatorChar, '/'))) - .AsEnumerable(); + if (path1 != null && path2 != null) + return path1 + global::java.io.File.separator + path2; + else if (path1 != null) + return path1; + else + return path2; } } diff --git a/src/IKVM.Tests/Java/java/nio/channels/AsynchronousFileChannelTests.cs b/src/IKVM.Tests/Java/java/nio/channels/AsynchronousFileChannelTests.cs index b1331e3067..48910c4122 100644 --- a/src/IKVM.Tests/Java/java/nio/channels/AsynchronousFileChannelTests.cs +++ b/src/IKVM.Tests/Java/java/nio/channels/AsynchronousFileChannelTests.cs @@ -426,37 +426,6 @@ void OnFailed(System.Exception e) throw new System.Exception("", o); } - /// - /// Check that the asynchronous APIs can read from the VFS. - /// - /// - [TestMethod] - public async Task CanReadVfsAssemblyClass() - { - var f = new File(System.IO.Path.Combine(VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, typeof(global::java.lang.Object).Assembly, JVM.Properties.HomePath), "java", "lang", "Object.class")); - - using var c = AsynchronousFileChannel.open(f.toPath(), StandardOpenOption.READ); - var b = ByteBuffer.allocate(512); - b.capacity().Should().Be(512); - b.position().Should().Be(0); - b.limit().Should().Be(512); - - var h = new AwaitableCompletionHandler(); - c.read(b, 0, null, h); - var n = await h; - n.intValue().Should().Be(512); - c.close(); - - b.position().Should().Be(512); - b.flip(); - b.capacity().Should().Be(512); - b.position().Should().Be(0); - b.limit().Should().Be(512); - b.order(ByteOrder.BIG_ENDIAN); - var m = b.getInt(); - m.Should().Be(unchecked((int)0xCAFEBABE)); - } - [TestMethod] public void ShouldThrowClosedChannelExceptionOnRead() { diff --git a/src/IKVM.Tests/Java/java/nio/file/FilesTests.cs b/src/IKVM.Tests/Java/java/nio/file/FilesTests.cs index 2fd882169c..0393581e24 100644 --- a/src/IKVM.Tests/Java/java/nio/file/FilesTests.cs +++ b/src/IKVM.Tests/Java/java/nio/file/FilesTests.cs @@ -55,54 +55,6 @@ public void CanGetIsDirectory() Files.isDirectory(Paths.get(f)).Should().Be(false); } - [TestMethod] - public void VfsAssemblyClassesDirectoryShouldBeDirectory() - { - var d = VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, typeof(object).Assembly, JVM.Properties.HomePath); - Files.isDirectory(Paths.get(d)).Should().Be(true); - } - - [TestMethod] - public void VfsAssemblyClassesDirectoryCanBeListed() - { - var d = VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, typeof(object).Assembly, JVM.Properties.HomePath); - var l = Files.list(Paths.get(d)).toArray(); - foreach (Path s in l) - System.Console.WriteLine(s); - } - - [TestMethod] - public void VfsAssemblyClassCanBeRead() - { - var f = System.IO.Path.Combine(VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, typeof(global::java.lang.Object).Assembly, JVM.Properties.HomePath), "java", "lang", "Class.class"); - var b = Files.readAllBytes(Paths.get(f)); - b.Length.Should().BeGreaterOrEqualTo(32); - } - - [TestMethod] - [ExpectedException(typeof(global::java.nio.file.AccessDeniedException))] - public void VfsAssemblyClassCanNotBeWritten() - { - var f = System.IO.Path.Combine(VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, typeof(global::java.lang.Object).Assembly, JVM.Properties.HomePath), "java", "lang", "Class.class"); - Files.write(Paths.get(f), new byte[] { 1 }); - } - - [TestMethod] - public void VfsAssemblyClassesDirectoryShouldHaveBasicAttributes() - { - var f = VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, typeof(global::java.lang.Object).Assembly, JVM.Properties.HomePath); - var a = (BasicFileAttributes)Files.readAttributes(Paths.get(f), typeof(BasicFileAttributes)); - a.isDirectory().Should().BeTrue(); - } - - [TestMethod] - public void VfsAssemblyClassesDirectoryShouldBeWalkable() - { - var f = VfsTable.GetAssemblyClassesPath(JVM.Vfs.Context, typeof(global::java.lang.Object).Assembly, JVM.Properties.HomePath); - var l = Files.walk(Paths.get(f)).toArray(); - l.Count().Should().BeGreaterOrEqualTo(16); - } - [TestMethod] public void CanPerformMoveReplace() { diff --git a/src/IKVM.Tests/Properties/launchSettings.json b/src/IKVM.Tests/Properties/launchSettings.json deleted file mode 100644 index c740c73dd4..0000000000 --- a/src/IKVM.Tests/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "IKVM.Tests": { - "commandName": "Project", - "nativeDebugging": true - } - } -} \ No newline at end of file diff --git a/src/IKVM.Tools.Importer.Tests/IKVM.Tools.Importer.Tests.csproj b/src/IKVM.Tools.Importer.Tests/IKVM.Tools.Importer.Tests.csproj index 3b136632f8..0c053aeccc 100644 --- a/src/IKVM.Tools.Importer.Tests/IKVM.Tools.Importer.Tests.csproj +++ b/src/IKVM.Tools.Importer.Tests/IKVM.Tools.Importer.Tests.csproj @@ -68,4 +68,4 @@ - \ No newline at end of file + diff --git a/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.cs b/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.cs index 079a690062..2dc40002ab 100644 --- a/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.cs +++ b/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.cs @@ -7,17 +7,11 @@ using FluentAssertions; +using IKVM.Java.Tests.Util; using IKVM.Tests.Util; using Microsoft.VisualStudio.TestTools.UnitTesting; -using IKVM.Java.Tests.Util; - - -#if NETCOREAPP -using Microsoft.Extensions.DependencyModel; -#endif - namespace IKVM.Tools.Importer.Tests { diff --git a/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.java b/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.java index 44cf77d204..1018764b00 100644 --- a/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.java +++ b/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.java @@ -1,10 +1,13 @@ package ikvm.tools.importer.tests; -public class IkvmImporterTests -{ +public class IkvmImporterTests { - public static String echo(String value) - { + @ikvm.lang.ModuleInitializer + static void Init() { + + } + + public static String echo(String value) { return value; } diff --git a/src/IKVM.Tools.Importer/CompilerClassLoader.cs b/src/IKVM.Tools.Importer/CompilerClassLoader.cs index 14c99ccb67..b4faafa6f1 100644 --- a/src/IKVM.Tools.Importer/CompilerClassLoader.cs +++ b/src/IKVM.Tools.Importer/CompilerClassLoader.cs @@ -26,6 +26,7 @@ Jeroen Frijters using System.Diagnostics; using System.IO; using System.IO.Compression; +using System.Linq; using System.Security; using System.Text; using System.Text.RegularExpressions; @@ -74,7 +75,7 @@ sealed class CompilerClassLoader : RuntimeClassLoader List internalsVisibleTo = new List(); List dynamicallyImportedTypes = new List(); List jarList = new List(); - List allwrappers; + List javaTypes; FakeTypes fakeTypes; /// @@ -361,6 +362,7 @@ private RuntimeJavaType GetTypeWrapperCompilerHook(string name) try { var tw = DefineClass(f, null); + // we successfully created the type, so we don't need to include the class as a resource if (options.nojarstubs) { @@ -370,12 +372,14 @@ private RuntimeJavaType GetTypeWrapperCompilerHook(string name) { itemRef.MarkAsStub(); } + int pos = f.Name.LastIndexOf('.'); if (pos != -1) { string manifestJar = options.IsClassesJar(itemRef.Jar) ? null : itemRef.Jar.Name; packages.DefinePackage(f.Name.Substring(0, pos), manifestJar); } + return tw; } catch (ClassFormatError x) @@ -396,12 +400,14 @@ private RuntimeJavaType GetTypeWrapperCompilerHook(string name) { Context.StaticCompiler.IssueMessage(options, Message.NoClassDefFoundError, name, x.Message); } + Context.StaticCompiler.IssueMessage(options, Message.ClassNotFound, x.Message); } catch (RetargetableJavaException x) { Context.StaticCompiler.IssueMessage(options, Message.GenericUnableToCompileError, name, x.GetType().Name, x.Message); } + Context.StaticCompiler.SuppressWarning(options, Message.ClassNotFound, name); return null; } @@ -2881,54 +2887,62 @@ void CompilePass1() fakeTypes.Create(GetTypeWrapperFactory().ModuleBuilder, this); } - allwrappers = new List(); + javaTypes = new List(); + foreach (var s in classesToCompile) { - var wrapper = TryLoadClassByName(s); - if (wrapper != null) + var javaType = TryLoadClassByName(s); + if (javaType != null) { - var loader = wrapper.GetClassLoader(); + var loader = javaType.GetClassLoader(); if (loader != this) { if (loader is RuntimeAssemblyClassLoader) - Context.StaticCompiler.IssueMessage(options, Message.SkippingReferencedClass, s, ((RuntimeAssemblyClassLoader)loader).GetAssembly(wrapper).FullName); + Context.StaticCompiler.IssueMessage(options, Message.SkippingReferencedClass, s, ((RuntimeAssemblyClassLoader)loader).GetAssembly(javaType).FullName); continue; } if (options.sharedclassloader != null && options.sharedclassloader[0] != this) - options.sharedclassloader[0].dynamicallyImportedTypes.Add(wrapper); + options.sharedclassloader[0].dynamicallyImportedTypes.Add(javaType); - allwrappers.Add(wrapper); + javaTypes.Add(javaType); } } } - private void CompilePass2() + void CompilePass2() { Tracer.Info(Tracer.Compiler, "Compiling class files (2)"); - foreach (RuntimeJavaType tw in allwrappers) + + foreach (var javaTypes in javaTypes) { - RuntimeByteCodeJavaType dtw = tw as RuntimeByteCodeJavaType; + var dtw = javaTypes as RuntimeByteCodeJavaType; if (dtw != null) - { dtw.CreateStep2(); - } } } - private int CompilePass3() + int CompilePass3() { Tracer.Info(Tracer.Compiler, "Compiling class files (3)"); + + // emits the IL required for module initialization + var moduleInitBuilders = new List>(); + + // bootstrap mode introduces fake types if (map != null && options.bootstrap) { fakeTypes.Finish(this); } + + // generate configured proxies foreach (string proxy in options.proxies) { Context.ProxyGenerator.Create(this, proxy); } + // set the main entry point to the main method of the specified class if (options.mainClass != null) { RuntimeJavaType wrapper = null; @@ -2970,10 +2984,12 @@ private int CompilePass3() SetMain(wrapper, options.target, options.props, options.noglobbing, apartmentAttributeType); } + // complete map if (map != null) { LoadMappedExceptions(map); Tracer.Info(Tracer.Compiler, "Loading remapped types (2)"); + try { FinishRemappedTypes(); @@ -2984,30 +3000,34 @@ private int CompilePass3() return 1; } } + Tracer.Info(Tracer.Compiler, "Compiling class files (2)"); WriteResources(); + // add external resources if (options.externalResources != null) foreach (KeyValuePair kv in options.externalResources) assemblyBuilder.AddResourceFile(JVM.MangleResourceName(kv.Key), kv.Value); + // configure Win32 file version if (options.fileversion != null) { - CustomAttributeBuilder filever = new CustomAttributeBuilder(Context.Resolver.ResolveCoreType(typeof(System.Reflection.AssemblyFileVersionAttribute).FullName).GetConstructor(new Type[] { Context.Types.String }), new object[] { options.fileversion }); + var filever = new CustomAttributeBuilder(Context.Resolver.ResolveCoreType(typeof(System.Reflection.AssemblyFileVersionAttribute).FullName).GetConstructor(new Type[] { Context.Types.String }), new object[] { options.fileversion }); assemblyBuilder.SetCustomAttribute(filever); } + + // apply assembly annotations if (options.assemblyAttributeAnnotations != null) { foreach (object[] def in options.assemblyAttributeAnnotations) { - Annotation annotation = Annotation.LoadAssemblyCustomAttribute(this, def); + var annotation = Annotation.LoadAssemblyCustomAttribute(this, def); if (annotation != null) - { annotation.Apply(this, assemblyBuilder, def); - } } } + // custom class loader specified if (options.classLoader != null) { RuntimeJavaType classLoaderType = null; @@ -3044,13 +3064,13 @@ private int CompilePass3() var mwModuleInit = classLoaderType.GetMethodWrapper("InitializeModule", "(Lcli.System.Reflection.Module;)V", false); if (mwModuleInit != null && mwModuleInit.IsStatic == false) { - var moduleInit = GetTypeWrapperFactory().ModuleBuilder.DefineGlobalMethod(".cctor", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, null, Type.EmptyTypes); - var moduleInitIL = moduleInit.GetILGenerator(); - moduleInitIL.Emit(OpCodes.Ldtoken, moduleInit); - moduleInitIL.Emit(OpCodes.Call, Context.Resolver.ResolveCoreType(typeof(System.Reflection.MethodBase).FullName).GetMethod("GetMethodFromHandle", new[] { Context.Resolver.ResolveCoreType(typeof(RuntimeMethodHandle).FullName) })); - moduleInitIL.Emit(OpCodes.Callvirt, Context.Resolver.ResolveCoreType(typeof(System.Reflection.MemberInfo).FullName).GetProperty("Module").GetGetMethod()); - moduleInitIL.Emit(OpCodes.Call, Context.Resolver.ResolveRuntimeType("IKVM.Runtime.ByteCodeHelper").GetMethod("InitializeModule")); - moduleInitIL.Emit(OpCodes.Ret); + moduleInitBuilders.Add((mb, il) => + { + il.Emit(OpCodes.Ldtoken, mb); + il.Emit(OpCodes.Call, Context.Resolver.ResolveCoreType(typeof(System.Reflection.MethodBase).FullName).GetMethod("GetMethodFromHandle", new[] { Context.Resolver.ResolveCoreType(typeof(RuntimeMethodHandle).FullName) })); + il.Emit(OpCodes.Callvirt, Context.Resolver.ResolveCoreType(typeof(System.Reflection.MemberInfo).FullName).GetProperty("Module").GetGetMethod()); + il.Emit(OpCodes.Call, Context.Resolver.ResolveRuntimeType("IKVM.Runtime.ByteCodeHelper").GetMethod("InitializeModule")); + }); } } @@ -3066,6 +3086,29 @@ private int CompilePass3() assemblyBuilder.DefineVersionInfoResource(); + // find methods marked as module initializers and append calls + foreach (var modInitMethod in javaTypes.SelectMany(i => i.GetMethods()).Where(i => i.IsModuleInitializer)) + { + var modInitMethod_ = modInitMethod; + moduleInitBuilders.Add((mb, il) => { modInitMethod_.Link(); modInitMethod_.EmitCall(il); }); + } + + // apply module initializer if any instructions added + if (moduleInitBuilders.Count > 0) + { + // begin a module initializer + var moduleInit = GetTypeWrapperFactory().ModuleBuilder.DefineGlobalMethod(".cctor", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, null, Type.EmptyTypes); + var moduleInitIL = Context.CodeEmitterFactory.Create(moduleInit); + + // allow builders to append IL + foreach (var moduleInitBuilder in moduleInitBuilders) + moduleInitBuilder(moduleInit, moduleInitIL); + + // finish method + moduleInitIL.Emit(OpCodes.Ret); + moduleInitIL.DoEmit(); + } + return 0; } diff --git a/src/IKVM.Tools.Importer/FatalCompilerErrorException.cs b/src/IKVM.Tools.Importer/FatalCompilerErrorException.cs index e9d4a015e3..a953792fb3 100644 --- a/src/IKVM.Tools.Importer/FatalCompilerErrorException.cs +++ b/src/IKVM.Tools.Importer/FatalCompilerErrorException.cs @@ -159,6 +159,8 @@ private static string GetMessage(Message id) return "Field '{0}' referenced in remap file was not found in class '{1}'"; case IKVM.Tools.Importer.Message.GhostInterfaceMethodMissing: return "Remapped class '{0}' does not implement ghost interface method\n\t({1}.{2}{3})"; + case Importer.Message.ModuleInitializerMethodRequirements: + return "Method '{1}.{2}{3}' does not meet the requirements of a module initializer."; default: return "Missing Error IKVM.Tools.Importer.Message. Please file a bug."; } diff --git a/src/IKVM.Tools.Importer/Message.cs b/src/IKVM.Tools.Importer/Message.cs index b866f28b26..dc5c93409a 100644 --- a/src/IKVM.Tools.Importer/Message.cs +++ b/src/IKVM.Tools.Importer/Message.cs @@ -127,6 +127,9 @@ internal enum Message MapFileFieldNotFound = 5057, GhostInterfaceMethodMissing = 5058, + // ModuleInitializer attribute placed on inappropriate method + ModuleInitializerMethodRequirements = 5059, + } } diff --git a/src/IKVM/IKVM.csproj b/src/IKVM/IKVM.csproj index 44335be1c9..816589663a 100644 --- a/src/IKVM/IKVM.csproj +++ b/src/IKVM/IKVM.csproj @@ -7,10 +7,9 @@ Java SE 8 Virtual Machine for .NET true $(AllowedOutputExtensionsInPackageBuildOutputFolder);.config - $(TargetsForTfmSpecificBuildOutput);GetProjectReferenceBuildOutputInPackage - $(TargetsForTfmSpecificDebugSymbolsInPackage);GetProjectReferenceDebugSymbolsInPackage NU5118 false + true @@ -32,20 +31,6 @@ - - - - - - - - - - $(TargetFramework) - - - - <_GeneratedPropsFileLine Include="<Project><PropertyGroup><IkvmVersion>$(PackageVersion)</IkvmVersion></PropertyGroup></Project>" /> diff --git a/src/IKVM/buildTransitive/IKVM.NoTasks.targets b/src/IKVM/buildTransitive/IKVM.IkvmReference.NoTasks.targets similarity index 100% rename from src/IKVM/buildTransitive/IKVM.NoTasks.targets rename to src/IKVM/buildTransitive/IKVM.IkvmReference.NoTasks.targets diff --git a/src/IKVM/buildTransitive/IKVM.Tasks.targets b/src/IKVM/buildTransitive/IKVM.IkvmReference.Tasks.targets similarity index 100% rename from src/IKVM/buildTransitive/IKVM.Tasks.targets rename to src/IKVM/buildTransitive/IKVM.IkvmReference.Tasks.targets diff --git a/src/IKVM/buildTransitive/IKVM.IkvmReference.props b/src/IKVM/buildTransitive/IKVM.IkvmReference.props new file mode 100644 index 0000000000..be41817347 --- /dev/null +++ b/src/IKVM/buildTransitive/IKVM.IkvmReference.props @@ -0,0 +1,33 @@ + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + + + + + + + + + + + + + + $(DebugType) + $(IkvmKeyFile) + + + true + true + true + + + + + + + + diff --git a/src/IKVM/buildTransitive/IKVM.IkvmReference.targets b/src/IKVM/buildTransitive/IKVM.IkvmReference.targets new file mode 100644 index 0000000000..e145a25096 --- /dev/null +++ b/src/IKVM/buildTransitive/IKVM.IkvmReference.targets @@ -0,0 +1,171 @@ + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + + <_IkvmReferenceItemPrepareStateFile Condition=" '$(IkvmReferenceItemPrepareStateFile)' == '' ">$(IntermediateOutputPath)$(MSBuildProjectFile).IkvmReferenceItemPrepare.cache + + + + + $(ResolveIkvmFrameworkReferencesDependsOn); + + + + + + <_IkvmFrameworkAssemblyReference Include="@(Reference)" Condition=" '%(Reference.NuGetIsFrameworkReference)' == 'true' Or '%(Reference.FrameworkFile)' == 'true' Or '%(Reference.ResolvedFrom)' == '{TargetFrameworkDirectory}' Or '%(Reference.IsImplicitlyDefined)' == 'true' Or '%(Reference.FrameworkReferenceName)' != '' Or '%(Reference.FrameworkReferenceVersion)' != '' Or '%(Reference.Identity)' == 'mscorlib' "/> + <_IkvmFrameworkAssemblyReference Include="@(Reference)" Condition=" '%(Reference.Identity)' == 'IKVM.Runtime' Or '%(Reference.Filename)%(Reference.Extension)' == 'IKVM.Runtime.dll' " /> + <_IkvmFrameworkAssemblyReference Include="@(Reference)" Condition=" '%(Reference.Identity)' == 'IKVM.Java' Or '%(Reference.Filename)%(Reference.Extension)' == 'IKVM.Java.dll' " /> + <_IkvmReferenceInstalledAssemblyDirectory Include="$(TargetFrameworkDirectory)" /> + <_IkvmReferenceInstalledAssemblySubsets Include="$(TargetFrameworkSubset)" /> + <_IkvmResolveAssemblyReferencesApplicationConfigFileForExes Include="@(AppConfigWithTargetPath)" Condition=" '$(AutoGenerateBindingRedirects)' == 'true' Or '$(AutoUnifyAssemblyReferences)' == 'false' "/> + + + + <_ResolveIkvmFrameworkReferencesStateFile Condition=" '$(DisableRarCache)' != 'true' And '$(_ResolveIkvmFrameworkReferencesStateFile)' == '' ">$(IntermediateOutputPath)$(MSBuildProjectFile).IkvmFrameworkReference.cache + <_IkvmResolveFrameworkReferencesSilent Condition="'$(_IkvmResolveFrameworkReferencesSilent)' == '' ">false + <_IkvmResolveFrameworkWarnOrErrorOnTargetArchitectureMismatch Condition=" '$(_IkvmResolveFrameworkWarnOrErrorOnTargetArchitectureMismatch)' == '' ">Warning + + + + + + + + + + + + + + + + + + + + + + + + <_IkvmReferenceReferences Include="@(IkvmFrameworkReference)" /> + + + + + + + + + + + + + + + + + $(GetIkvmReferenceItemsDependsOn); + ResolveIkvmFrameworkReferences; + GetIkvmReferenceItemsFromIkvmReferences; + _UpdateIkvmReferenceItemsMetadata; + + + + + + + + + + + + + + + + $(CompileIkvmReferenceAssemblies); + GetIkvmReferenceItems; + ResolveIkvmFrameworkReferences; + _CompileIkvmReferences; + + + + + + + + + + + + ResolveIkvmReferences + %(IkvmReferenceItem.CachePath) + %(IkvmReferenceItem.Aliases) + %(IkvmReferenceItem.Private) + %(IkvmReferenceItem.ReferenceOutputAssembly) + %(IkvmReferenceItem.Compile) + + + + + + + $(ResolveIkvmReferencesDependsOn); + CompileIkvmReferences; + GetIkvmReferenceItems; + _ResolveIkvmReferences; + + + + + + + + + + + diff --git a/src/IKVM/buildTransitive/IKVM.props b/src/IKVM/buildTransitive/IKVM.props index 09d35e4b07..1427e08763 100644 --- a/src/IKVM/buildTransitive/IKVM.props +++ b/src/IKVM/buildTransitive/IKVM.props @@ -9,39 +9,17 @@ $(MSBuildThisFileDirectory)..\ikvm.snk - - - - - - - - - - - - - - $(DebugType) - $(IkvmKeyFile) - - - true - true - true - - + + + + false PreserveNewest runtimes\%(RecursiveDir)%(Filename)%(Extension) - false - - - - + diff --git a/src/IKVM/buildTransitive/IKVM.targets b/src/IKVM/buildTransitive/IKVM.targets index e244d300cc..6ddd64692c 100644 --- a/src/IKVM/buildTransitive/IKVM.targets +++ b/src/IKVM/buildTransitive/IKVM.targets @@ -3,169 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - <_IkvmReferenceItemPrepareStateFile Condition=" '$(IkvmReferenceItemPrepareStateFile)' == '' ">$(IntermediateOutputPath)$(MSBuildProjectFile).IkvmReferenceItemPrepare.cache - - - - - $(ResolveIkvmFrameworkReferencesDependsOn); - - - - - - <_IkvmFrameworkAssemblyReference Include="@(Reference)" Condition=" '%(Reference.NuGetIsFrameworkReference)' == 'true' Or '%(Reference.FrameworkFile)' == 'true' Or '%(Reference.ResolvedFrom)' == '{TargetFrameworkDirectory}' Or '%(Reference.IsImplicitlyDefined)' == 'true' Or '%(Reference.FrameworkReferenceName)' != '' Or '%(Reference.FrameworkReferenceVersion)' != '' Or '%(Reference.Identity)' == 'mscorlib' "/> - <_IkvmFrameworkAssemblyReference Include="@(Reference)" Condition=" '%(Reference.Identity)' == 'IKVM.Runtime' Or '%(Reference.Filename)%(Reference.Extension)' == 'IKVM.Runtime.dll' " /> - <_IkvmFrameworkAssemblyReference Include="@(Reference)" Condition=" '%(Reference.Identity)' == 'IKVM.Java' Or '%(Reference.Filename)%(Reference.Extension)' == 'IKVM.Java.dll' " /> - <_IkvmReferenceInstalledAssemblyDirectory Include="$(TargetFrameworkDirectory)" /> - <_IkvmReferenceInstalledAssemblySubsets Include="$(TargetFrameworkSubset)" /> - <_IkvmResolveAssemblyReferencesApplicationConfigFileForExes Include="@(AppConfigWithTargetPath)" Condition=" '$(AutoGenerateBindingRedirects)' == 'true' Or '$(AutoUnifyAssemblyReferences)' == 'false' "/> - - - - <_ResolveIkvmFrameworkReferencesStateFile Condition=" '$(DisableRarCache)' != 'true' And '$(_ResolveIkvmFrameworkReferencesStateFile)' == '' ">$(IntermediateOutputPath)$(MSBuildProjectFile).IkvmFrameworkReference.cache - <_IkvmResolveFrameworkReferencesSilent Condition="'$(_IkvmResolveFrameworkReferencesSilent)' == '' ">false - <_IkvmResolveFrameworkWarnOrErrorOnTargetArchitectureMismatch Condition=" '$(_IkvmResolveFrameworkWarnOrErrorOnTargetArchitectureMismatch)' == '' ">Warning - - - - - - - - - - - - - - - - - - - - - - - - <_IkvmReferenceReferences Include="@(IkvmFrameworkReference)" /> - - - - - - - - - - - - - - - - - $(GetIkvmReferenceItemsDependsOn); - ResolveIkvmFrameworkReferences; - GetIkvmReferenceItemsFromIkvmReferences; - _UpdateIkvmReferenceItemsMetadata; - - - - - - - - - - - - - - - - $(CompileIkvmReferenceAssemblies); - GetIkvmReferenceItems; - ResolveIkvmFrameworkReferences; - _CompileIkvmReferences; - - - - - - - - - + + + + - - ResolveIkvmReferences - %(IkvmReferenceItem.CachePath) - %(IkvmReferenceItem.Aliases) - %(IkvmReferenceItem.Private) - %(IkvmReferenceItem.ReferenceOutputAssembly) - %(IkvmReferenceItem.Compile) - + <_IkvmRuntimeIdentifiers Include="$(_IkvmRuntimeIdentifier)" /> + <_IkvmRuntimeIdentifiers Include="@(IkvmAvailableRuntimeIdentifiers)" Condition=" '@(_IkvmRuntimeIdentifiers)' == '' " /> - - - $(ResolveIkvmReferencesDependsOn); - CompileIkvmReferences; - GetIkvmReferenceItems; - _ResolveIkvmReferences; - - - - - - - - - - + diff --git a/src/java/java.csproj b/src/java/java.csproj index 9c1be1b207..ce37b0c081 100644 --- a/src/java/java.csproj +++ b/src/java/java.csproj @@ -1,4 +1,8 @@ - + + + + + Exe net472;net6.0;net8.0 @@ -9,4 +13,8 @@ + + + + diff --git a/src/javac-ref/Properties/launchSettings.json b/src/javac-ref/Properties/launchSettings.json index b796f7ffde..889072b99e 100644 --- a/src/javac-ref/Properties/launchSettings.json +++ b/src/javac-ref/Properties/launchSettings.json @@ -1,10 +1,11 @@ { - "profiles": { - "javac": { - "commandName": "Project", - "environmentVariables": { - "IKVM_HOME_ROOT": "C:\\dev\\ikvm2\\src\\IKVM.Tests\\bin\\Debug\\net6.0\\ikvm\\" - } + "profiles": { + "javac": { + "commandName": "Project", + "commandLineArgs": "@C:\\dev\\ikvm\\src\\javadoc\\obj\\Debug\\net8.0\\osx-arm64\\javadoc.javac.rsp", + "environmentVariables": { + } } + } } \ No newline at end of file diff --git a/src/javac-ref/javac-ref.csproj b/src/javac-ref/javac-ref.csproj index 1616db48a9..261255fa42 100644 --- a/src/javac-ref/javac-ref.csproj +++ b/src/javac-ref/javac-ref.csproj @@ -6,7 +6,7 @@ Exe javac - net472;net6.0;net8.0 + net8.0;net472;net6.0; $(_SupportedImageRuntimes) true true @@ -20,6 +20,7 @@ + diff --git a/src/javac/javac.csproj b/src/javac/javac.csproj index 6abc46c8b9..375ae1ce28 100644 --- a/src/javac/javac.csproj +++ b/src/javac/javac.csproj @@ -14,6 +14,7 @@ + diff --git a/src/javadoc/javadoc.csproj b/src/javadoc/javadoc.csproj index 42d8517d55..1e273a92c5 100644 --- a/src/javadoc/javadoc.csproj +++ b/src/javadoc/javadoc.csproj @@ -14,6 +14,7 @@ + diff --git a/src/javah/javah.csproj b/src/javah/javah.csproj index c7430b045b..5a9d08cbad 100644 --- a/src/javah/javah.csproj +++ b/src/javah/javah.csproj @@ -14,6 +14,7 @@ + diff --git a/src/javap/javap.csproj b/src/javap/javap.csproj index 6ddd0e31a1..5d215a83ea 100644 --- a/src/javap/javap.csproj +++ b/src/javap/javap.csproj @@ -14,6 +14,7 @@ + diff --git a/src/jdeps/jdeps.csproj b/src/jdeps/jdeps.csproj index 07c297f2e0..1aead720f1 100644 --- a/src/jdeps/jdeps.csproj +++ b/src/jdeps/jdeps.csproj @@ -14,6 +14,7 @@ + diff --git a/src/keytool/keytool.csproj b/src/keytool/keytool.csproj index 9bc542a6ce..641cb06143 100644 --- a/src/keytool/keytool.csproj +++ b/src/keytool/keytool.csproj @@ -14,6 +14,7 @@ + diff --git a/src/libawt/libawt.clangproj b/src/libawt/libawt.clangproj index ef4e1b3c00..6c152b19f0 100644 --- a/src/libawt/libawt.clangproj +++ b/src/libawt/libawt.clangproj @@ -6,11 +6,11 @@ awt - c99 + dll - - + + diff --git a/src/libfdlibm/libfdlibm.clangproj b/src/libfdlibm/libfdlibm.clangproj index c220f82031..37b34be8e6 100644 --- a/src/libfdlibm/libfdlibm.clangproj +++ b/src/libfdlibm/libfdlibm.clangproj @@ -6,17 +6,14 @@ fdlibm + lib c89 +
- -
- %(RecursiveDir)%(Filename)%(Extension) -
-
diff --git a/src/libiava/libiava.clangproj b/src/libiava/libiava.clangproj index bdfa2640a4..8bf4bea859 100644 --- a/src/libiava/libiava.clangproj +++ b/src/libiava/libiava.clangproj @@ -6,7 +6,8 @@ iava - c89 + dll + c99 @@ -14,57 +15,170 @@ - - - - +
+
+ + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + (); + + foreach (var path in Paths) + { + if (Directory.Exists(path.ItemSpec)) + { + foreach (var file in Directory.GetFiles(path.ItemSpec, "*.c")) + { + var n = Path.GetFileName(file); + if (Excludes.Any(i => i.ItemSpec == n) == false) + items.Add(new TaskItem(Path.Combine(path.ItemSpec, n))); + } + } + } + + Items = items.ToArray(); + return true; + } + +} + ]]> + + + + + + + + + + + + + + + + + + + + + + + GetLibJavaItems; + UpdateLibJavaItems; + $(CompileDependsOn); + + + - \ No newline at end of file + diff --git a/src/libikvm-tests/libikvm-tests.clangproj b/src/libikvm-tests/libikvm-tests.clangproj index fc163d289b..5f1375b7ca 100644 --- a/src/libikvm-tests/libikvm-tests.clangproj +++ b/src/libikvm-tests/libikvm-tests.clangproj @@ -6,6 +6,7 @@ ikvm-tests + dll diff --git a/src/libikvm/dl.c b/src/libikvm/dl.c index add5a5a971..5dd226ce34 100644 --- a/src/libikvm/dl.c +++ b/src/libikvm/dl.c @@ -2,7 +2,7 @@ #define NETEXPORT __declspec(dllexport) #define NETCALL __stdcall #else -#define NETEXPORT +#define NETEXPORT __attribute__((visibility("default"))) #define NETCALL #endif @@ -23,7 +23,13 @@ static pthread_mutex_t dl_mutex; NETEXPORT void* NETCALL IKVM_dl_open(const char* name) { #ifdef WIN32 - return LoadLibraryEx(name, 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); + size_t sname = (size_t)MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); + LPWSTR wname = (LPWSTR)malloc(sname * sizeof(WCHAR)); + MultiByteToWideChar(CP_UTF8, 0, name, -1, wname, sname); + + void* result = LoadLibraryExW(wname, 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); + free(wname); + return result; #else return dlopen(name, RTLD_LAZY | RTLD_GLOBAL); #endif diff --git a/src/libikvm/io.c b/src/libikvm/io.c index f3b0099937..a79d5ca5c2 100644 --- a/src/libikvm/io.c +++ b/src/libikvm/io.c @@ -2,7 +2,7 @@ #define NETEXPORT __declspec(dllexport) #define NETCALL __stdcall #else -#define NETEXPORT +#define NETEXPORT __attribute__((visibility("default"))) #define NETCALL #endif diff --git a/src/libikvm/libikvm.clangproj b/src/libikvm/libikvm.clangproj index 00866b9bdb..5e7150331a 100644 --- a/src/libikvm/libikvm.clangproj +++ b/src/libikvm/libikvm.clangproj @@ -6,11 +6,13 @@ ikvm + dll - - + + + - + diff --git a/src/libikvm/sig.c b/src/libikvm/sig.c index e17b8b4775..28440688f5 100644 --- a/src/libikvm/sig.c +++ b/src/libikvm/sig.c @@ -2,7 +2,7 @@ #define NETEXPORT __declspec(dllexport) #define NETCALL __stdcall #else -#define NETEXPORT +#define NETEXPORT __attribute__((visibility("default"))) #define NETCALL #endif diff --git a/src/libj2pkcs11/README.md b/src/libj2pkcs11/README.md deleted file mode 100644 index 6a83bae0cf..0000000000 --- a/src/libj2pkcs11/README.md +++ /dev/null @@ -1 +0,0 @@ -Not yet functional. \ No newline at end of file diff --git a/src/libj2pkcs11/libj2pkcs11.clangproj b/src/libj2pkcs11/libj2pkcs11.clangproj index 57b8587ba7..0258530a37 100644 --- a/src/libj2pkcs11/libj2pkcs11.clangproj +++ b/src/libj2pkcs11/libj2pkcs11.clangproj @@ -1,26 +1,31 @@  - - - - 8afae23f-de5f-4b71-b9c3-c5b0e7705b96 - - - j2pkcs11 - c89 - $(PreprocessorDefinitions);P11_DEBUG;SECMOD_DEBUG - $(IncludeDirectories);$(OpenJdkDir)jdk\src\share\native\sun\security\pkcs11 - $(IncludeDirectories);$(OpenJdkDir)jdk\src\share\native\sun\security\pkcs11\wrapper - $(IncludeDirectories);$(OpenJdkDir)jdk\src\$(OpenJdkTargetOsApiDir)\native\sun\security\pkcs11 - $(IncludeDirectories);$(OpenJdkDir)jdk\src\$(OpenJdkTargetOsApiDir)\native\sun\security\pkcs11\wrapper - - - - - - - - - - - + + + + 8afae23f-de5f-4b71-b9c3-c5b0e7705b96 + + + j2pkcs11 + dll + c99 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/libjaas/libjaas.clangproj b/src/libjaas/libjaas.clangproj new file mode 100644 index 0000000000..7bcfcaa802 --- /dev/null +++ b/src/libjaas/libjaas.clangproj @@ -0,0 +1,33 @@ + + + + + 2d69f3e3-d750-479b-975a-d8de7fa3f7ee + + + jaas + jaas_unix + jaas_nt + dll + c99 + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libjnf/JavaNativeFoundation/JNFAssert.h b/src/libjnf/JavaNativeFoundation/JNFAssert.h new file mode 100644 index 0000000000..9bfbfb27d7 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFAssert.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Assertions used by the JNF_COCOA_ENTER()/JNF_COCOA_EXIT() and class + * caching macros. When building debug builds, improper use of the caching + * macros will trigger warnings output to the console. + */ + +#import + +#ifdef DEBUG +#define JAVA_ASSERTIONS_ON +#endif /* DEBUG */ + +// Use the WARN macro to send a message to stderr in the +// debug build. It gets removed from the optimized build +// during preprocessing. +#ifdef DEBUG +#define JNF_WARN JNFDebugWarning +#else +#define JNF_WARN if (0) JNFDebugWarning +#endif /* DEBUG */ + +__BEGIN_DECLS + +JNF_EXPORT extern void JNFDebugWarning(const char *fmt, ...); + +JNF_EXPORT extern void JNFAssertionFailure(const char *file, int line, const char *condition, const char *msg); + +#ifdef JAVA_ASSERTIONS_ON + +#define JNF_ASSERT_FAILURE(condition, msg) \ + JNFAssertionFailure(__FILE__, __LINE__, condition, msg) \ + + +#define JNF_ASSERT_MSG(condition, msg) \ +do { \ + if (!(condition)) { \ + JNF_ASSERT_FAILURE(#condition, msg); \ + } \ +} while(0) \ + + +#define JNF_ASSERT_COND(condition) \ + JNF_ASSERT_MSG(condition, NULL) \ + + +#define JNF_EXCEPTION_WARN(env, msg) \ +do { \ + (*(env))->ExceptionDescribe(env); \ + JNF_ASSERT_FAILURE("Java exception thrown", msg); \ +} while (0) \ + + +#define JNF_ASSERT_NO_EXCEPTION_MSG(env, msg) \ +if ((*(env))->ExceptionOccurred(env)) { \ + JNF_EXCEPTION_WARN(env, msg); \ +} \ + + +#define JNF_ASSERT_NO_EXCEPTION(env) \ + JNF_ASSERT_NO_EXCEPTION_MSG(env, NULL) \ + +#else + +#define JNF_ASSERT_COND(condition) +#define JNF_ASSERT_MSG(condition, msg) +#define JNF_EXCEPTION_WARN(env, msg) +#define JNF_ASSERT_NO_EXCEPTION(env) +#define JNF_ASSERT_NO_EXCEPTION_MSG(env, msg) + +#endif /* JAVA_ASSERTIONS_ON */ + +JNF_EXPORT extern void JNFDumpJavaStack(JNIEnv *env); + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFAssert.m b/src/libjnf/JavaNativeFoundation/JNFAssert.m new file mode 100644 index 0000000000..fceb8f819e --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFAssert.m @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFJNI.h" +#import "JNFAssert.h" + +#import "debug.h" + +static void JNFDebugMessageV(const char *fmt, va_list args) { + // Prints a message and breaks into debugger. + fprintf(stderr, "JavaNativeFoundation: "); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); +} + +static void JNFDebugMessage(const char *fmt, ...) { + // Takes printf args and then calls DebugBreak + va_list args; + va_start(args, fmt); + JNFDebugMessageV(fmt, args); + va_end(args); +} + +void JNFDebugWarning(const char *fmt, ...) { + // Takes printf args and then calls DebugBreak + va_list args; + va_start(args, fmt); + JNFDebugMessageV(fmt, args); + va_end(args); +} + +void JNFAssertionFailure(const char *file, int line, const char *condition, const char *msg) { + JNFDebugMessage("Assertion failure: %s", condition); + if (msg) JNFDebugMessage(msg); + JNFDebugMessage("File %s; Line %d", file, line); +} + +void JNFDumpJavaStack(JNIEnv *env) { + static JNF_CLASS_CACHE(jc_Thread, "java/lang/Thread"); + static JNF_STATIC_MEMBER_CACHE(jsm_Thread_dumpStack, jc_Thread, "dumpStack", "()V"); + JNFCallVoidMethod(env, jc_Thread.cls, jsm_Thread_dumpStack); +} diff --git a/src/libjnf/JavaNativeFoundation/JNFAutoreleasePool.h b/src/libjnf/JavaNativeFoundation/JNFAutoreleasePool.h new file mode 100644 index 0000000000..7d3c543f0b --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFAutoreleasePool.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Utility class used by the JNF_COCOA_ENTER()/JNF_COCOA_EXIT() macros + * from JNFJNI.h. Do not use this class or releated functions directly. + */ + +#import + +#import + +__BEGIN_DECLS + +typedef void JNFAutoreleasePoolToken; + +// JNFNativeMethodEnter - called on entry to each native method by the +// JNF_COCOA_ENTER(env) macro in JNFJNI.h +JNF_EXPORT extern JNFAutoreleasePoolToken *JNFNativeMethodEnter(void); + +// JNFNativeMethodExit - called on exit from each native method by the +// JNF_COCOA_EXIT(env) macro in JNFJNI.h +JNF_EXPORT extern void JNFNativeMethodExit(JNFAutoreleasePoolToken *token); + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFAutoreleasePool.m b/src/libjnf/JavaNativeFoundation/JNFAutoreleasePool.m new file mode 100644 index 0000000000..50d513bab0 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFAutoreleasePool.m @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * The JNFAutoreleasePool manages setting up and tearing down autorelease + * pools for Java calls into the Cocoa frameworks. + * + * The external entry point into this machinery is JNFMethodEnter() and JNFMethodExit(). + */ + +#import "JNFAutoreleasePool.h" + +#import + +// These are vended by the Objective-C runtime, but they are unfortunately +// not available as API in the macOS SDK. We are following suit with swift +// and clang in declaring them inline here. They canot be removed or changed +// in the OS without major bincompat ramifications. +// +// These were added in macOS 10.7. +void * _Nonnull objc_autoreleasePoolPush(void); +void objc_autoreleasePoolPop(void * _Nonnull context); + +#if TIMED +static int64_t elapsedTime = 0; +#endif + +#pragma mark - +#pragma mark External API + +// JNFNativeMethodEnter - called on entry to each native method +// +// It sets up an autorelease pool, and will return a token if +// JNFNativeMethodExit should be called. It attempts to consider +// how much time has elapsed since the last autorelease pop. + +JNFAutoreleasePoolToken *JNFNativeMethodEnter() { +#if TIMED + int64_t start = mach_absolute_time(); +#endif + + JNFAutoreleasePoolToken * const tokenToReturn = objc_autoreleasePoolPush(); + +#if TIMED + elapsedTime += (mach_absolute_time() - start); +#endif + + return tokenToReturn; +} + + +// JNFNativeMethodExit - called on exit from native methods +// +// This method is only called on exit from the first +// native method to appear in the execution stack. +// This function does not need to be called on exit +// from the inner native methods (as an optimization). +// JNFNativeMethodEnter sets the token to non-nil if +// JNFNativeMethodExit needs to be called on exit. + +void JNFNativeMethodExit(JNFAutoreleasePoolToken *token) { + +#if TIMED + int64_t start = mach_absolute_time(); +#endif + + objc_autoreleasePoolPop(token); + +#if TIMED + elapsedTime += (mach_absolute_time() - start); + + NSLog(@"elapsedTime: %llu", elapsedTime); + // elapsedTime = 0; +#endif +} diff --git a/src/libjnf/JavaNativeFoundation/JNFDate.h b/src/libjnf/JavaNativeFoundation/JNFDate.h new file mode 100644 index 0000000000..93f0e6dfac --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFDate.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Functions to convert between date container classes. + */ + +#import + +#import + +__BEGIN_DECLS + +/* + * Converts java.util.Calendar and java.util.Date to an NSDate + * NOTE: Return value is auto-released. + */ +JNF_EXPORT extern NSDate *JNFJavaToNSDate(JNIEnv *env, jobject date); + +/* + * Converts an NSDate to a java.util.Calendar + * NOTE: This returns a JNI local ref. Any code that calls this should call DeleteLocalRef when done with the return value. + */ +JNF_EXPORT extern jobject JNFNSToJavaCalendar(JNIEnv *env, NSDate *date); + +/* + * Converts a millisecond time interval since the Java Jan 1, 1970 epoch into an + * NSTimeInterval since Mac OS X's Jan 1, 2001 epoch. + */ +JNF_EXPORT extern NSTimeInterval JNFJavaMillisToNSTimeInterval(jlong javaMillisSince1970); + +/* + * Converts an NSTimeInterval since the Mac OS X Jan 1, 2001 epoch into a + * Java millisecond time interval since Java's Jan 1, 1970 epoch. + */ +JNF_EXPORT extern jlong JNFNSTimeIntervalToJavaMillis(NSTimeInterval intervalSince2001); + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFDate.m b/src/libjnf/JavaNativeFoundation/JNFDate.m new file mode 100644 index 0000000000..f3b4042fb2 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFDate.m @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFDate.h" +#import "JNFJNI.h" + + +static JNF_CLASS_CACHE(sjc_Calendar, "java/util/Calendar"); +static JNF_CLASS_CACHE(sjc_Date, "java/util/Date"); + +JNF_EXPORT extern NSTimeInterval JNFJavaMillisToNSTimeInterval(jlong javaMillisSince1970) +{ + return (NSTimeInterval)(((double)javaMillisSince1970 / 1000.0) - NSTimeIntervalSince1970); +} + +JNF_EXPORT extern jlong JNFNSTimeIntervalToJavaMillis(NSTimeInterval intervalSince2001) +{ + return (jlong)((intervalSince2001 + NSTimeIntervalSince1970) * 1000.0); +} + +JNF_EXPORT extern NSDate *JNFJavaToNSDate(JNIEnv *env, jobject date) +{ + if (date == NULL) return nil; + + jlong millis = 0; + if (JNFIsInstanceOf(env, date, &sjc_Calendar)) { + static JNF_MEMBER_CACHE(jm_getTimeInMillis, sjc_Calendar, "getTimeInMillis", "()J"); + millis = JNFCallLongMethod(env, date, jm_getTimeInMillis); + } else if (JNFIsInstanceOf(env, date, &sjc_Date)) { + static JNF_MEMBER_CACHE(jm_getTime, sjc_Date, "getTime", "()J"); + millis = JNFCallLongMethod(env, date, jm_getTime); + } + + if (millis == 0) { + return nil; + } + + return [NSDate dateWithTimeIntervalSince1970:((double)millis / 1000.0)]; +} + +JNF_EXPORT extern jobject JNFNSToJavaCalendar(JNIEnv *env, NSDate *date) +{ + if (date == nil) return NULL; + + const jlong millis = (jlong)([date timeIntervalSince1970] * 1000.0); + + static JNF_STATIC_MEMBER_CACHE(jsm_getInstance, sjc_Calendar, "getInstance", "()Ljava/util/Calendar;"); + jobject calendar = JNFCallStaticObjectMethod(env, jsm_getInstance); + + static JNF_MEMBER_CACHE(jm_setTimeInMillis, sjc_Calendar, "setTimeInMillis", "(J)V"); + JNFCallVoidMethod(env, calendar, jm_setTimeInMillis, millis); + + return calendar; +} diff --git a/src/libjnf/JavaNativeFoundation/JNFException.h b/src/libjnf/JavaNativeFoundation/JNFException.h new file mode 100644 index 0000000000..c93be64045 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFException.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * JNFExceptions handle bridging exceptions between Foundation and Java. NSExceptions are + * caught by the JNF_COCOA_ENTER()/JNF_COCOA_EXIT() macros, and transformed and thrown as + * Java exceptions at the JNI boundry. The macros in JNFJNI.h also check for Java exceptions + * and rethrow them as NSExceptions until they hit an @try/@catch block, or the + * JNF_COCOA_ENTER()/JNF_COCOA_EXIT() macros. + */ + +#import + +#import + +__BEGIN_DECLS + +// Some exception class names. +// These strings contain the full class name of each Java exception, so +// they are handy to use when you need to throw an exception. +JNF_EXPORT extern const char *kOutOfMemoryError; +JNF_EXPORT extern const char *kClassNotFoundException; +JNF_EXPORT extern const char *kNullPointerException; +JNF_EXPORT extern const char *kIllegalAccessException; +JNF_EXPORT extern const char *kIllegalArgumentException; +JNF_EXPORT extern const char *kNoSuchFieldException; +JNF_EXPORT extern const char *kNoSuchMethodException; +JNF_EXPORT extern const char *kRuntimeException; + +// JNFException - a subclass of NSException that wraps a Java exception +// +// When a java exception is thrown out to a native method, use +raiseUnnamedException: +// to turn it into an NSException. When returning out of a native method in +// which an NSException has been raised, use the -raiseToJava: method to turn +// it back into a Java exception and "throw" it, in the Java sense. + +JNF_EXPORT +@interface JNFException : NSException + ++ (void)raiseUnnamedException:(JNIEnv *)env; ++ (void)raise:(JNIEnv *)env throwable:(jthrowable)throwable; ++ (void)raise:(JNIEnv *)env as:(const char *)javaExceptionType reason:(const char *)reasonMsg; + +- init:(JNIEnv *)env throwable:(jthrowable)throwable; +- init:(JNIEnv *)env as:(const char *)javaExceptionType reason:(const char *)reasonMsg; + ++ (void)throwToJava:(JNIEnv *)env exception:(NSException *)exception; ++ (void)throwToJava:(JNIEnv *)env exception:(NSException *)exception as:(const char *)javaExceptionType; + +- (void)raiseToJava:(JNIEnv *)env; + +@end + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFException.m b/src/libjnf/JavaNativeFoundation/JNFException.m new file mode 100644 index 0000000000..28a75dd781 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFException.m @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFException.h" + +#import +#import + +#import "JNFObject.h" +#import "JNFString.h" +#import "JNFAssert.h" +#import "JNFThread.h" +#import "debug.h" + + +#define JAVA_LANG "java/lang/" +const char* kOutOfMemoryError = JAVA_LANG "OutOfMemoryError"; +const char* kClassNotFoundException = JAVA_LANG "ClassNotFoundException"; +const char* kNullPointerException = JAVA_LANG "NullPointerException"; +const char* kIllegalAccessException = JAVA_LANG "IllegalAccessException"; +const char* kIllegalArgumentException = JAVA_LANG "IllegalArgumentException"; +const char* kNoSuchFieldException = JAVA_LANG "NoSuchFieldException"; +const char* kNoSuchMethodException = JAVA_LANG "NoSuchMethodException"; +const char* kRuntimeException = JAVA_LANG "RuntimeException"; + +@interface JNFException () +@property (readwrite, nonatomic, assign) jthrowable javaException; +@end + +@interface JNFException(_JNFPrivateExceptionLifecycle) + +- (void) _setThrowable:(jthrowable)throwable withEnv:(JNIEnv *)env; +- (void) _clearThrowableWithEnv:(JNIEnv *)env; +- (void) _setThrowable:(jthrowable)throwable withNonNullEnv:(JNIEnv *)env; +- (void) _clearThrowableWithNonNullEnv:(JNIEnv *)env; + +@end + + +@implementation JNFException + +- initUnnamed:(JNIEnv *)env { + JNF_ASSERT_COND(env); + jthrowable throwable = (*env)->ExceptionOccurred(env); + if (throwable) return [self init:env throwable:throwable]; + + return [self initWithName:@"JavaNativeException" reason:@"See Java exception" userInfo:nil]; +} + ++ (void)raiseUnnamedException:(JNIEnv *)env { + JNF_ASSERT_COND(env); + [[[[JNFException alloc] initUnnamed:env] autorelease] raise]; +} + ++ (void)raise:(JNIEnv *)env throwable:(jthrowable)throwable { + JNF_ASSERT_COND(env); + [[[[JNFException alloc] init:env throwable:throwable] autorelease] raise]; +} + ++ (void)raise:(JNIEnv *)env as:(const char *)javaExceptionType reason:(const char *)reasonMsg { + JNF_ASSERT_COND(env); + [[[[JNFException alloc] init:env as:javaExceptionType reason:reasonMsg] autorelease] raise]; +} + +- init:(JNIEnv *)env throwable:(jthrowable)throwable { + [self _setThrowable:throwable withEnv:env]; + (*env)->ExceptionClear(env); // The exception will be rethrown in -raiseToJava + + static jclass jc_Throwable = NULL; + if (jc_Throwable == NULL) { + jc_Throwable = (*env)->FindClass(env, "java/lang/Throwable"); + jthrowable unexpected = (*env)->ExceptionOccurred(env); + if (unexpected) { + (*env)->ExceptionClear(env); + return [self initWithName:@"JavaNativeException" reason:@"Internal JNF Error: could not find Throwable class" userInfo:nil]; + } + } + + static jmethodID jm_Throwable_getMessage = NULL; + if (jm_Throwable_getMessage == NULL && jc_Throwable != NULL) { + jm_Throwable_getMessage = (*env)->GetMethodID(env, jc_Throwable, "toString", "()Ljava/lang/String;"); + jthrowable unexpected = (*env)->ExceptionOccurred(env); + if (unexpected) { + (*env)->ExceptionClear(env); + return [self initWithName:@"JavaNativeException" reason:@"Internal JNF Error: could not find Throwable.toString() method" userInfo:nil]; + } + } + + if (jm_Throwable_getMessage == NULL) { + return [self initWithName:@"JavaNativeException" reason:@"Internal JNF Error: exception occurred, unable to determine cause" userInfo:nil]; + } + + jobject msg = (*env)->CallObjectMethod(env, throwable, jm_Throwable_getMessage); + jthrowable unexpected = (*env)->ExceptionOccurred(env); + if (unexpected) { + (*env)->ExceptionClear(env); + return [self initWithName:@"JavaNativeException" reason:@"Internal JNF Error: failed calling Throwable.toString()" userInfo:nil]; + } + + NSString *reason = JNFJavaToNSString(env, msg); + (*env)->DeleteLocalRef(env, msg); + return [self initWithName:@"JavaNativeException" reason:reason userInfo:nil]; +} + +- init:(JNIEnv *)env as:(const char *)javaExceptionType reason:(const char *)reasonMsg { + jclass exceptionClass = NULL; + char *buf = NULL; + + JNF_ASSERT_COND(env); + if (javaExceptionType != NULL) { + exceptionClass = (*env)->FindClass(env, javaExceptionType); + } + + if (exceptionClass == NULL) { + // Try to throw an AWTError exception + static jthrowable panicExceptionClass = NULL; + const char* panicExceptionName = kRuntimeException; + if (panicExceptionClass == NULL) { + jclass cls = (*env)->FindClass(env, panicExceptionName); + if (cls != NULL) { + panicExceptionClass = (*env)->NewGlobalRef(env, cls); + } + } + + exceptionClass = panicExceptionClass; + if (javaExceptionType == NULL) { + reasonMsg = "Missing Java exception class name while trying to throw a new Java exception"; + } else { + // Quick and dirty thread-safe message buffer. + buf = calloc(1, 512); + if (buf != NULL) { + sprintf(buf, "Unknown throwable class: %s.80", javaExceptionType); + reasonMsg = buf; + } else { + reasonMsg = "Unknown throwable class, out of memory!"; + } + } + javaExceptionType = panicExceptionName; + } + + // Can't throw squat if there's no class to throw + if (exceptionClass != NULL) { + (*env)->ThrowNew(env, exceptionClass, reasonMsg); + jthrowable ex = (*env)->ExceptionOccurred(env); + if (ex) { + (*env)->ExceptionClear(env); // Exception will be rethrown in -raiseToJava + } + [self _setThrowable:ex withEnv:env]; + } + + if (reasonMsg == NULL) reasonMsg = "unknown"; + + @try { + return [self initWithName:[NSString stringWithUTF8String:javaExceptionType] + reason:[NSString stringWithUTF8String:reasonMsg] + userInfo:nil]; + } @finally { + if (buf != NULL) free(buf); + } + + return self; +} + ++ (void)throwToJava:(JNIEnv *)env exception:(NSException *)exception { + [self throwToJava:env exception:exception as:kRuntimeException]; +} + ++ (void)throwToJava:(JNIEnv *)env exception:(NSException *)exception as:(const char *)javaExceptionType{ + if (![exception isKindOfClass:[JNFException class]]) { + exception = [[JNFException alloc] init:env as:javaExceptionType reason:[[NSString stringWithFormat:@"Non-Java exception raised, not handled! (Original problem: %@)", [exception reason]] UTF8String]]; + [exception autorelease]; + JNF_WARN("NSException not handled by native method. Passing to Java."); + } + + [(JNFException *)exception raiseToJava:env]; +} + +- (void)raiseToJava:(JNIEnv *)env { + jthrowable const javaException = self.javaException; + + JNF_ASSERT_COND(env); + JNF_ASSERT_COND(javaException != NULL); + (*env)->Throw(env, javaException); +} + +- (NSString *)description { + jthrowable const javaException = self.javaException; + NSString *desc = [super description]; + if (!javaException) return desc; + + @try { + JNFThreadContext ctx = JNFThreadDetachImmediately; + JNIEnv *env = JNFObtainEnv(&ctx); + if (!env) { + NSLog(@"JavaNativeFoundation: NULL JNIEnv error occurred obtaining Java exception description"); + return desc; + } + (*env)->ExceptionClear(env); + NSString *stackTrace = JNFGetStackTraceAsNSString(env, javaException); + JNFReleaseEnv(env, &ctx); + + return stackTrace; + } @catch (NSException *e) { + // we clearly blew up trying to print our own exception, so we should + // not try to do that again, even if it looks helpful - its a trap! + NSLog(@"JavaNativeFoundation error occurred obtaining Java exception description"); + } + return desc; +} + +- (void) _setThrowable:(jthrowable)throwable withEnv:(JNIEnv *)env { + if (env) { + [self _clearThrowableWithNonNullEnv:env]; + [self _setThrowable:throwable withNonNullEnv:env]; + return; + } + + JNFThreadContext threadContext = JNFThreadDetachImmediately; + env = JNFObtainEnv(&threadContext); + if (env == NULL) return; + + [self _clearThrowableWithNonNullEnv:env]; + [self _setThrowable:throwable withEnv:env]; + + JNFReleaseEnv(env, &threadContext); +} + +- (void) _clearThrowableWithEnv:(JNIEnv *)env { + if (env) { + [self _clearThrowableWithNonNullEnv:env]; + return; + } + + JNFThreadContext threadContext = JNFThreadDetachImmediately; + env = JNFObtainEnv(&threadContext); + if (env == NULL) return; // leak? + + [self _clearThrowableWithNonNullEnv:env]; + + JNFReleaseEnv(env, &threadContext); +} + +- (void) _setThrowable:(jthrowable)throwable withNonNullEnv:(JNIEnv *)env { + if (!throwable) return; + self.javaException = (*env)->NewGlobalRef(env, throwable); +} + +// delete and clear +- (void) _clearThrowableWithNonNullEnv:(JNIEnv *)env { + jthrowable const javaException = self.javaException; + if (!javaException) return; + self.javaException = NULL; + (*env)->DeleteGlobalRef(env, javaException); +} + +- (void) dealloc { + [self _clearThrowableWithEnv:NULL]; + [super dealloc]; +} + +@end diff --git a/src/libjnf/JavaNativeFoundation/JNFJNI.h b/src/libjnf/JavaNativeFoundation/JNFJNI.h new file mode 100644 index 0000000000..a5b34fb0bd --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFJNI.h @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * The basic building blocks of writing Java JNI code that interacts with Objective-C. + * + * All JNI functions should call JNF_COCOA_ENTER()/JNF_COCOA_EXIT() to properly + * catch thrown NSExceptions and periodically flush the autorelease pool for the + * current thread. JNF_COCOA_DURING()/JNF_COCOA_HANDLE() should only be used when + * AppKit is known to not be initialized yet. + * + * JNF_CLASS_CACHE()/JNF_MEMBER_CACHE()/JNF_STATIC_MEMBER_CACHE()/JNF_CTOR_CACHE() + * all cache references to Java classes, methods, and variables for use by the + * GET/SET/CALL functions. These functions check for Java exceptions, immediately + * re-throwing them as JNFExceptions, and are simpler than their pure JNI equivalents. + */ + +#import +#import +#import + +#define JNF_EXPORT __attribute__ ((visibility ("default"))) API_UNAVAILABLE(ios) + +#import +#import + +__BEGIN_DECLS + +// from jlong.h +// All pointers in and out of JNI functions should be expressed as jlongs +// to accomodate for both 32-bit and 64-bit pointer sizes +#ifndef jlong_to_ptr +#define jlong_to_ptr(a) ((void *)(uintptr_t)(a)) +#endif + +#ifndef ptr_to_jlong +#define ptr_to_jlong(a) ((jlong)(uintptr_t)(a)) +#endif + +// JNF_COCOA_DURING - Outermost exception scope for a JNI native method +// +// Use this macro only if you don't want any autorelease pool set or +// other JNFThreadContext setup (ie, if the AppKit isn't running +// yet). Usually, you want to use JNF_COCOA_ENTER & JNF_COCOA_EXIT +#define JNF_COCOA_DURING(env) \ +@try { + + +// JNF_COCOA_HANDLE - Close of JNF_COCOA_DURING +// +// Use this macro to match an JNF_COCOA_DURING +// This macro ensures that no NSException is thrown into +// the VM. It turns NSExceptions into Java exceptions. +#define JNF_COCOA_HANDLE(env) \ +} @catch(NSException *localException) { \ + [JNFException throwToJava:env exception:localException]; \ +} \ + + +// JNF_COCOA_ENTER - Place at the beginning of every JNI method +// +// Sets up an exception handler and an autorelease pool if one is +// not already setup. +// +// Note: if the native method executes before AppKit is +// initialized, use JNF_COCOA_DURING. +#define JNF_COCOA_ENTER(env) \ +{ \ + JNFAutoreleasePoolToken* _token = JNFNativeMethodEnter(); \ + JNF_COCOA_DURING(env) + + +// JNF_COCOA_EXIT - Place at the end of every JNI method +// +// Catches NSExceptions and re-throws them as Java exceptions. +// Use this macro to match JNF_COCOA_ENTER. +#define JNF_COCOA_EXIT(env) \ + JNF_COCOA_HANDLE(env) \ + @finally { \ + if (_token) JNFNativeMethodExit(_token); \ + } \ +} + +// JNF_CHECK_AND_RETHROW_EXCEPTION - rethrows exceptions from Java +// +// Takes an exception thrown from Java, and transforms it into an +// NSException. The NSException should bubble up to the upper-most +// JNF_COCOA_ENTER/JNF_COCOA_EXIT pair, and then be re-thrown as +// a Java exception when returning from JNI. This check should be +// done after raw JNI operations which could cause a Java exception +// to be be thrown. The JNF{Get/Set/Call} macros below do this +// check automatically. +#define JNF_CHECK_AND_RETHROW_EXCEPTION(env) \ +{ \ + jthrowable _exception = (*env)->ExceptionOccurred(env); \ + if (_exception) [JNFException raise:env throwable:_exception]; \ +} + + +// Use JNF_CLASS_CACHE, JNF_MEMBER_CACHE, JNF_STATIC_MEMBER_CACHE +// and JNF_CTOR_CACHE as convenient ways to create +// JNFClassInfo and JNFMemberInfo records that can +// be passed to the utility functions that follow. + +// JNF_CLASS_CACHE - Create a JNFClassInfo struct +// +// Use this macro to define a JNFClassInfo struct. +// For example: +// JNF_CLASS_CACHE(jc_java_awt_Font, "java/awt/Font"); +// defines the symbol jc_java_awt_Font to point to the +// appropriately initialized JNFClassInfo struct. +// The "jc_" prefix is short for "java class." +#define JNF_CLASS_CACHE(cache_symbol, name) \ + JNFClassInfo cache_symbol = {name, NULL} + +// JNF_MEMBER_CACHE - Create a JNFMemberInfo struct +// +// This macro creates and initializes a JNFMemberInfo +// struct, and defines a pointer to it. Example: +// JNF_MEMBER_CACHE(jm_Font_isBold, jc_java_awt_Font, "isBold", "Z"); +// This defines the symbol jm_Font_isBold to point to a +// JNFMemberInfo struct that represents the isBold method +// of the class java.awt.Font. Use this macro for both +// fields and methods. +#define JNF_MEMBER_CACHE(cache_symbol, class_cache_symbol, name, sig) \ + JNFMemberInfo _ ## cache_symbol = {name, sig, NO, &class_cache_symbol, {NULL}}, *cache_symbol=&_ ## cache_symbol + +// JNF_STATIC_MEMBER_CACHE - Create a JNFMemberInfo struct for static members +// +// Same as JNF_MEMBER_CACHE, but used for static fields and mehods. +#define JNF_STATIC_MEMBER_CACHE(cache_symbol, class_cache_symbol, name, sig) \ + JNFMemberInfo _ ## cache_symbol = {name, sig, YES, &class_cache_symbol, {NULL}}, *cache_symbol=&_ ## cache_symbol + +// JNF_CTOR_CACHE - Create a JNFMemberInfo struct for a constructor +// +// Same as JNF_MEMBER_CACHE, but for constructors +#define JNF_CTOR_CACHE(cache_symbol, class_cache_symbol, sig) \ + JNFMemberInfo _ ## cache_symbol = {"", sig, NO, &class_cache_symbol, {NULL}}, *cache_symbol=&_ ## cache_symbol + + +// JNFClassInfo - struct for caching a java class reference +// +// Create one of these by using the JNF_CLASS_CACHE macro (below). +// The class ref is resolved lazily. +typedef struct _JNFClassInfo { + const char *name; // fully/qualified/ClassName + jclass cls; // The JNI global class reference. +} JNFClassInfo; + +// JNFMemberInfo - struct for caching a field or method ID +// +// Create these by using the JNF_MEMBER_CACHE macro (below). +// The member ID is resolved lazily. +typedef struct _JNFMemberInfo { + const char *name; // The name of the member + const char *sig; // The signature of the member + BOOL isStatic; // Is this member declared static? + JNFClassInfo *classInfo; // points to the JNFClassInfo struct of + // which this field/method is a member. + union _j { + jfieldID fieldID; // If field, the JNI field ID + jmethodID methodID; // If method, the JNI method ID + } j; +} JNFMemberInfo; + + +/* + * JNI Utility Functions + * + * These functions make use of class and method ID caching, so they + * are more efficient than simply calling their JNI equivalents directly. + * They also detect Java exceptions and throw a corresponding + * NSException when JNI returns with a Java exception. + * Therefore, you should be prepared to handle exceptions + * before they propagate either back to the VM or up + * to the run loop. + */ + +// JNFIsInstanceOf - returns whether obj is an instance of clazz +JNF_EXPORT extern BOOL JNFIsInstanceOf(JNIEnv *env, jobject obj, JNFClassInfo *clazz); + +// Creating instances +JNF_EXPORT extern jobject JNFNewObject(JNIEnv *env, JNFMemberInfo *constructor, ...); + +// Creating arrays +JNF_EXPORT extern jobjectArray JNFNewObjectArray (JNIEnv *env, JNFClassInfo *clazz, jsize length); +JNF_EXPORT extern jbooleanArray JNFNewBooleanArray (JNIEnv *env, jsize length); +JNF_EXPORT extern jbyteArray JNFNewByteArray (JNIEnv *env, jsize length); +JNF_EXPORT extern jcharArray JNFNewCharArray (JNIEnv *env, jsize length); +JNF_EXPORT extern jshortArray JNFNewShortArray (JNIEnv *env, jsize length); +JNF_EXPORT extern jintArray JNFNewIntArray (JNIEnv *env, jsize length); +JNF_EXPORT extern jlongArray JNFNewLongArray (JNIEnv *env, jsize length); +JNF_EXPORT extern jfloatArray JNFNewFloatArray (JNIEnv *env, jsize length); +JNF_EXPORT extern jdoubleArray JNFNewDoubleArray (JNIEnv *env, jsize length); + +// Non-static getters +JNF_EXPORT extern jobject JNFGetObjectField (JNIEnv *env, jobject obj, JNFMemberInfo *field); +JNF_EXPORT extern jboolean JNFGetBooleanField(JNIEnv *env, jobject obj, JNFMemberInfo *field); +JNF_EXPORT extern jbyte JNFGetByteField (JNIEnv *env, jobject obj, JNFMemberInfo *field); +JNF_EXPORT extern jchar JNFGetCharField (JNIEnv *env, jobject obj, JNFMemberInfo *field); +JNF_EXPORT extern jshort JNFGetShortField (JNIEnv *env, jobject obj, JNFMemberInfo *field); +JNF_EXPORT extern jint JNFGetIntField (JNIEnv *env, jobject obj, JNFMemberInfo *field); +JNF_EXPORT extern jlong JNFGetLongField (JNIEnv *env, jobject obj, JNFMemberInfo *field); +JNF_EXPORT extern jfloat JNFGetFloatField (JNIEnv *env, jobject obj, JNFMemberInfo *field); +JNF_EXPORT extern jdouble JNFGetDoubleField (JNIEnv *env, jobject obj, JNFMemberInfo *field); + +// Static getters +JNF_EXPORT extern jobject JNFGetStaticObjectField (JNIEnv *env, JNFMemberInfo *field); +JNF_EXPORT extern jboolean JNFGetStaticBooleanField(JNIEnv *env, JNFMemberInfo *field); +JNF_EXPORT extern jbyte JNFGetStaticByteField (JNIEnv *env, JNFMemberInfo *field); +JNF_EXPORT extern jchar JNFGetStaticCharField (JNIEnv *env, JNFMemberInfo *field); +JNF_EXPORT extern jshort JNFGetStaticShortField (JNIEnv *env, JNFMemberInfo *field); +JNF_EXPORT extern jint JNFGetStaticIntField (JNIEnv *env, JNFMemberInfo *field); +JNF_EXPORT extern jlong JNFGetStaticLongField (JNIEnv *env, JNFMemberInfo *field); +JNF_EXPORT extern jfloat JNFGetStaticFloatField (JNIEnv *env, JNFMemberInfo *field); +JNF_EXPORT extern jdouble JNFGetStaticDoubleField (JNIEnv *env, JNFMemberInfo *field); + +// Non-static setters +JNF_EXPORT extern void JNFSetObjectField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jobject val); +JNF_EXPORT extern void JNFSetBooleanField(JNIEnv *env, jobject obj, JNFMemberInfo *field, jboolean val); +JNF_EXPORT extern void JNFSetByteField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jbyte val); +JNF_EXPORT extern void JNFSetCharField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jchar val); +JNF_EXPORT extern void JNFSetShortField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jshort val); +JNF_EXPORT extern void JNFSetIntField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jint val); +JNF_EXPORT extern void JNFSetLongField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jlong val); +JNF_EXPORT extern void JNFSetFloatField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jfloat val); +JNF_EXPORT extern void JNFSetDoubleField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jdouble val); + +// Static setters +JNF_EXPORT extern void JNFSetStaticObjectField (JNIEnv *env, JNFMemberInfo *field, jobject val); +JNF_EXPORT extern void JNFSetStaticBooleanField(JNIEnv *env, JNFMemberInfo *field, jboolean val); +JNF_EXPORT extern void JNFSetStaticByteField (JNIEnv *env, JNFMemberInfo *field, jbyte val); +JNF_EXPORT extern void JNFSetStaticCharField (JNIEnv *env, JNFMemberInfo *field, jchar val); +JNF_EXPORT extern void JNFSetStaticShortField (JNIEnv *env, JNFMemberInfo *field, jshort val); +JNF_EXPORT extern void JNFSetStaticIntField (JNIEnv *env, JNFMemberInfo *field, jint val); +JNF_EXPORT extern void JNFSetStaticLongField (JNIEnv *env, JNFMemberInfo *field, jlong val); +JNF_EXPORT extern void JNFSetStaticFloatField (JNIEnv *env, JNFMemberInfo *field, jfloat val); +JNF_EXPORT extern void JNFSetStaticDoubleField (JNIEnv *env, JNFMemberInfo *field, jdouble val); + +// Calling instance methods +JNF_EXPORT extern void JNFCallVoidMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...); +JNF_EXPORT extern jobject JNFCallObjectMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...); +JNF_EXPORT extern jboolean JNFCallBooleanMethod(JNIEnv *env, jobject obj, JNFMemberInfo *method, ...); +JNF_EXPORT extern jbyte JNFCallByteMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...); +JNF_EXPORT extern jchar JNFCallCharMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...); +JNF_EXPORT extern jshort JNFCallShortMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...); +JNF_EXPORT extern jint JNFCallIntMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...); +JNF_EXPORT extern jlong JNFCallLongMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...); +JNF_EXPORT extern jfloat JNFCallFloatMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...); +JNF_EXPORT extern jdouble JNFCallDoubleMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...); + +// Calling static methods +JNF_EXPORT extern void JNFCallStaticVoidMethod (JNIEnv *env, JNFMemberInfo *method, ...); +JNF_EXPORT extern jobject JNFCallStaticObjectMethod (JNIEnv *env, JNFMemberInfo *method, ...); +JNF_EXPORT extern jboolean JNFCallStaticBooleanMethod(JNIEnv *env, JNFMemberInfo *method, ...); +JNF_EXPORT extern jbyte JNFCallStaticByteMethod (JNIEnv *env, JNFMemberInfo *method, ...); +JNF_EXPORT extern jchar JNFCallStaticCharMethod (JNIEnv *env, JNFMemberInfo *method, ...); +JNF_EXPORT extern jshort JNFCallStaticShortMethod (JNIEnv *env, JNFMemberInfo *method, ...); +JNF_EXPORT extern jint JNFCallStaticIntMethod (JNIEnv *env, JNFMemberInfo *method, ...); +JNF_EXPORT extern jlong JNFCallStaticLongMethod (JNIEnv *env, JNFMemberInfo *method, ...); +JNF_EXPORT extern jfloat JNFCallStaticFloatMethod (JNIEnv *env, JNFMemberInfo *method, ...); +JNF_EXPORT extern jdouble JNFCallStaticDoubleMethod (JNIEnv *env, JNFMemberInfo *method, ...); + +// Global references +JNF_EXPORT extern jobject JNFNewGlobalRef(JNIEnv *env, jobject obj); +JNF_EXPORT extern void JNFDeleteGlobalRef(JNIEnv *env, jobject globalRef); +JNF_EXPORT extern jobject JNFNewWeakGlobalRef(JNIEnv *env, jobject obj); +JNF_EXPORT extern void JNFDeleteWeakGlobalRef(JNIEnv *env, jobject globalRef); + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFJNI.m b/src/libjnf/JavaNativeFoundation/JNFJNI.m new file mode 100644 index 0000000000..1d20327ccf --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFJNI.m @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFJNI.h" + +#import "JNFAssert.h" +#import "debug.h" + +// constants ripped from jvm.h +#define JVM_SIGNATURE_ARRAY '[' +#define JVM_SIGNATURE_BYTE 'B' +#define JVM_SIGNATURE_CHAR 'C' +#define JVM_SIGNATURE_CLASS 'L' +#define JVM_SIGNATURE_ENDCLASS ';' +#define JVM_SIGNATURE_ENUM 'E' +#define JVM_SIGNATURE_FLOAT 'F' +#define JVM_SIGNATURE_DOUBLE 'D' +#define JVM_SIGNATURE_FUNC '(' +#define JVM_SIGNATURE_ENDFUNC ')' +#define JVM_SIGNATURE_INT 'I' +#define JVM_SIGNATURE_LONG 'J' +#define JVM_SIGNATURE_SHORT 'S' +#define JVM_SIGNATURE_VOID 'V' +#define JVM_SIGNATURE_BOOLEAN 'Z' + +// IS_METHOD - Does the parameter point to a method member? +// +// This is used mostly in asserts. +#define IS_METHOD(member) (*(member->sig) == SIGNATURE_FUNC) + +static inline BOOL isMethod(JNFMemberInfo *member) { + return (*(member->sig)) == JVM_SIGNATURE_FUNC; +} + +static void JNFLookupClass(JNIEnv *env, JNFClassInfo *class) { + jclass localCls = NULL; + JNF_ASSERT_COND(class); + localCls = (*env)->FindClass(env, class->name); + if (localCls == NULL) [JNFException raiseUnnamedException:env]; + + class->cls = JNFNewGlobalRef(env, localCls); + (*env)->DeleteLocalRef(env, localCls); + if (class->cls == NULL) [JNFException raiseUnnamedException:env]; +} + +static void JNFLookupMemberID(JNIEnv *env, JNFMemberInfo *member) { + JNF_ASSERT_COND(member); + JNF_ASSERT_COND(member->classInfo); + + if (member->classInfo->cls == NULL) JNFLookupClass(env, member->classInfo); + + if (isMethod(member)) { + member->j.methodID = member->isStatic ? + (*env)->GetStaticMethodID(env, member->classInfo->cls, member->name, member->sig) : + (*env)->GetMethodID(env, member->classInfo->cls, member->name, member->sig); + } else { // This member is a field + member->j.fieldID = member->isStatic ? + (*env)->GetStaticFieldID(env, member->classInfo->cls, member->name, member->sig) : + (*env)->GetFieldID(env, member->classInfo->cls, member->name, member->sig); + } + + // If NULL, then exception occurred + if (member->j.methodID == NULL) [JNFException raiseUnnamedException:env]; +} + +BOOL JNFIsInstanceOf(JNIEnv *env, jobject obj, JNFClassInfo *clazz) { + if (clazz->cls == NULL) JNFLookupClass(env, clazz); + return (BOOL)(*env)->IsInstanceOf(env, obj, clazz->cls); +} + +// +// A whole mess o' macros +// +// All of these macros provide caching of class refs and member IDs, +// which speeds all member accesses following the first. In addition, +// Java exceptions are caught and turned into NSExceptions, +// so error handling is much easier on the native side. +// +// You can use these if you need them for optimization, but it's generally +// easier and better to use the utility functions in jni_utilities.h. + +// LOOKUP_MEMBER_ID - Lookup a fieldID if needed +// +// Give this macro a JNFMemberInfo*, and it will +// lookup and cache the field ID as needed. +#define LOOKUP_MEMBER_ID(env, member) \ +if (member->j.fieldID == NULL) \ +JNFLookupMemberID(env, member) + +#ifdef RAWT_DEBUG +#define VERIFY_MEMBERS +#endif + +#ifdef VERIFY_MEMBERS +#define VERIFY_FIELD(env, obj, field, sig) VerifyMember(env, obj, field, sig, NO) +#define VERIFY_METHOD(env, obj, method, sig) VerifyMember(env, obj, method, sig, YES) +#else +#define VERIFY_FIELD(env, obj, member, sig) +#define VERIFY_METHOD(env, obj, member, sig) +#endif /* RAWT_DEBUG */ + +// GET_FIELD - Safe way to get a java field +// +// This macro takes care of the caching and exception +// propgation. +#define GET_FIELD(env, obj, field, result, sig, jni_call) \ + LOOKUP_MEMBER_ID(env, field); \ + VERIFY_FIELD(env, obj, field, sig); \ + result = (*env)->jni_call(env, obj, field->j.fieldID); \ + JNF_CHECK_AND_RETHROW_EXCEPTION(env); + +// GET_STATIC_FIELD +// +#define GET_STATIC_FIELD(env, field, result, sig, jni_call) \ + LOOKUP_MEMBER_ID(env, field); \ + VERIFY_FIELD(env, NULL, field, sig); \ + result = (*env)->jni_call(env, field->classInfo->cls, field->j.fieldID); \ + JNF_CHECK_AND_RETHROW_EXCEPTION(env); + +// SET_FIELD - Safe way to set a java field +// +// Similar to GET_FIELD +#define SET_FIELD(env, obj, field, val, sig, jni_call) \ + LOOKUP_MEMBER_ID(env, field); \ + VERIFY_FIELD(env, obj, field, sig); \ + (*env)->jni_call(env, obj, field->j.fieldID, val); \ + JNF_CHECK_AND_RETHROW_EXCEPTION(env); + +// SET_STATIC_FIELD +// +#define SET_STATIC_FIELD(env, field, val, sig, jni_call) \ + LOOKUP_MEMBER_ID(env, field); \ + VERIFY_FIELD(env, NULL, field, sig); \ + (*env)->jni_call(env, field->classInfo->cls, field->j.fieldID, val); \ + JNF_CHECK_AND_RETHROW_EXCEPTION(env); + +// CALL_VOID_METHOD +// +// "args" is a va_list +#define CALL_VOID_METHOD(env, obj, method, jni_call, args) \ + LOOKUP_MEMBER_ID(env, method); \ + VERIFY_METHOD(env, obj, method, JVM_SIGNATURE_VOID); \ + (*env)->jni_call(env, obj, method->j.methodID, args); \ + JNF_CHECK_AND_RETHROW_EXCEPTION(env); + +// CALL_STATIC_VOID_METHOD +// +// "args" is a va_list +#define CALL_STATIC_VOID_METHOD(env, method, jni_call, args) \ + LOOKUP_MEMBER_ID(env, method); \ + VERIFY_METHOD(env, NULL, method, JVM_SIGNATURE_VOID); \ + (*env)->jni_call(env, method->classInfo->cls, method->j.methodID, args); \ + JNF_CHECK_AND_RETHROW_EXCEPTION(env); + +// CALL_METHOD - Call a method that returns a value +// +// "args" is a va_list +#define CALL_METHOD(env, obj, method, result, sig, jni_call, args ) \ + LOOKUP_MEMBER_ID(env, method); \ + VERIFY_METHOD(env, obj, method, sig); \ + result = (*env)->jni_call(env, obj, method->j.methodID, args); \ + JNF_CHECK_AND_RETHROW_EXCEPTION(env); + +// CALL_STATIC_METHOD - Call a static method that returns a value +// +// "args" is a va_list +#define CALL_STATIC_METHOD(env, method, result, sig, jni_call, args) \ + LOOKUP_MEMBER_ID(env, method); \ + VERIFY_METHOD(env, NULL, method, sig); \ + result = (*env)->jni_call(env, method->classInfo->cls, method->j.methodID, args); \ + JNF_CHECK_AND_RETHROW_EXCEPTION(env); + + +// NEW_OBJECT - Create instances +// +// "constructor" is a JNFMemberInfo* to a constructor method +// "args" is a va_list of arguments +#define NEW_OBJECT(env, constructor, obj, args) \ + LOOKUP_MEMBER_ID(env, constructor); \ + VERIFY_METHOD(env, NULL, constructor, JVM_SIGNATURE_VOID); \ + obj = (*env)->NewObjectV(env, constructor->classInfo->cls, constructor->j.methodID, args); \ + JNF_CHECK_AND_RETHROW_EXCEPTION(env); + + +// +// Non-static getters & setters +#define GET_FIELD_IMPLEMENTATION(type, sig, jni_call) \ + type JNF ## jni_call(JNIEnv *env, jobject obj, JNFMemberInfo* field) { \ + type result; \ + JNF_ASSERT_COND(!field->isStatic); \ + GET_FIELD(env, obj, field, result, sig, jni_call); \ + return result; \ + } + +#define SET_FIELD_IMPLEMENTATION(type, sig, jni_call) \ + void JNF ## jni_call(JNIEnv *env, jobject obj, JNFMemberInfo* field, type val) {\ + JNF_ASSERT_COND(!field->isStatic); \ + SET_FIELD(env, obj, field, val, sig, jni_call); \ + } + +// +// Non-static getter implemenations +GET_FIELD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, GetObjectField) +GET_FIELD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, GetBooleanField) +GET_FIELD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, GetByteField) +GET_FIELD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, GetCharField) +GET_FIELD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, GetShortField) +GET_FIELD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, GetIntField) +GET_FIELD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, GetLongField) +GET_FIELD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, GetFloatField) +GET_FIELD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, GetDoubleField) + +// +// Non-static setter implemenations +SET_FIELD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, SetObjectField) +SET_FIELD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, SetBooleanField) +SET_FIELD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, SetByteField) +SET_FIELD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, SetCharField) +SET_FIELD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, SetShortField) +SET_FIELD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, SetIntField) +SET_FIELD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, SetLongField) +SET_FIELD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, SetFloatField) +SET_FIELD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, SetDoubleField) + +// +// Static getters & setters +#define GET_STATIC_FIELD_IMPLEMENTATION(type, sig, jni_call) \ + type JNF ## jni_call(JNIEnv *env, JNFMemberInfo* field) { \ + type result; \ + JNF_ASSERT_COND(field->isStatic); \ + GET_STATIC_FIELD(env, field, result, sig, jni_call); \ + return result; \ + } + +#define SET_STATIC_FIELD_IMPLEMENTATION(type, sig, jni_call) \ + void JNF ## jni_call(JNIEnv *env, JNFMemberInfo* field, type val) { \ + JNF_ASSERT_COND(field->isStatic); \ + SET_STATIC_FIELD(env, field, val, sig, jni_call); \ + } + +// +// Static getter implementations +GET_STATIC_FIELD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, GetStaticObjectField) +GET_STATIC_FIELD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, GetStaticBooleanField) +GET_STATIC_FIELD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, GetStaticByteField) +GET_STATIC_FIELD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, GetStaticCharField) +GET_STATIC_FIELD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, GetStaticShortField) +GET_STATIC_FIELD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, GetStaticIntField) +GET_STATIC_FIELD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, GetStaticLongField) +GET_STATIC_FIELD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, GetStaticFloatField) +GET_STATIC_FIELD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, GetStaticDoubleField) + +// +// Static setter implemenations +SET_STATIC_FIELD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, SetStaticObjectField) +SET_STATIC_FIELD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, SetStaticBooleanField) +SET_STATIC_FIELD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, SetStaticByteField) +SET_STATIC_FIELD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, SetStaticCharField) +SET_STATIC_FIELD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, SetStaticShortField) +SET_STATIC_FIELD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, SetStaticIntField) +SET_STATIC_FIELD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, SetStaticLongField) +SET_STATIC_FIELD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, SetStaticFloatField) +SET_STATIC_FIELD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, SetStaticDoubleField) + + +// +// Calling instance methods +// +// FIX: if an exception is thrown, va_end is not called. +// On i386, va_end is a null macro. Check on PPC to verify the same. +void JNFCallVoidMethod(JNIEnv *env, jobject obj, JNFMemberInfo* method, ...) { + va_list args; + JNF_ASSERT_COND(!method->isStatic); + va_start(args, method); + CALL_VOID_METHOD(env, obj, method, CallVoidMethodV, args); + va_end(args); +} + +#define CALL_METHOD_IMPLEMENTATION(type, sig, jni_call) \ + type JNF ## jni_call(JNIEnv *env, jobject obj, JNFMemberInfo* method, ...) {\ + type result; \ + va_list args; \ + JNF_ASSERT_COND(!method->isStatic); \ + va_start(args, method); \ + CALL_METHOD(env, obj, method, result, sig, jni_call ## V, args); \ + va_end(args); \ + return result; \ + } + +CALL_METHOD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, CallObjectMethod) +CALL_METHOD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, CallBooleanMethod) +CALL_METHOD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, CallByteMethod) +CALL_METHOD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, CallCharMethod) +CALL_METHOD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, CallShortMethod) +CALL_METHOD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, CallIntMethod) +CALL_METHOD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, CallLongMethod) +CALL_METHOD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, CallFloatMethod) +CALL_METHOD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, CallDoubleMethod) + +// +// Calling static methods +// +// FIX: if an exception is thrown, va_end is not called. +// On i386, va_end is a null macro. Check on PPC to verify the same. +void JNFCallStaticVoidMethod(JNIEnv *env, JNFMemberInfo* method, ...) { + va_list args; + JNF_ASSERT_COND(method->isStatic); + va_start(args, method); + CALL_STATIC_VOID_METHOD(env, method, CallStaticVoidMethodV, args); + va_end(args); +} + +#define CALL_STATIC_METHOD_IMPLEMENTATION(type, sig, jni_call) \ + type JNF ## jni_call(JNIEnv *env, JNFMemberInfo* method, ...) { \ + type result; \ + va_list args; \ + JNF_ASSERT_COND(method->isStatic); \ + va_start(args, method); \ + CALL_STATIC_METHOD(env, method, result, sig, jni_call ## V, args); \ + va_end(args); \ + return result; \ + } + +CALL_STATIC_METHOD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, CallStaticObjectMethod) +CALL_STATIC_METHOD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, CallStaticBooleanMethod) +CALL_STATIC_METHOD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, CallStaticByteMethod) +CALL_STATIC_METHOD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, CallStaticCharMethod) +CALL_STATIC_METHOD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, CallStaticShortMethod) +CALL_STATIC_METHOD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, CallStaticIntMethod) +CALL_STATIC_METHOD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, CallStaticLongMethod) +CALL_STATIC_METHOD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, CallStaticFloatMethod) +CALL_STATIC_METHOD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, CallStaticDoubleMethod) + +// +// Creating new object instances +jobject JNFNewObject(JNIEnv *env, JNFMemberInfo* constructor, ...) +{ + jobject newobj; + va_list args; + JNF_ASSERT_COND(!constructor->isStatic); + va_start(args, constructor); + NEW_OBJECT(env, constructor, newobj, args); + va_end(args); + return newobj; +} + +jobjectArray JNFNewObjectArray(JNIEnv *env, JNFClassInfo *clazz, jsize length) +{ + if (clazz->cls == NULL) JNFLookupClass(env, clazz); + JNF_ASSERT_COND(clazz->cls); + jobjectArray newArray = (*env)->NewObjectArray(env, length, clazz->cls, NULL); + JNF_CHECK_AND_RETHROW_EXCEPTION(env); + return newArray; +} + +#define NEW_PRIMITIVE_ARRAY(primitiveArrayType, methodName) \ + primitiveArrayType JNF ## methodName(JNIEnv *env, jsize length) { \ + primitiveArrayType array = (*env)->methodName(env, length); \ + JNF_CHECK_AND_RETHROW_EXCEPTION(env); \ + return array; \ + } + +NEW_PRIMITIVE_ARRAY(jbooleanArray, NewBooleanArray) +NEW_PRIMITIVE_ARRAY(jbyteArray, NewByteArray) +NEW_PRIMITIVE_ARRAY(jcharArray, NewCharArray) +NEW_PRIMITIVE_ARRAY(jshortArray, NewShortArray) +NEW_PRIMITIVE_ARRAY(jintArray, NewIntArray) +NEW_PRIMITIVE_ARRAY(jlongArray, NewLongArray) +NEW_PRIMITIVE_ARRAY(jfloatArray, NewFloatArray) +NEW_PRIMITIVE_ARRAY(jdoubleArray, NewDoubleArray) + + +// Class-related functions + +// A bottleneck for creating global references +jobject JNFNewGlobalRef(JNIEnv *env, jobject obj) +{ + if (!obj) return NULL; + + jobject globalRef = (*env)->NewGlobalRef(env, obj); + if (!globalRef) JNF_CHECK_AND_RETHROW_EXCEPTION(env); + + // JNF_WARN("Created global ref %#08lx to object:", globalRef); + // JNFDumpJavaObject(env, globalRef); + return globalRef; +} + +// A bottleneck for deleting global references. +void JNFDeleteGlobalRef(JNIEnv *env, jobject globalRef) +{ + if (!globalRef) return; + // JNF_WARN("Deleting global ref %#08lx to object:", globalRef); + // JNFDumpJavaObject(env, globalRef); + (*env)->DeleteGlobalRef(env, globalRef); +} + +// A bottleneck for creating weak global references +jobject JNFNewWeakGlobalRef(JNIEnv *env, jobject obj) +{ + if (!obj) return NULL; + + jobject globalRef = (*env)->NewWeakGlobalRef(env, obj); + if (!globalRef) JNF_CHECK_AND_RETHROW_EXCEPTION(env); + + // JNF_WARN("Created global ref %#08lx to object:", globalRef); + // JNFDumpJavaObject(env, globalRef); + return globalRef; +} + +// A bottleneck for deleting weak global references. +void JNFDeleteWeakGlobalRef(JNIEnv *env, jobject globalRef) +{ + if (!globalRef) return; + // JNF_WARN("Deleting global ref %#08lx to object:", globalRef); + // JNFDumpJavaObject(env, globalRef); + (*env)->DeleteWeakGlobalRef(env, globalRef); +} diff --git a/src/libjnf/JavaNativeFoundation/JNFJObjectWrapper.h b/src/libjnf/JavaNativeFoundation/JNFJObjectWrapper.h new file mode 100644 index 0000000000..58f5f0bd5e --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFJObjectWrapper.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Simple wrapper classes to hold Java Objects in JNI global references. + * + * This is used to pass Java objects across thread boundries, often through + * -performSelectorOnMainThread invocations. This wrapper properly creates a + * new global ref, and clears it on -dealloc or -finalize, attaching to the + * current VM, attaching the current thread if necessary, releasing the global + * ref, and detaching the thread from the VM if it attached it. + * + * Destruction of this wrapper is expensive if the jobject has not been + * pre-cleared, because it must re-attach to the JVM. + * + * The JNFWeakJObjectWrapper manages a weak global reference which may become + * invalid if the JVM garbage collects the original object. + */ + +#import +#import + +__BEGIN_DECLS + +JNF_EXPORT +@interface JNFJObjectWrapper : NSObject + ++ (JNFJObjectWrapper *) wrapperWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env; +- (id) initWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env; +- (void) setJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env; // clears any pre-existing global-ref +- (jobject) jObjectWithEnv:(JNIEnv *)env; // returns a new local-ref, must be released with DeleteLocalRef + +@property (readonly, nonatomic, assign) jobject jObject; + +@end + + +JNF_EXPORT +@interface JNFWeakJObjectWrapper : JNFJObjectWrapper { } + ++ (JNFWeakJObjectWrapper *) wrapperWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env; + +@end + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFJObjectWrapper.m b/src/libjnf/JavaNativeFoundation/JNFJObjectWrapper.m new file mode 100644 index 0000000000..17eac99e24 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFJObjectWrapper.m @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFJObjectWrapper.h" + +#import "JNFJNI.h" +#import "JNFThread.h" + +@interface JNFJObjectWrapper () +@property (readwrite, nonatomic, assign) jobject jObject; +@end + +@implementation JNFJObjectWrapper + +- (jobject) _getWithEnv:(__unused JNIEnv *)env { + return self.jObject; +} + +- (jobject) _createObj:(jobject)jObjectIn withEnv:(JNIEnv *)env { + return JNFNewGlobalRef(env, jObjectIn); +} + +- (void) _destroyObj:(jobject)jObjectIn withEnv:(JNIEnv *)env { + JNFDeleteGlobalRef(env, jObjectIn); +} + ++ (JNFJObjectWrapper *) wrapperWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env { + return [[[JNFJObjectWrapper alloc] initWithJObject:jObjectIn withEnv:env] autorelease]; +} + +- (id) initWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env { + self = [super init]; + if (!self) return self; + + if (jObjectIn) { + self.jObject = [self _createObj:jObjectIn withEnv:env]; + } + + return self; +} + +- (jobject) jObjectWithEnv:(JNIEnv *)env { + jobject validObj = [self _getWithEnv:env]; + if (!validObj) return NULL; + + return (*env)->NewLocalRef(env, validObj); +} + +- (void) setJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env { + jobject const jobj = self.jObject; + if (jobj == jObjectIn) return; + + if (jobj) { + [self _destroyObj:jobj withEnv:env]; + } + + if (jObjectIn) { + self.jObject = [self _createObj:jObjectIn withEnv:env]; + } else { + self.jObject = NULL; + } +} + +- (void) clearJObjectReference { + jobject const jobj = self.jObject; + if (!jobj) return; + + JNFThreadContext threadContext = JNFThreadDetachImmediately; + JNIEnv *env = JNFObtainEnv(&threadContext); + if (env == NULL) return; // leak? + + [self _destroyObj:jobj withEnv:env]; + self.jObject = NULL; + + JNFReleaseEnv(env, &threadContext); +} + +- (void) dealloc { + [self clearJObjectReference]; + [super dealloc]; +} + +@end + + +@implementation JNFWeakJObjectWrapper + ++ (JNFWeakJObjectWrapper *) wrapperWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env { + return [[[JNFWeakJObjectWrapper alloc] initWithJObject:jObjectIn withEnv:env] autorelease]; +} + +- (jobject) _getWithEnv:(JNIEnv *)env { + jobject const jobj = self.jObject; + + if ((*env)->IsSameObject(env, jobj, NULL) == JNI_TRUE) { + self.jObject = NULL; // object went invalid + return NULL; + } + return jobj; +} + +- (jobject) _createObj:(jobject)jObjectIn withEnv:(JNIEnv *)env { + return JNFNewWeakGlobalRef(env, jObjectIn); +} + +- (void) _destroyObj:(jobject)jObjectIn withEnv:(JNIEnv *)env { + JNFDeleteWeakGlobalRef(env, jObjectIn); +} + +@end diff --git a/src/libjnf/JavaNativeFoundation/JNFNumber.h b/src/libjnf/JavaNativeFoundation/JNFNumber.h new file mode 100644 index 0000000000..0a4683bf30 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFNumber.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Functions that convert between number container classes. + */ + +#import + +#import + +__BEGIN_DECLS + +/* + * Converts java.lang.Number to an NSNumber + * NOTE: Return value is auto-released, so if you need to hang on to it, you should retain it. + */ +JNF_EXPORT extern NSNumber *JNFJavaToNSNumber(JNIEnv *env, jobject n); + +/* + * Converts an NSNumber to a java.lang.Number + * Only returns java.lang.Longs or java.lang.Doubles. + * NOTE: This returns a JNI Local Ref. Any code that calls must call DeleteLocalRef with the return value. + */ +JNF_EXPORT extern jobject JNFNSToJavaNumber(JNIEnv *env, NSNumber *n); + +/* + * Converts a java.lang.Boolean constants to the CFBooleanRef constants + */ +JNF_EXPORT extern CFBooleanRef JNFJavaToCFBoolean(JNIEnv* env, jobject b); + +/* + * Converts a CFBooleanRef constants to the java.lang.Boolean constants + */ +JNF_EXPORT extern jobject JNFCFToJavaBoolean(JNIEnv *env, CFBooleanRef b); + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFNumber.m b/src/libjnf/JavaNativeFoundation/JNFNumber.m new file mode 100644 index 0000000000..aa8327625f --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFNumber.m @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFNumber.h" +#import "JNFJNI.h" + +static JNF_CLASS_CACHE(sjc_Long, "java/lang/Long"); +static JNF_CLASS_CACHE(sjc_Double, "java/lang/Double"); +static JNF_CLASS_CACHE(sjc_Boolean, "java/lang/Boolean"); + +NSNumber *JNFJavaToNSNumber(JNIEnv* env, jobject n) +{ + if (n == NULL) return nil; + + static JNF_CLASS_CACHE(sjc_Number, "java/lang/Number"); + static JNF_CLASS_CACHE(sjc_Integer, "java/lang/Integer"); + static JNF_CLASS_CACHE(sjc_Float, "java/lang/Float"); + static JNF_CLASS_CACHE(sjc_Byte, "java/lang/Byte"); + static JNF_CLASS_CACHE(sjc_Short, "java/lang/Short"); + + // AWT_THREADING Safe (known object) + if (JNFIsInstanceOf(env, n, &sjc_Integer)) { + static JNF_MEMBER_CACHE(jm_intValue, sjc_Number, "intValue", "()I"); + return [NSNumber numberWithInt:JNFCallIntMethod(env, n, jm_intValue)]; + } else if (JNFIsInstanceOf(env, n, &sjc_Long)) { + static JNF_MEMBER_CACHE(jm_longValue, sjc_Number, "longValue", "()J"); + return [NSNumber numberWithLongLong:JNFCallLongMethod(env, n, jm_longValue)]; + } else if (JNFIsInstanceOf(env, n, &sjc_Float)) { + static JNF_MEMBER_CACHE(jm_floatValue, sjc_Number, "floatValue", "()F"); + return [NSNumber numberWithFloat:JNFCallFloatMethod(env, n, jm_floatValue)]; + } else if (JNFIsInstanceOf(env, n, &sjc_Double)) { + static JNF_MEMBER_CACHE(jm_doubleValue, sjc_Number, "doubleValue", "()D"); + return [NSNumber numberWithDouble:JNFCallDoubleMethod(env, n, jm_doubleValue)]; + } else if (JNFIsInstanceOf(env, n, &sjc_Byte)) { + static JNF_MEMBER_CACHE(jm_byteValue, sjc_Number, "byteValue", "()B"); + return [NSNumber numberWithChar:JNFCallByteMethod(env, n, jm_byteValue)]; + } else if (JNFIsInstanceOf(env, n, &sjc_Short)) { + static JNF_MEMBER_CACHE(jm_shortValue, sjc_Number, "shortValue", "()S"); + return [NSNumber numberWithShort:JNFCallShortMethod(env, n, jm_shortValue)]; + } + + return [NSNumber numberWithInt:0]; +} + +jobject JNFNSToJavaNumber(JNIEnv *env, NSNumber *n) +{ + if (n == nil) return NULL; + + if (CFNumberIsFloatType((CFNumberRef)n)) { + static JNF_CTOR_CACHE(jm_Double, sjc_Double, "(D)V"); + return JNFNewObject(env, jm_Double, [n doubleValue]); // AWT_THREADING Safe (known object) + } else { + static JNF_CTOR_CACHE(jm_Long, sjc_Long, "(J)V"); + return JNFNewObject(env, jm_Long, [n longLongValue]); // AWT_THREADING Safe (known object) + } +} + +CFBooleanRef JNFJavaToCFBoolean(JNIEnv* env, jobject b) +{ + if (b == NULL) return NULL; + if (!JNFIsInstanceOf(env, b, &sjc_Boolean)) return NULL; + static JNF_MEMBER_CACHE(jm_booleanValue, sjc_Boolean, "booleanValue", "()Z"); + return JNFCallBooleanMethod(env, b, jm_booleanValue) ? kCFBooleanTrue : kCFBooleanTrue; +} + +jobject JNFCFToJavaBoolean(JNIEnv *env, CFBooleanRef b) +{ + if (b == NULL) return NULL; + static JNF_STATIC_MEMBER_CACHE(js_TRUE, sjc_Boolean, "TRUE", "java/lang/Boolean"); + static JNF_STATIC_MEMBER_CACHE(js_FALSE, sjc_Boolean, "FALSE", "java/lang/Boolean"); + return JNFGetStaticObjectField(env, (b == kCFBooleanTrue) ? js_TRUE : js_FALSE); +} diff --git a/src/libjnf/JavaNativeFoundation/JNFObject.h b/src/libjnf/JavaNativeFoundation/JNFObject.h new file mode 100644 index 0000000000..24c1134d02 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFObject.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Functions that access some of the base functionality of java.lang.Object. + */ + +#import + +#import + +__BEGIN_DECLS + +/* + * Returns Object.equals() for the two items + */ +JNF_EXPORT extern BOOL JNFObjectEquals(JNIEnv* env, jobject a, jobject b); + +/* + * Returns Object.toString() as an NSString + */ +JNF_EXPORT extern NSString *JNFObjectToString(JNIEnv *env, jobject obj); + +/* + * Returns Object.getClass().toString() as an NSString. Useful in gdb. + */ +JNF_EXPORT extern NSString *JNFObjectClassName(JNIEnv* env, jobject obj); + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFObject.m b/src/libjnf/JavaNativeFoundation/JNFObject.m new file mode 100644 index 0000000000..510e58e449 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFObject.m @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFObject.h" + +#import "JNFJNI.h" +#import "JNFString.h" + +static JNF_CLASS_CACHE(sjc_Object, "java/lang/Object"); + +BOOL JNFObjectEquals(JNIEnv* env, jobject a, jobject b) +{ + if ((a == NULL) && (b == NULL)) return YES; + if ((a == NULL) || (b == NULL)) return NO; + + static JNF_MEMBER_CACHE(jm_equals, sjc_Object, "equals", "(Ljava/lang/Object;)Z"); + return (BOOL)JNFCallBooleanMethod(env, a, jm_equals, b); // AWT_THREADING Safe (!appKit) +} + +NSString *JNFObjectToString(JNIEnv *env, jobject obj) +{ + static JNF_MEMBER_CACHE(jm_toString, sjc_Object, "toString", "()Ljava/lang/String;"); + jobject name = JNFCallObjectMethod(env, obj, jm_toString); // AWT_THREADING Safe (known object) + + id result = JNFJavaToNSString(env, name); + (*env)->DeleteLocalRef(env, name); + return result; +} + +NSString *JNFObjectClassName(JNIEnv* env, jobject obj) +{ + static JNF_MEMBER_CACHE(jm_getClass, sjc_Object, "getClass", "()Ljava/lang/Class;"); + + jobject clz = JNFCallObjectMethod(env, obj, jm_getClass); // AWT_THREADING Safe (known object) + NSString *result = JNFObjectToString(env, clz); + (*env)->DeleteLocalRef(env, clz); + return result; +} diff --git a/src/libjnf/JavaNativeFoundation/JNFPath.h b/src/libjnf/JavaNativeFoundation/JNFPath.h new file mode 100644 index 0000000000..401bd69470 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFPath.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Functions that create strings that are in the proper format for holding + * paths in Java and native. + */ + +#import + +#import + +__BEGIN_DECLS + +/* + * Returns a jstring in precomposed UTF16 format that is compatable with Java's + * expectation of the UTF16 format for strings to be displayed. + */ +JNF_EXPORT extern jstring JNFNormalizedJavaStringForPath(JNIEnv *env, NSString *path); + +/* + * Returns an NSString in decomposed UTF16 format that is compatable with HFS's + * expectation of the UTF16 format for file system paths. + * NOTE: this NSString is autoreleased. + */ +JNF_EXPORT extern NSString *JNFNormalizedNSStringForPath(JNIEnv *env, jstring path); + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFPath.m b/src/libjnf/JavaNativeFoundation/JNFPath.m new file mode 100644 index 0000000000..608a9e3b14 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFPath.m @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFPath.h" + +#import + +#import "JNFString.h" + +jstring JNFNormalizedJavaStringForPath(JNIEnv *env, NSString *inString) +{ + if (inString == nil) return NULL; + + CFMutableStringRef mutableDisplayName = CFStringCreateMutableCopy(NULL, 0, (CFStringRef)inString); + CFStringNormalize(mutableDisplayName, kCFStringNormalizationFormC); + jstring returnValue = JNFNSToJavaString(env, (NSString *)mutableDisplayName); + CFRelease(mutableDisplayName); + + return returnValue; +} + +NSString *JNFNormalizedNSStringForPath(JNIEnv *env, jstring javaString) +{ + if (javaString == NULL) return nil; + + // We were given a filename, so convert it to a compatible representation for the file system. + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *fileName = JNFJavaToNSString(env, javaString); + const char *compatibleFilename = [fm fileSystemRepresentationWithPath:fileName]; + return [fm stringWithFileSystemRepresentation:compatibleFilename length:strlen(compatibleFilename)]; +} diff --git a/src/libjnf/JavaNativeFoundation/JNFRunLoop.h b/src/libjnf/JavaNativeFoundation/JNFRunLoop.h new file mode 100644 index 0000000000..e03e2a1863 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFRunLoop.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Used to perform selectors and blocks in the Java runloop mode. + */ + +#import +#import + +__BEGIN_DECLS + +JNF_EXPORT extern NSString *JNFRunLoopDidStartNotification; + +JNF_EXPORT +@interface JNFRunLoop : NSObject { } + ++ (NSString *)javaRunLoopMode; ++ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait; +#if __BLOCKS__ ++ (void)performOnMainThreadWaiting:(BOOL)waitUntilDone withBlock:(void (^)(void))block; +#endif + +@end + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFRunLoop.m b/src/libjnf/JavaNativeFoundation/JNFRunLoop.m new file mode 100644 index 0000000000..c3ece5bfea --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFRunLoop.m @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2009-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFRunLoop.h" + +#import + + +NSString *JNFRunLoopDidStartNotification = @"JNFRunLoopDidStartNotification"; + +static NSString *AWTRunLoopMode = @"AWTRunLoopMode"; +static NSArray *sPerformModes = nil; + +@implementation JNFRunLoop + ++ (void)initialize { + if (sPerformModes) return; + sPerformModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, NSModalPanelRunLoopMode, NSEventTrackingRunLoopMode, AWTRunLoopMode, nil]; +} + ++ (NSString *)javaRunLoopMode { + return AWTRunLoopMode; +} + ++ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)waitUntilDone { + [target performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:waitUntilDone modes:sPerformModes]; +} + +#if __BLOCKS__ + ++ (void)_performDirectBlock:(void (^)(void))block { + block(); +} + ++ (void)_performCopiedBlock:(void (^)(void))newBlock { + newBlock(); + Block_release(newBlock); +} + ++ (void)performOnMainThreadWaiting:(BOOL)waitUntilDone withBlock:(void (^)(void))block { + if (waitUntilDone) { + [self performOnMainThread:@selector(_performDirectBlock:) on:self withObject:block waitUntilDone:YES]; + } else { + void (^newBlock)(void) = Block_copy(block); + [self performOnMainThread:@selector(_performCopiedBlock:) on:self withObject:newBlock waitUntilDone:NO]; + } +} + +#endif + +@end diff --git a/src/libjnf/JavaNativeFoundation/JNFRunnable.h b/src/libjnf/JavaNativeFoundation/JNFRunnable.h new file mode 100644 index 0000000000..1db4e4e8bc --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFRunnable.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Creates NSInvocations which wrap java.lang.Runnables. + */ + +#import +#import + +__BEGIN_DECLS + +JNF_EXPORT +@interface JNFRunnable : NSObject { } ++ (NSInvocation *) invocationWithRunnable:(jobject)runnable withEnv:(JNIEnv *)env; +#if __BLOCKS__ ++ (void(^)(void)) blockWithRunnable:(jobject)runnable withEnv:(JNIEnv *)env; +#endif +@end + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFRunnable.m b/src/libjnf/JavaNativeFoundation/JNFRunnable.m new file mode 100644 index 0000000000..7df6249f8f --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFRunnable.m @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2009-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFRunnable.h" +#import "JNFThread.h" +#import "JNFJObjectWrapper.h" + + +static JNF_CLASS_CACHE(jc_Runnable, "java/lang/Runnable"); +static JNF_MEMBER_CACHE(jm_run, jc_Runnable, "run", "()V"); + +@interface JNFRunnableWrapper : JNFJObjectWrapper { } +- (void) invokeRunnable; +@end + +@implementation JNFRunnableWrapper + +- (void) invokeRunnable { + JNFThreadContext ctx = JNFThreadDetachOnThreadDeath | JNFThreadSetSystemClassLoaderOnAttach | JNFThreadAttachAsDaemon; + JNIEnv *env = JNFObtainEnv(&ctx); + JNFCallVoidMethod(env, [self jObjectWithEnv:env], jm_run); + JNFReleaseEnv(env, &ctx); +} + +@end + + +@implementation JNFRunnable + ++ (NSInvocation *) invocationWithRunnable:(jobject)runnable withEnv:(JNIEnv *)env { + SEL sel = @selector(invokeRunnable); + NSMethodSignature *sig = [JNFRunnableWrapper instanceMethodSignatureForSelector:sel]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; + [invocation retainArguments]; + [invocation setSelector:sel]; + + JNFRunnableWrapper *runnableWrapper = [[JNFRunnableWrapper alloc] initWithJObject:runnable withEnv:env]; + [invocation setTarget:runnableWrapper]; + [runnableWrapper release]; + + return invocation; +} + +#if __BLOCKS__ ++ (void(^)(void)) blockWithRunnable:(jobject)runnable withEnv:(JNIEnv *)env { + JNFJObjectWrapper *runnableWrapper = [JNFJObjectWrapper wrapperWithJObject:runnable withEnv:env]; + + return [[^() { + JNFThreadContext ctx = JNFThreadDetachOnThreadDeath | JNFThreadSetSystemClassLoaderOnAttach | JNFThreadAttachAsDaemon; + JNIEnv *_block_local_env = JNFObtainEnv(&ctx); + JNFCallVoidMethod(env, [runnableWrapper jObjectWithEnv:_block_local_env], jm_run); + JNFReleaseEnv(_block_local_env, &ctx); + } copy] autorelease]; +} +#endif + +@end diff --git a/src/libjnf/JavaNativeFoundation/JNFString.h b/src/libjnf/JavaNativeFoundation/JNFString.h new file mode 100644 index 0000000000..6a8ba6d8e3 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFString.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Functions that create NSStrings, UTF16 unichars, or UTF8 chars from java.lang.Strings + */ + +#import + +#import + +__BEGIN_DECLS + +// Returns an NSString given a java.lang.String object +// NOTE: Return value is auto-released, so if you need to hang on to it, you should retain it. +JNF_EXPORT extern NSString *JNFJavaToNSString(JNIEnv *env, jstring javaString); + +// Returns a java.lang.String object as a JNI local ref. +// NOTE: This returns a JNI Local Ref. Any code that calls this should call DeleteLocalRef with the return value. +JNF_EXPORT extern jstring JNFNSToJavaString(JNIEnv *env, NSString *nsString); + +/* + * Gets UTF16 unichars from a Java string, and checks for errors and raises a JNFException if + * the unichars cannot be obtained from Java. + */ +JNF_EXPORT extern const unichar *JNFGetStringUTF16UniChars(JNIEnv *env, jstring javaString); + +/* + * Releases the unichars obtained from JNFGetStringUTF16UniChars() + */ +JNF_EXPORT extern void JNFReleaseStringUTF16UniChars(JNIEnv *env, jstring javaString, const unichar *unichars); + +/* + * Gets UTF8 chars from a Java string, and checks for errors and raises a JNFException if + * the chars cannot be obtained from Java. + */ +JNF_EXPORT extern const char *JNFGetStringUTF8Chars(JNIEnv *env, jstring javaString); + +/* + * Releases the chars obtained from JNFGetStringUTF8Chars() + */ +JNF_EXPORT extern void JNFReleaseStringUTF8Chars(JNIEnv *env, jstring javaString, const char *chars); + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFString.m b/src/libjnf/JavaNativeFoundation/JNFString.m new file mode 100644 index 0000000000..db6d465eb5 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFString.m @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFString.h" + +#import "JNFJNI.h" +#import "JNFAssert.h" +#import "debug.h" + +#define STACK_BUFFER_SIZE 64 + +/* + * Utility function to convert java String to NSString. We don't go through intermediate cString + * representation, since we are trying to preserve unicode characters from Java to NSString. + */ +NSString *JNFJavaToNSString(JNIEnv *env, jstring javaString) +{ + // We try very hard to only allocate and memcopy once. + if (javaString == NULL) return nil; + + jsize length = (*env)->GetStringLength(env, javaString); + unichar *buffer = (unichar *)calloc((size_t)length, sizeof(unichar)); + (*env)->GetStringRegion(env, javaString, 0, length, buffer); + NSString *str = (NSString *)CFStringCreateWithCharactersNoCopy(NULL, buffer, length, kCFAllocatorMalloc); + // NSLog(@"%@", str); + return [(NSString *)CFMakeCollectable(str) autorelease]; +} + +/* + * Utility function to convert NSString to Java string. We don't go through intermediate cString + * representation, since we are trying to preserve unicode characters in translation. + */ +jstring JNFNSToJavaString(JNIEnv *env, NSString *nsString) +{ + jstring res = nil; + if (nsString == nil) return NULL; + + unsigned long length = [nsString length]; + unichar *buffer; + unichar stackBuffer[STACK_BUFFER_SIZE]; + if (length > STACK_BUFFER_SIZE) { + buffer = (unichar *)calloc(length, sizeof(unichar)); + } else { + buffer = stackBuffer; + } + + JNF_ASSERT_COND(buffer != NULL); + [nsString getCharacters:buffer]; + res = (*env)->NewString(env, buffer, (jsize)length); + if (buffer != stackBuffer) free(buffer); + return res; +} + +const unichar *JNFGetStringUTF16UniChars(JNIEnv *env, jstring javaString) +{ + const jchar *unichars = NULL; + JNF_ASSERT_COND(javaString != NULL); + unichars = (*env)->GetStringChars(env, javaString, NULL); + if (unichars == NULL) [JNFException raise:env as:kNullPointerException reason:"unable to obtain characters from GetStringChars"]; + return (const unichar *)unichars; +} + +void JNFReleaseStringUTF16UniChars(JNIEnv *env, jstring javaString, const unichar *unichars) +{ + JNF_ASSERT_COND(unichars != NULL); + (*env)->ReleaseStringChars(env, javaString, (const jchar *)unichars); +} + +const char *JNFGetStringUTF8Chars(JNIEnv *env, jstring javaString) +{ + const char *chars = NULL; + JNF_ASSERT_COND(javaString != NULL); + chars = (*env)->GetStringUTFChars(env, javaString, NULL); + if (chars == NULL) [JNFException raise:env as:kNullPointerException reason:"unable to obtain characters from GetStringUTFChars"]; + return chars; +} + +void JNFReleaseStringUTF8Chars(JNIEnv *env, jstring javaString, const char *chars) +{ + JNF_ASSERT_COND(chars != NULL); + (*env)->ReleaseStringUTFChars(env, javaString, (const char *)chars); +} diff --git a/src/libjnf/JavaNativeFoundation/JNFThread.h b/src/libjnf/JavaNativeFoundation/JNFThread.h new file mode 100644 index 0000000000..f50f8010b2 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFThread.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Functions to help obtain a JNIEnv pointer in places where one cannot be passed + * though (callbacks, catagory functions, etc). Use sparingly. + */ + +#import +#import + +__BEGIN_DECLS + +// Options only apply if thread was not already attached to the JVM. +enum { + JNFThreadDetachImmediately = (1 << 1), + JNFThreadDetachOnThreadDeath = (1 << 2), + JNFThreadSetSystemClassLoaderOnAttach = (1 << 3), + JNFThreadAttachAsDaemon = (1 << 4) +}; + +typedef jlong JNFThreadContext; + + +/* + * Attaches the current thread to the Java VM if needed, and obtains a JNI environment + * to interact with the VM. Use a provided JNIEnv pointer for your current thread + * whenever possible, since this method is particularly expensive to the Java VM if + * used repeatedly. + * + * Provide a pointer to a JNFThreadContext to pass to JNFReleaseEnv(). + */ +JNF_EXPORT extern JNIEnv *JNFObtainEnv(JNFThreadContext *context) API_DEPRECATED("This functionality is no longer supported and may stop working in a future version of macOS.", macos(10.10, 10.16)); + +/* + * Release the JNIEnv for this thread, and detaches the current thread from the VM if + * it was not already attached. + */ +JNF_EXPORT extern void JNFReleaseEnv(JNIEnv *env, JNFThreadContext *context) API_DEPRECATED("This functionality is no longer supported and may stop working in a future version of macOS.", macos(10.10, 10.16)); + + +#if __BLOCKS__ + +/* + * Performs the same attach/detach as JNFObtainEnv() and JNFReleaseEnv(), but executes a + * block that accepts the obtained JNIEnv. + */ +typedef void (^JNIEnvBlock)(JNIEnv *); +JNF_EXPORT extern void JNFPerformEnvBlock(JNFThreadContext context, JNIEnvBlock block) API_DEPRECATED("This functionality is no longer supported and may stop working in a future version of macOS.", macos(10.10, 10.16)); + +#endif + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFThread.m b/src/libjnf/JavaNativeFoundation/JNFThread.m new file mode 100644 index 0000000000..c5feb2756c --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFThread.m @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFThread.h" + +#import +#import + +static JavaVM *GetGlobalVM() { // obtains a connection to the current VM + static JavaVM *globalVM; + + if (globalVM != NULL) { + return globalVM; + } + + void *jvmHandle = dlopen("@rpath/libjvm.dylib", RTLD_NOW); + if (!jvmHandle) { + NSLog(@"JavaNativeFoundation: %s: Failed to locate @rpath/libjvm.dylib for JNI_GetCreatedJavaVMs(). A JVM must be loaded before calling this function.", __FUNCTION__); + return NULL; + } + + jint (*_JNI_GetCreatedJavaVMs)(JavaVM **, jsize, jsize *) = dlsym(jvmHandle, "JNI_GetCreatedJavaVMs"); + if (!_JNI_GetCreatedJavaVMs) { + NSLog(@"JavaNativeFoundation: %s: Failed to locate JNI_GetCreatedJavaVMs symbol in @rpath/libjvm.dylib", __FUNCTION__); + return NULL; + } + + JavaVM *vmArray; + jsize numVMs = 0; + if (_JNI_GetCreatedJavaVMs(&vmArray, 1, &numVMs) == 0 && numVMs >= 1) { + globalVM = &vmArray[0]; + } + + if (globalVM == NULL) { + NSLog(@"JavaNativeFoundation: %s: JNI_GetCreatedJavaVMs() failed to get any VM.", __FUNCTION__); + return NULL; + } + + return globalVM; +} + +// private marker to indicate if we need to detach on release +enum { + JNFThreadWillDetachOnRelease = (1 << 12) +}; + +static void setSystemClassLoader(JNIEnv *env) { + // setup the context class loader for this new thread coming into the JVM + JNF_CLASS_CACHE(jc_Thread, "java/lang/Thread"); + JNF_STATIC_MEMBER_CACHE(jm_currentThread, jc_Thread, "currentThread", "()Ljava/lang/Thread;"); + jobject currentThread = JNFCallStaticObjectMethod(env, jm_currentThread); + + JNF_CLASS_CACHE(jc_ClassLoader, "java/lang/ClassLoader"); + JNF_STATIC_MEMBER_CACHE(jm_getSystemClassLoader, jc_ClassLoader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); + jobject systemClassLoader = JNFCallStaticObjectMethod(env, jm_getSystemClassLoader); + + JNF_MEMBER_CACHE(jm_setContextClassLoader, jc_Thread, "setContextClassLoader", "(Ljava/lang/ClassLoader;)V"); + JNFCallVoidMethod(env, currentThread, jm_setContextClassLoader, systemClassLoader); +} + +static JNFThreadContext GetEnvUsingJVM(JavaVM *jvm, void **envPtr, BOOL shouldDetachOnRelease, BOOL setClassLoader, BOOL attachAsDaemon) { + jint status = (*jvm)->GetEnv(jvm, envPtr, JNI_VERSION_1_4); + if (status == JNI_OK) { + // common path + return 0; + } + + if (status != JNI_EDETACHED) { + // can't use JNF_ASSERT macros, since we don't really know if we have an env :( + NSLog(@"JavaNativeFoundation: JNFObtainEnv unable to obtain JNIEnv (%d)", (int)status); + return 0; + } + + // we need to attach + if (attachAsDaemon) { + status = (*jvm)->AttachCurrentThreadAsDaemon(jvm, envPtr, NULL); + } else { + status = (*jvm)->AttachCurrentThread(jvm, envPtr, NULL); + } + + if (status != JNI_OK) { + // failed - need to clear our mark to detach, if present + return 0; + } + + if (setClassLoader) { + setSystemClassLoader((JNIEnv *)(*envPtr)); + } + + // by default, we detach at pthread death, but if requested, we will detach on env-release + if (shouldDetachOnRelease) { + return JNFThreadWillDetachOnRelease; + } + + // we don't do anything in this case, because HotSpot on Mac OS X will detach for us. + // Can we install a pthread_atexit handler to detach if we haven't already? + return 0; +} + +// public call to obtain an env, and attach the current thread to the VM in needed +JNIEnv *JNFObtainEnv(JNFThreadContext *context) { + JavaVM *jvm = GetGlobalVM(); + if (!jvm) { + *context = 0; + return NULL; + } + + JNFThreadContext ctx = *context; + BOOL shouldDetachOnRelease = (0 != (ctx & JNFThreadDetachImmediately)); + BOOL setClassLoader = (0 != (ctx & JNFThreadSetSystemClassLoaderOnAttach)); + BOOL attachAsDaemon = (0 != (ctx & JNFThreadAttachAsDaemon)); + + void *env = NULL; + *context = GetEnvUsingJVM(jvm, &env, shouldDetachOnRelease, setClassLoader, attachAsDaemon); + return (JNIEnv *)env; +} + +void JNFReleaseEnv(__unused JNIEnv *env, JNFThreadContext *context) { + if ((*context & JNFThreadWillDetachOnRelease) == 0) { + return; + } + + JavaVM *jvm = GetGlobalVM(); + if (!jvm) return; + + jint status = (*jvm)->DetachCurrentThread(jvm); + if (status != JNI_OK) { + // can't use JNF_ASSERT macros, since we don't really know if we have an env :( + NSLog(@"JavaNativeFoundation: %s: unable to release JNIEnv (%d)", __FUNCTION__, (int)status); + } +} + + +#if __BLOCKS__ + +JNF_EXPORT extern void JNFPerformEnvBlock(JNFThreadContext context, JNIEnvBlock block) { + JNIEnv *env = JNFObtainEnv(&context); + if (env == NULL) [NSException raise:@"Unable to obtain JNIEnv" format:@"Unable to obtain JNIEnv for context: %p", (void *)context]; + + @try { + block(env); + } @finally { + JNFReleaseEnv(env, &context); + } +} + +#endif diff --git a/src/libjnf/JavaNativeFoundation/JNFTypeCoercion.h b/src/libjnf/JavaNativeFoundation/JNFTypeCoercion.h new file mode 100644 index 0000000000..4dbaa99caa --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFTypeCoercion.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Type Coercion system that translates between Java VM objects and Objective-C Foundation objects. + * + * JNFTypeCoercions are registered into JNFTypeCoercers, which can be chained to other + * JNFTypeCoercers using -deriveCoercer or -initWithParent. If the set of Coercions + * in a Coercer aren't capable of converting an object, the Coercer will delegate up to + * it's parent. + * + * Coercions are registered by Objective-C class and Java class name. If an object is an + * instance of the registered class name, the coercion will be invoked. Default + * implementations for several basic types are provided by JNFDefaultCoercions, and can + * be installed in any order. More specific coercions should be placed farther down + * a coercer chain, and more generic coercions should be placed higher. A Coercer can be + * initialized with a basic Coercion that may want to handle "all cases", like calling + * Object.toString() and -describe on all objects passed to it. + * + * Coercions are passed the Coercion-object that was originally invoked on the + * target object. This permits the lowest level Coercion to be used for subsequent + * object translations for composite objects. The provided List, Map, and Set Coercions + * only handle object hierarchies, and will infinitely recurse if confronted with a + * cycle in the object graph. + * + * Null and nil are both perfectly valid return types for Coercions, and do not indicate + * a failure to coerce an object. Coercers are not thread safe. + */ + +#import +#import + +__BEGIN_DECLS + +@class JNFTypeCoercion; + +JNF_EXPORT +@protocol JNFTypeCoercion + +- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer; +- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer; + +@end + + +JNF_EXPORT +@interface JNFTypeCoercer : NSObject + +- (id) init; +- (id) initWithParent:(NSObject *)parentIn; +- (JNFTypeCoercer *) deriveCoercer; +- (void) addCoercion:(NSObject *)coercion forNSClass:(Class)nsClass javaClass:(NSString *)javaClassName; + +- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env; +- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env; + +@end + + +JNF_EXPORT +@interface JNFDefaultCoercions : NSObject { } + ++ (void) addStringCoercionTo:(JNFTypeCoercer *)coercer; ++ (void) addNumberCoercionTo:(JNFTypeCoercer *)coercer; ++ (void) addDateCoercionTo:(JNFTypeCoercer *)coercer; ++ (void) addListCoercionTo:(JNFTypeCoercer *)coercer; ++ (void) addMapCoercionTo:(JNFTypeCoercer *)coercer; ++ (void) addSetCoercionTo:(JNFTypeCoercer *)coercer; + ++ (JNFTypeCoercer *) defaultCoercer; // returns autoreleased copy, not shared, not thread safe + +@end + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/JNFTypeCoercion.m b/src/libjnf/JavaNativeFoundation/JNFTypeCoercion.m new file mode 100644 index 0000000000..8eae113aca --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JNFTypeCoercion.m @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "JNFTypeCoercion.h" + +#import "JNFJNI.h" +#import "JNFObject.h" +#import "JNFString.h" +#import "JNFNumber.h" +#import "JNFDate.h" +#import "JNFJObjectWrapper.h" + +// #define DEBUG 1 + +@interface JNFInternalJavaClassToCoersionHolder : JNFJObjectWrapper + +- (id) initWithCoercion:(NSObject *)coercionIn className:(NSString *)className withEnv:(JNIEnv *)env; +- (BOOL) isClassFor:(jobject)obj withEnv:(JNIEnv *)env; +- (NSObject *)coercion; + +@property (nonatomic, readwrite, strong) NSObject *coercion; + +@end + +@interface JNFTypeCoercer () + +@property (nonatomic, readwrite, strong) NSObject *parent; +@property (nonatomic, readwrite, strong) NSMutableDictionary *nsClassToCoercion; +@property (nonatomic, readwrite, strong) NSMutableDictionary *javaClassNameToCoercion; +@property (nonatomic, readwrite, strong) NSArray *javaClassToCoercion; + +@end + +@implementation JNFTypeCoercer + +- (id) init { + return [self initWithParent:nil]; +} + +- (id) initWithParent:(NSObject *)parentIn { + self = [super init]; + if (!self) return self; + + self.parent = parentIn; + self.nsClassToCoercion = [NSMutableDictionary dictionary]; + self.javaClassNameToCoercion = [NSMutableDictionary dictionary]; + self.javaClassToCoercion = nil; + + return self; +} + +- (void) dealloc { + self.parent = nil; + self.nsClassToCoercion = nil; + self.javaClassNameToCoercion = nil; + self.javaClassToCoercion = nil; + + [super dealloc]; +} + +- (JNFTypeCoercer *) deriveCoercer { + return [[[JNFTypeCoercer alloc] initWithParent:self] autorelease]; +} + +- (void) addCoercion:(NSObject *)coercion forNSClass:(Class)nsClass javaClass:(NSString *)javaClassName { + if (nsClass) [self.nsClassToCoercion setObject:coercion forKey:(id)nsClass]; + if (javaClassName) [self.javaClassNameToCoercion setObject:coercion forKey:javaClassName]; + self.javaClassToCoercion = nil; // invalidate Java Class cache +} + +- (NSObject *) findCoercerForNSObject:(id)obj { + NSMutableDictionary * const nsClassToCoercion = self.nsClassToCoercion; + NSObject *coercer = [nsClassToCoercion objectForKey:[obj class]]; + if (coercer) return coercer; + + NSEnumerator *classes = [nsClassToCoercion keyEnumerator]; + Class clazzIter; + while ((clazzIter = [classes nextObject]) != nil) { + if ([obj isKindOfClass:clazzIter]) { + return [nsClassToCoercion objectForKey:clazzIter]; + } + } + + return self.parent; +} + +- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer { + return [[self findCoercerForNSObject:obj] coerceNSObject:obj withEnv:env usingCoercer:coercer]; +} + +- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env { + return [self coerceNSObject:obj withEnv:env usingCoercer:(JNFTypeCoercion *)self]; +} + + +- (NSArray *) javaClassCacheUsingEnv:(JNIEnv *)env { + NSArray * const javaClassToCoercion = self.javaClassToCoercion; + if (javaClassToCoercion) return javaClassToCoercion; + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + NSMutableDictionary * const javaClassNameToCoercion = self.javaClassNameToCoercion; + NSEnumerator *classNames = [javaClassNameToCoercion keyEnumerator]; + NSString *className; + while ((className = [classNames nextObject]) != nil) { + NSObject *coercion = [javaClassNameToCoercion objectForKey:className]; + JNFInternalJavaClassToCoersionHolder *holder = [[JNFInternalJavaClassToCoersionHolder alloc] initWithCoercion:coercion className:className withEnv:env]; + [array addObject:holder]; + [holder release]; + } + + self.javaClassToCoercion = array; + return [array autorelease]; +} + +- (NSObject *) findCoercerForJavaObject:(jobject)obj withEnv:(JNIEnv *)env { + if (obj == NULL) return nil; + + NSMutableDictionary * const javaClassNameToCoercion = self.javaClassNameToCoercion; + NSString *javaClazzName = JNFObjectClassName(env, obj); + NSObject *coercer = [javaClassNameToCoercion objectForKey:javaClazzName]; + if (coercer) return coercer; + +#ifdef DEBUG + NSLog(@"attempting to find coercer for: %@", javaClazzName); +#endif + + NSArray *javaClassCache = [self javaClassCacheUsingEnv:env]; + NSEnumerator *holderIter = [javaClassCache objectEnumerator]; + JNFInternalJavaClassToCoersionHolder *holder; + while ((holder = [holderIter nextObject]) != nil) { + if ([holder isClassFor:obj withEnv:env]) { + NSObject *coercion = [holder coercion]; + [javaClassNameToCoercion setObject:coercion forKey:javaClazzName]; + return coercion; + } + } + + return self.parent; +} + +- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer { + NSObject *coercion = [self findCoercerForJavaObject:obj withEnv:env]; + id nsObj = [coercion coerceJavaObject:obj withEnv:env usingCoercer:coercer]; + if (nsObj == nil) return [NSNull null]; + return nsObj; +} + +- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env { + return [self coerceJavaObject:obj withEnv:env usingCoercer:(JNFTypeCoercion *)self]; +} + +@end + + +@implementation JNFInternalJavaClassToCoersionHolder + +- (id) initWithCoercion:(NSObject *)coercionIn className:(NSString *)className withEnv:(JNIEnv *)env { + const char *classNameCStr = [className cStringUsingEncoding:NSUTF8StringEncoding]; + jclass clz = (*env)->FindClass(env, classNameCStr); + if (clz == NULL) [JNFException raise:env as:kClassNotFoundException reason:"Unable to create type converter."]; + + self = [super initWithJObject:clz withEnv:env]; + if (!self) return self; + + self.coercion = coercionIn; + return self; +} + +- (BOOL)isEqual:(id)object { + jclass javaClazz = [self jObject]; + + if ([object isKindOfClass:[self class]]) { + return [((JNFInternalJavaClassToCoersionHolder *)object) jObject] == javaClazz; + } + + return NO; +} + +- (void) dealloc { + self.coercion = nil; + [super dealloc]; +} + +- (NSUInteger)hash { + jclass javaClazz = [self jObject]; + return (NSUInteger)ptr_to_jlong(javaClazz); +} + +- (BOOL) isClassFor:(jobject)obj withEnv:(JNIEnv *)env { + if (obj == NULL) return JNI_FALSE; +#ifdef DEBUG + NSLog(@"is (%@(%@)) a kind of (%@)?", JNFToString(env, obj), JNFClassName(env, obj), JNFToString(env, javaClazz)); +#endif + + jclass javaClazz = [self jObject]; + return (BOOL)(*env)->IsInstanceOf(env, obj, javaClazz); +} + +@end + + +@interface JNFStringCoercion : NSObject { } +@end + +@implementation JNFStringCoercion + +- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer { + return JNFNSToJavaString(env, (NSString *)obj); +} + +- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer { + return JNFJavaToNSString(env, (jstring)obj); +} + +@end + + +@interface JNFNumberCoercion : NSObject { } +@end + +@implementation JNFNumberCoercion + +- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer { + return JNFNSToJavaNumber(env, (NSNumber *)obj); +} + +- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer { + return JNFJavaToNSNumber(env, obj); +} + +@end + + +@interface JNFDateCoercion : NSObject { } +@end + +@implementation JNFDateCoercion + +- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer { + return JNFNSToJavaCalendar(env, (NSDate *)obj); +} + +- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer { + return JNFJavaToNSDate(env, obj); +} + +@end + + +static JNF_CLASS_CACHE(jc_Iterator, "java/util/Iterator"); +static JNF_MEMBER_CACHE(jm_Iterator_hasNext, jc_Iterator, "hasNext", "()Z"); +static JNF_MEMBER_CACHE(jm_Iterator_next, jc_Iterator, "next", "()Ljava/lang/Object;"); + +@interface JNFMapCoercion : NSObject { } +@end + +@implementation JNFMapCoercion + +- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer { + static JNF_CLASS_CACHE(jc_HashMap, "java/util/HashMap"); + static JNF_CTOR_CACHE(jm_HashMap_ctor, jc_HashMap, "()V"); + static JNF_MEMBER_CACHE(jm_HashMap_put, jc_HashMap, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + NSDictionary *nsDict = (NSDictionary *)obj; + NSEnumerator *keyEnum = [nsDict keyEnumerator]; + + jobject jHashMap = JNFNewObject(env, jm_HashMap_ctor); + + id key; + while ((key = [keyEnum nextObject]) != nil) { + jobject jkey = [coercer coerceNSObject:key withEnv:env usingCoercer:coercer]; + + id value = [nsDict objectForKey:key]; + jobject java_value = [coercer coerceNSObject:value withEnv:env usingCoercer:coercer]; + + JNFCallObjectMethod(env, jHashMap, jm_HashMap_put, jkey, java_value); + + if (jkey != NULL) (*env)->DeleteLocalRef(env, jkey); + if (java_value != NULL) (*env)->DeleteLocalRef(env, java_value); + } + + return jHashMap; +} + +- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer { + static JNF_CLASS_CACHE(jc_Map, "java/util/Map"); + static JNF_MEMBER_CACHE(jm_Map_keySet, jc_Map, "keySet", "()Ljava/util/Set;"); + static JNF_MEMBER_CACHE(jm_Map_get, jc_Map, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); + + static JNF_CLASS_CACHE(jc_Set, "java/util/Set"); + static JNF_MEMBER_CACHE(jm_Set_iterator, jc_Set, "iterator", "()Ljava/util/Iterator;"); + + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + jobject jKeySet = JNFCallObjectMethod(env, obj, jm_Map_keySet); + jobject jKeyIter = JNFCallObjectMethod(env, jKeySet, jm_Set_iterator); + if (jKeySet != NULL) (*env)->DeleteLocalRef(env, jKeySet); + + while (JNFCallBooleanMethod(env, jKeyIter, jm_Iterator_hasNext)) { + jobject jkey = JNFCallObjectMethod(env, jKeyIter, jm_Iterator_next); + id nsKey = [coercer coerceJavaObject:jkey withEnv:env usingCoercer:coercer]; + + jobject java_value = JNFCallObjectMethod(env, obj, jm_Map_get, jkey); + if (jkey != NULL) (*env)->DeleteLocalRef(env, jkey); + + id nsValue = [coercer coerceJavaObject:java_value withEnv:env usingCoercer:coercer]; + if (java_value != NULL) (*env)->DeleteLocalRef(env, java_value); + + [dict setObject:nsValue forKey:nsKey]; + } + + return [dict autorelease]; +} + +@end + + +@interface JNFListCoercion : NSObject { } +@end + +@implementation JNFListCoercion + +- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer { + static JNF_CLASS_CACHE(jc_List, "java/util/ArrayList"); + static JNF_CTOR_CACHE(jm_List_ctor, jc_List, "(I)V"); + static JNF_MEMBER_CACHE(jm_List_add, jc_List, "add", "(Ljava/lang/Object;)Z"); + + NSArray *nsArray = (NSArray *)obj; + unsigned long count = [nsArray count]; + + jobject javaArray = JNFNewObject(env, jm_List_ctor, (jint)count); + + unsigned long i; + for (i = 0; i < count; i++) { + id iThObj = [nsArray objectAtIndex:i]; + jobject iThJObj = [coercer coerceNSObject:iThObj withEnv:env usingCoercer:coercer]; + JNFCallBooleanMethod(env, javaArray, jm_List_add, iThJObj); + if (iThJObj != NULL) (*env)->DeleteLocalRef(env, iThJObj); + } + + return javaArray; +} + +- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer { + static JNF_CLASS_CACHE(jc_List, "java/util/List"); + static JNF_MEMBER_CACHE(jm_List_iterator, jc_List, "iterator", "()Ljava/util/Iterator;"); + + jobject jIterator = JNFCallObjectMethod(env, obj, jm_List_iterator); + + NSMutableArray *nsArray = [[NSMutableArray alloc] init]; + while (JNFCallBooleanMethod(env, jIterator, jm_Iterator_hasNext)) { + jobject jobj = JNFCallObjectMethod(env, jIterator, jm_Iterator_next); + id nsObj = [coercer coerceJavaObject:jobj withEnv:env usingCoercer:coercer]; + if (jobj != NULL) (*env)->DeleteLocalRef(env, jobj); + [nsArray addObject:nsObj]; + } + + return [nsArray autorelease]; +} + +@end + + +@interface JNFSetCoercion : NSObject { } +@end + +@implementation JNFSetCoercion + +- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer { + static JNF_CLASS_CACHE(jc_Set, "java/util/HashSet"); + static JNF_CTOR_CACHE(jm_Set_ctor, jc_Set, "()V"); + static JNF_MEMBER_CACHE(jm_Set_add, jc_Set, "add", "(Ljava/lang/Object;)Z"); + + NSSet *nsSet = (NSSet *)obj; + NSEnumerator *enumerator = [nsSet objectEnumerator]; + + jobject javaSet = JNFNewObject(env, jm_Set_ctor); + id next; + while ((next = [enumerator nextObject]) != nil) { + jobject jnext = [coercer coerceNSObject:next withEnv:env usingCoercer:coercer]; + if (jnext != NULL) { + JNFCallBooleanMethod(env, javaSet, jm_Set_add, jnext); + (*env)->DeleteLocalRef(env, jnext); + } + } + + return javaSet; +} + +- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer { + static JNF_CLASS_CACHE(jc_Set, "java/util/Set"); + static JNF_MEMBER_CACHE(jm_Set_iterator, jc_Set, "iterator", "()Ljava/util/Iterator;"); + + jobject jIterator = JNFCallObjectMethod(env, obj, jm_Set_iterator); + + NSMutableSet *nsSet = [[NSMutableSet alloc] init]; + while (JNFCallBooleanMethod(env, jIterator, jm_Iterator_hasNext)) { + jobject jobj = JNFCallObjectMethod(env, jIterator, jm_Iterator_next); + if (jobj != NULL) { + id nsObj = [coercer coerceJavaObject:jobj withEnv:env usingCoercer:coercer]; + (*env)->DeleteLocalRef(env, jobj); + [nsSet addObject:nsObj]; + } + } + + return [nsSet autorelease]; +} + +@end + + +@implementation JNFDefaultCoercions + ++ (void) addStringCoercionTo:(JNFTypeCoercer *)coercer { + [coercer addCoercion:[[[JNFStringCoercion alloc] init] autorelease] forNSClass:[NSString class] javaClass:@"java/lang/String"]; +} + ++ (void) addNumberCoercionTo:(JNFTypeCoercer *)coercer { + [coercer addCoercion:[[[JNFNumberCoercion alloc] init] autorelease] forNSClass:[NSNumber class] javaClass:@"java/lang/Number"]; +} + ++ (void) addDateCoercionTo:(JNFTypeCoercer *)coercer { + id dateCoercion = [[[JNFDateCoercion alloc] init] autorelease]; + [coercer addCoercion:dateCoercion forNSClass:[NSDate class] javaClass:@"java/util/Calendar"]; + [coercer addCoercion:dateCoercion forNSClass:[NSDate class] javaClass:@"java/util/Date"]; +} + ++ (void) addListCoercionTo:(JNFTypeCoercer *)coercer { + [coercer addCoercion:[[[JNFListCoercion alloc] init] autorelease] forNSClass:[NSArray class] javaClass:@"java/util/List"]; +} + ++ (void) addMapCoercionTo:(JNFTypeCoercer *)coercer { + [coercer addCoercion:[[[JNFMapCoercion alloc] init] autorelease] forNSClass:[NSDictionary class] javaClass:@"java/util/Map"]; +} + ++ (void) addSetCoercionTo:(JNFTypeCoercer *)coercer { + [coercer addCoercion:[[[JNFSetCoercion alloc] init] autorelease] forNSClass:[NSSet class] javaClass:@"java/util/Set"]; +} + ++ (JNFTypeCoercer *) defaultCoercer { + JNFTypeCoercer *coercer = [[[JNFTypeCoercer alloc] initWithParent:nil] autorelease]; + + [JNFDefaultCoercions addStringCoercionTo:coercer]; + [JNFDefaultCoercions addNumberCoercionTo:coercer]; + [JNFDefaultCoercions addDateCoercionTo:coercer]; + [JNFDefaultCoercions addListCoercionTo:coercer]; + [JNFDefaultCoercions addMapCoercionTo:coercer]; + [JNFDefaultCoercions addSetCoercionTo:coercer]; + + return coercer; +} + +@end diff --git a/src/libjnf/JavaNativeFoundation/JavaNativeFoundation-Info.plist b/src/libjnf/JavaNativeFoundation/JavaNativeFoundation-Info.plist new file mode 100644 index 0000000000..3d5722632f --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JavaNativeFoundation-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(CURRENT_PROJECT_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright © 2008-2020 Apple Inc.\nAll Rights Reserved. + + diff --git a/src/libjnf/JavaNativeFoundation/JavaNativeFoundation.h b/src/libjnf/JavaNativeFoundation/JavaNativeFoundation.h new file mode 100644 index 0000000000..e7e66d4109 --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/JavaNativeFoundation.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * This umbrella header should be included by all JNI/Cocoa source files + * for easy building. Use this file instead of importing individual JNF + * headers. + */ + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/src/libjnf/JavaNativeFoundation/Modules/module.modulemap b/src/libjnf/JavaNativeFoundation/Modules/module.modulemap new file mode 100644 index 0000000000..bde3b3182c --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module JavaNativeFoundation [extern_c] { + umbrella header "JavaNativeFoundation.h" + export * + module * { export * } +} diff --git a/src/libjnf/JavaNativeFoundation/debug.h b/src/libjnf/JavaNativeFoundation/debug.h new file mode 100644 index 0000000000..d967795fef --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/debug.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * -- + * + * Internal functions to Java Native Foundation. + */ + +#import +#import + +__BEGIN_DECLS + +// +// Debugging support +// + +// prints a stack trace from the Java VM (can be called from gdb) +void JNFJavaStackTrace(JNIEnv *env); + +// dump some info about a generic Java object. +void JNFDumpJavaObject(JNIEnv *env, jobject obj); + +// prints a Java stack trace into a string +NSString *JNFGetStackTraceAsNSString(JNIEnv *env, jthrowable throwable); + +__END_DECLS diff --git a/src/libjnf/JavaNativeFoundation/debug.m b/src/libjnf/JavaNativeFoundation/debug.m new file mode 100644 index 0000000000..ab359fd7aa --- /dev/null +++ b/src/libjnf/JavaNativeFoundation/debug.m @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "debug.h" + +#import "JNFAssert.h" +#import "JNFObject.h" + +/* + * Utility function to print the Java stack backtrace. + * In gdb, if you have a value for the JNIEnv on the thread + * you want to trace, you can do a gdb "print" of this function + * to get the stack trace for the thread. + */ +void JNFJavaStackTrace(JNIEnv *env) { + jthrowable obj_javaException; + if ((obj_javaException = (*env)->ExceptionOccurred(env)) != NULL) (*env)->ExceptionClear(env); + + jclass cls_Thread = (*env)->FindClass(env, "java/lang/Thread"); + jmethodID mid_currentThread = (*env)->GetStaticMethodID(env, cls_Thread, "currentThread", "()Ljava/lang/Thread;"); + jobject obj_currentThread = (*env)->CallStaticObjectMethod(env, cls_Thread, mid_currentThread); + jclass cls_currentThread = (*env)->GetObjectClass(env, obj_currentThread); + jmethodID mid_getName = (*env)->GetMethodID(env, cls_currentThread, "getName", "()Ljava/lang/String;"); + jobject obj_threadName = (*env)->CallObjectMethod(env, obj_currentThread, mid_getName); + (*env)->DeleteLocalRef(env, obj_currentThread); + + const char *threadName = (*env)->GetStringUTFChars(env, obj_threadName, NULL); + JNF_WARN("Stack trace from Java thread \"%s\":", threadName); + (*env)->ReleaseStringUTFChars(env, obj_threadName, threadName); + (*env)->DeleteLocalRef(env, obj_threadName); + + jmethodID mid_dumpStack = (*env)->GetStaticMethodID(env, cls_Thread, "dumpStack", "()V"); + (*env)->CallStaticVoidMethod(env, cls_Thread, mid_dumpStack); + (*env)->DeleteLocalRef(env, cls_Thread); + + if (obj_javaException) (*env)->Throw(env, obj_javaException); +} + +/* + * Utility function to dump some info about a generic Java object. + * To be called from gdb. Like JNFJavaStackTrace, you need to have + * a valid value for the JNIEnv to call this function. + */ +void JNFDumpJavaObject(JNIEnv *env, jobject obj) { + jthrowable obj_javaException; + if ((obj_javaException = (*env)->ExceptionOccurred(env)) != NULL) (*env)->ExceptionClear(env); + + jclass cls_CToolkit = (*env)->FindClass(env, "apple/awt/CToolkit"); + jmethodID mid_dumpObject = (*env)->GetStaticMethodID(env, cls_CToolkit, "dumpObject", "(Ljava/lang/Object;)V"); + (*env)->CallStaticVoidMethod(env, cls_CToolkit, mid_dumpObject, obj); + (*env)->DeleteLocalRef(env, cls_CToolkit); + + if (obj_javaException) (*env)->Throw(env, obj_javaException); +} + +/* + * Utility function to print a Java stack trace into a string + */ +NSString *JNFGetStackTraceAsNSString(JNIEnv *env, jthrowable throwable) { + // Writer writer = new StringWriter(); + JNF_CLASS_CACHE(jc_StringWriter, "java/io/StringWriter"); + JNF_CTOR_CACHE(jct_StringWriter, jc_StringWriter, "()V"); + jobject writer = JNFNewObject(env, jct_StringWriter); + + // PrintWriter printWriter = new PrintWriter(writer); + JNF_CLASS_CACHE(jc_PrintWriter, "java/io/PrintWriter"); + JNF_CTOR_CACHE(jct_PrintWriter, jc_PrintWriter, "(Ljava/io/Writer;)V"); + jobject printWriter = JNFNewObject(env, jct_PrintWriter, writer); + + // throwable.printStackTrace(printWriter); + JNF_CLASS_CACHE(jc_Throwable, "java/lang/Throwable"); + JNF_MEMBER_CACHE(jm_printStackTrace, jc_Throwable, "printStackTrace", "(Ljava/io/PrintWriter;)V"); + JNFCallVoidMethod(env, throwable, jm_printStackTrace, printWriter); + (*env)->DeleteLocalRef(env, printWriter); + + // return writer.toString(); + NSString *stackTraceAsString = JNFObjectToString(env, writer); + (*env)->DeleteLocalRef(env, writer); + return stackTraceAsString; +} diff --git a/src/libnio/share/jni_onload.c b/src/libjnf/jni_onload.c similarity index 100% rename from src/libnio/share/jni_onload.c rename to src/libjnf/jni_onload.c diff --git a/src/libjnf/libjnf.clangproj b/src/libjnf/libjnf.clangproj new file mode 100644 index 0000000000..4196b1984d --- /dev/null +++ b/src/libjnf/libjnf.clangproj @@ -0,0 +1,25 @@ + + + + + 606e173d-798d-4463-8efd-0ad750831dd3 + + + jnf + dll + osx-arm64 + + + + + + + + + + + + + + + diff --git a/src/libjsound/libjsound.clangproj b/src/libjsound/libjsound.clangproj index 18b762589f..7b824b678e 100644 --- a/src/libjsound/libjsound.clangproj +++ b/src/libjsound/libjsound.clangproj @@ -5,8 +5,9 @@ 403E0642-B6ED-464E-8694-2E467CDA2C02 - win-x64;win-x86;win-arm64;linux-x64;linux-arm;linux-arm64;linux-musl-x64;linux-musl-arm;linux-musl-arm64 jsound + dll + win-x64;win-x86;win-arm64;linux-x64;linux-arm;linux-arm64;linux-musl-x64;linux-musl-arm;linux-musl-arm64 @@ -16,7 +17,7 @@ - + @@ -33,15 +34,15 @@ - + - - + + @@ -59,20 +60,21 @@ - + + - + - + - + @@ -98,11 +100,11 @@ - + - \ No newline at end of file + diff --git a/src/libjsoundalsa/libjsoundalsa.clangproj b/src/libjsoundalsa/libjsoundalsa.clangproj index 3d2f27b1bf..19dfe8ce64 100644 --- a/src/libjsoundalsa/libjsoundalsa.clangproj +++ b/src/libjsoundalsa/libjsoundalsa.clangproj @@ -5,8 +5,9 @@ 555CDB6E-84CE-4FE8-8945-47553C4D0A51 - linux-x64;linux-arm;linux-arm64;linux-musl-x64;linux-musl-arm;linux-musl-arm64 jsoundalsa + dll + linux-x64;linux-arm;linux-arm64;linux-musl-x64;linux-musl-arm;linux-musl-arm64 @@ -34,6 +35,7 @@ + @@ -68,4 +70,4 @@ - \ No newline at end of file + diff --git a/src/libjsoundds/libjsoundds.clangproj b/src/libjsoundds/libjsoundds.clangproj index 67aa0758a2..354f584600 100644 --- a/src/libjsoundds/libjsoundds.clangproj +++ b/src/libjsoundds/libjsoundds.clangproj @@ -5,8 +5,9 @@ 30B763A2-A59A-4CE8-B11E-DD49527480CB - win-x64;win-x86;win-arm64 jsoundds + dll + win-x64;win-x86;win-arm64 @@ -48,4 +49,4 @@ - \ No newline at end of file + diff --git a/src/libjvm/README.md b/src/libjvm/README.md index f61001d0bd..684ae947b7 100644 --- a/src/libjvm/README.md +++ b/src/libjvm/README.md @@ -4,7 +4,5 @@ There are two major uses of this library. The first is for external hosting of t The second set of functions prefixed with JVM_ are used internally by OpenJDK C code for various low level operations. To the extent possible we copy the implementations from OpenJDK. But, many of these functions need to call back into the internals of IKVM. -A few functions prefixed IKVM_ are used by our JVM_ implementation functions to provide support for things OpenJDK C code expects, such as throwing exceptions. - -We also make use of JVM_LoadLibrary and JVM_UnloadLibrary in our JNI implementation, because this is how OpenJDK does so, and for good reasons: it causes loading of JNI libraries to originate from libjvm.dylib on OSX, and thus inherit it's loader path capabilities to load other JNI libraries from arbitrary locations. +We also make use of JVM_LoadLibrary and JVM_UnloadLibrary in our JNI implementation, because this is how OpenJDK does so, and for good reasons: it causes loading of JNI libraries to originate from libjvm.dylib on OSX and thus inherit its loader path capabilities to load other JNI libraries from arbitrary locations. diff --git a/src/libjvm/ikvm.c b/src/libjvm/ikvm.c deleted file mode 100644 index 8b12af3cec..0000000000 --- a/src/libjvm/ikvm.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "ikvm.h" - -static IKVM_ThrowException_Func *IKVM_ThrowException_Ptr; - -NETEXPORT void NETCALL Set_IKVM_ThrowException(IKVM_ThrowException_Func *func) -{ - IKVM_ThrowException_Ptr = func; -} - -void IKVM_ThrowException(const char *name, const char *msg) -{ - (*IKVM_ThrowException_Ptr)(name, msg); -} diff --git a/src/libjvm/ikvm.h b/src/libjvm/ikvm.h index 8919d7b301..3930d4f18e 100644 --- a/src/libjvm/ikvm.h +++ b/src/libjvm/ikvm.h @@ -1,18 +1,23 @@ -#ifdef WIN32 -#define NETEXPORT __declspec(dllexport) -#define NETCALL __stdcall -#else -#define NETEXPORT -#define NETCALL -#endif +#include #ifdef __cplusplus extern "C" { #endif -typedef void IKVM_ThrowException_Func(const char *name, const char *msg); +typedef struct JVMInvokeInterface { + jint (*JNI_GetDefaultJavaVMInitArgs)(void *); + jint (*JNI_GetCreatedJavaVMs)(JavaVM **vmBuf, jsize bufLen, jsize *nVMs); + jint (*JNI_CreateJavaVM)(JavaVM **p_vm, void **p_env, void *vm_args); + void (*JVM_ThrowException)(const char*, const char*); + void* (*JVM_GetThreadInterruptEvent)(); + jint (*JVM_ActiveProcessorCount)(); +} JVMInvokeInterface; + +extern JVMInvokeInterface *jvmii; + +JNIEXPORT void JNICALL JVM_Init(JVMInvokeInterface *p_jvmii); -void IKVM_ThrowException(const char *name, const char *msg); +void JNICALL JVM_ThrowException(const char *name, const char *msg); #ifdef __cplusplus } diff --git a/src/libjvm/jni.c b/src/libjvm/jni.c index 50f0bf1ce5..22df251776 100644 --- a/src/libjvm/jni.c +++ b/src/libjvm/jni.c @@ -1,56 +1,18 @@ #include -#ifdef WIN32 -#define NETEXPORT __declspec(dllexport) -#define NETCALL __stdcall -#else -#define NETEXPORT -#define NETCALL -#endif - -typedef jint JNI_GetDefaultJavaVMInitArgs_Func(void* vm_args); -typedef jint JNI_GetCreatedJavaVMs_Func(JavaVM** vmBuf, jsize bufLen, jsize* nVMs); -typedef jint JNI_CreateJavaVM_Func(JavaVM** p_vm, void** p_env, void* vm_args); - -static JNI_GetDefaultJavaVMInitArgs_Func *JNI_GetDefaultJavaVMInitArgs_Ptr; -static JNI_GetCreatedJavaVMs_Func *JNI_GetCreatedJavaVMs_Ptr; -static JNI_CreateJavaVM_Func *JNI_CreateJavaVM_Ptr; - -/** - * Sets the JNI_GetDefaultJavaVMInitArgs_Ptr value to a delegate. - */ -NETEXPORT void NETCALL Set_JNI_GetDefaultJavaVMInitArgs(JNI_GetDefaultJavaVMInitArgs_Func *func) -{ - JNI_GetDefaultJavaVMInitArgs_Ptr = func; -} - -/** - * Sets the JNI_GetCreatedJavaVMs_Ptr value to a delegate. - */ -NETEXPORT void NETCALL Set_JNI_GetCreatedJavaVMs(JNI_GetCreatedJavaVMs_Func *func) -{ - JNI_GetCreatedJavaVMs_Ptr = func; -} - -/** - * Sets the JNI_CreateJavaVM_Ptr value to a delegate. - */ -NETEXPORT void NETCALL Set_JNI_CreateJavaVM(JNI_CreateJavaVM_Func *func) -{ - JNI_CreateJavaVM_Ptr = func; -} +#include "ikvm.h" JNIEXPORT jint JNICALL JNI_GetDefaultJavaVMInitArgs(void* vm_args) { - return (*JNI_GetDefaultJavaVMInitArgs_Ptr)(vm_args); + return jvmii->JNI_GetDefaultJavaVMInitArgs(vm_args); } JNIEXPORT jint JNICALL JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) { - return (*JNI_GetCreatedJavaVMs_Ptr)(vmBuf, bufLen, nVMs); + return jvmii->JNI_GetCreatedJavaVMs(vmBuf, bufLen, nVMs); } JNIEXPORT jint JNICALL JNI_CreateJavaVM(JavaVM** p_vm, void** p_env, void* vm_args) { - return (*JNI_CreateJavaVM_Ptr)(p_vm, p_env, vm_args); + return jvmii->JNI_CreateJavaVM(p_vm, p_env, vm_args); } diff --git a/src/libjvm/jvm.cpp b/src/libjvm/jvm.cpp index 080be46810..19eeb16314 100644 --- a/src/libjvm/jvm.cpp +++ b/src/libjvm/jvm.cpp @@ -2,6 +2,7 @@ #include #include #include + #include "ikvm.h" #if defined WIN32 @@ -28,6 +29,18 @@ extern "C" { #endif +JVMInvokeInterface *jvmii; + +void JNICALL JVM_Init(JVMInvokeInterface *p_jvmii) +{ + jvmii = p_jvmii; +} + +void JNICALL JVM_ThrowException(const char *name, const char *msg) +{ + jvmii->JVM_ThrowException(name, msg); +} + #define assert(condition, fmt, ...); typedef uint32_t uint; @@ -102,9 +115,9 @@ jint JNICALL JVM_GetInterfaceVersion() // Java standards require the number of milliseconds since 1/1/1970 // Constant offset - calculated using offset() -static jlong _offset = 116444736000000000; +static jlong _offset = 116444736000000000; // Fake time counter for reproducible results when debugging -static jlong fake_time = 0; +static jlong fake_time = 0; inline jlong windows_to_java_time(FILETIME wt) { jlong a = jlong_from(wt.dwHighDateTime, wt.dwLowDateTime); @@ -188,22 +201,23 @@ size_t os_lasterror(char* buf, size_t len) { DWORD errval; if ((errval = GetLastError()) != 0) { - // DOS error - size_t n = (size_t)FormatMessage( + LPWSTR w = new wchar_t[len]; + size_t n = (size_t)::FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errval, 0, - buf, + w, (DWORD)len, NULL); - if (n > 3) { - // Drop final '.', CR, LF - if (buf[n - 1] == '\n') n--; - if (buf[n - 1] == '\r') n--; - if (buf[n - 1] == '.') n--; - buf[n] = '\0'; - } + w[n] = '\0'; + + n = ::WideCharToMultiByte(CP_UTF8, 0, w, -1, buf, 0, NULL, NULL); + if (n >= len) n = len - 1; + ::WideCharToMultiByte(CP_UTF8, 0, w, -1, buf, n, NULL, NULL); + buf[n] = '\0'; + + delete[] w; return n; } @@ -211,9 +225,11 @@ size_t os_lasterror(char* buf, size_t len) { // C runtime error that has no corresponding DOS error code const char* s = strerror(errno); size_t n = strlen(s); + if (n >= len) n = len - 1; strncpy(buf, s, n); buf[n] = '\0'; + return n; } @@ -256,6 +272,10 @@ jint JNICALL JVM_GetLastErrorString(char* buf, int len) return (jint)os_lasterror(buf, len); } +jint JNICALL JVM_ActiveProcessorCount() { + return jvmii->JVM_ActiveProcessorCount(); +} + jclass JNICALL JVM_FindClassFromClass(JNIEnv* env, const char* name, jboolean init, jclass from) { return 0; @@ -871,7 +891,12 @@ int JNICALL JVM_GetHostName(char* name, int namelen) #ifdef WIN32 void* os_dll_load(const char* filename, char* ebuf, int ebuflen) { - void* result = ::LoadLibraryEx(filename, 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); + size_t sfilename = (size_t)::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); + LPWSTR wfilename = new WCHAR[sfilename]; + ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, wfilename, sfilename); + + void* result = ::LoadLibraryExW(wfilename, 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); + delete[] wfilename; if (result != NULL) { return result; } @@ -923,7 +948,7 @@ void* JNICALL JVM_LoadLibrary(const char* name) if (load_result == NULL) { char msg[1024]; jio_snprintf(msg, sizeof msg, "%s: %s", name, ebuf); - IKVM_ThrowException("java/lang/UnsatisfiedLinkError", (const char*)msg); + JVM_ThrowException("java/lang/UnsatisfiedLinkError", (const char*)msg); return NULL; } @@ -985,10 +1010,20 @@ void* JNICALL JVM_FindLibraryEntry(void* handle, const char* name) #ifdef WIN32 void* JNICALL JVM_GetThreadInterruptEvent() { - return 0; + return jvmii->JVM_GetThreadInterruptEvent(); } #endif +void* JNICALL JVM_RegisterSignal(jint sig, void* handler) +{ + return 0; +} + +jboolean JNICALL JVM_RaiseSignal(jint sig) +{ + return JNI_FALSE; +} + int jio_vsnprintf(char* str, size_t count, const char* fmt, va_list args) { // Reject count values that are negative signed values converted to @@ -1037,4 +1072,4 @@ int jio_printf(const char* fmt, ...) { #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/src/libjvm/libjvm.clangproj b/src/libjvm/libjvm.clangproj index 8f0d42d322..3b9ab88200 100644 --- a/src/libjvm/libjvm.clangproj +++ b/src/libjvm/libjvm.clangproj @@ -1,66 +1,74 @@  - - - - fe90ddcb-06f3-4470-a9a7-7640b04ea9e4 - - - jvm - $(AdditionalCompileOptions);-Wno-dll-attribute-on-redeclaration - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- %(RecursiveDir)%(Filename)%(Extension) -
-
- %(RecursiveDir)%(Filename)%(Extension) -
-
- %(RecursiveDir)%(Filename)%(Extension) -
-
- - + + + + fe90ddcb-06f3-4470-a9a7-7640b04ea9e4 + + + jvm + dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ %(RecursiveDir)%(Filename)%(Extension) +
+
+ %(RecursiveDir)%(Filename)%(Extension) +
+
+ %(RecursiveDir)%(Filename)%(Extension) +
+
+ ikvm.h +
+
+ + + + +
\ No newline at end of file diff --git a/src/libjvm/mapfile-vers b/src/libjvm/mapfile-vers new file mode 100644 index 0000000000..c55de7a6c3 --- /dev/null +++ b/src/libjvm/mapfile-vers @@ -0,0 +1,338 @@ +# +# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# + +# Define public interface. + +SUNWprivate_1.1 { + global: + # JNI + JNI_CreateJavaVM; + JNI_GetCreatedJavaVMs; + JNI_GetDefaultJavaVMInitArgs; + + # JVM + JVM_Init; + JVM_Accept; + JVM_ActiveProcessorCount; + JVM_AllocateNewArray; + JVM_AllocateNewObject; + JVM_ArrayCopy; + JVM_AssertionStatusDirectives; + JVM_Available; + JVM_Bind; + JVM_ClassDepth; + JVM_ClassLoaderDepth; + JVM_Clone; + JVM_Close; + JVM_CX8Field; + JVM_CompileClass; + JVM_CompileClasses; + JVM_CompilerCommand; + JVM_Connect; + JVM_ConstantPoolGetClassAt; + JVM_ConstantPoolGetClassAtIfLoaded; + JVM_ConstantPoolGetDoubleAt; + JVM_ConstantPoolGetFieldAt; + JVM_ConstantPoolGetFieldAtIfLoaded; + JVM_ConstantPoolGetFloatAt; + JVM_ConstantPoolGetIntAt; + JVM_ConstantPoolGetLongAt; + JVM_ConstantPoolGetMethodAt; + JVM_ConstantPoolGetMethodAtIfLoaded; + JVM_ConstantPoolGetMemberRefInfoAt; + JVM_ConstantPoolGetSize; + JVM_ConstantPoolGetStringAt; + JVM_ConstantPoolGetUTF8At; + JVM_CountStackFrames; + JVM_CurrentClassLoader; + JVM_CurrentLoadedClass; + JVM_CurrentThread; + JVM_CurrentTimeMillis; + JVM_DefineClass; + JVM_DefineClassWithSource; + JVM_DefineClassWithSourceCond; + JVM_DesiredAssertionStatus; + JVM_DisableCompiler; + JVM_DoPrivileged; + JVM_DTraceGetVersion; + JVM_DTraceActivate; + JVM_DTraceIsProbeEnabled; + JVM_DTraceIsSupported; + JVM_DTraceDispose; + JVM_DumpAllStacks; + JVM_DumpThreads; + JVM_EnableCompiler; + JVM_Exit; + JVM_FillInStackTrace; + JVM_FindClassFromCaller; + JVM_FindClassFromClass; + JVM_FindClassFromClassLoader; + JVM_FindClassFromBootLoader; + JVM_FindLibraryEntry; + JVM_FindLoadedClass; + JVM_FindPrimitiveClass; + JVM_FindSignal; + JVM_FreeMemory; + JVM_GC; + JVM_GetAllThreads; + JVM_GetArrayElement; + JVM_GetArrayLength; + JVM_GetCPClassNameUTF; + JVM_GetCPFieldClassNameUTF; + JVM_GetCPFieldModifiers; + JVM_GetCPFieldNameUTF; + JVM_GetCPFieldSignatureUTF; + JVM_GetCPMethodClassNameUTF; + JVM_GetCPMethodModifiers; + JVM_GetCPMethodNameUTF; + JVM_GetCPMethodSignatureUTF; + JVM_GetCallerClass; + JVM_GetClassAccessFlags; + JVM_GetClassAnnotations; + JVM_GetClassCPEntriesCount; + JVM_GetClassCPTypes; + JVM_GetClassConstantPool; + JVM_GetClassContext; + JVM_GetClassDeclaredConstructors; + JVM_GetClassDeclaredFields; + JVM_GetClassDeclaredMethods; + JVM_GetClassFieldsCount; + JVM_GetClassInterfaces; + JVM_GetClassLoader; + JVM_GetClassMethodsCount; + JVM_GetClassModifiers; + JVM_GetClassName; + JVM_GetClassNameUTF; + JVM_GetClassSignature; + JVM_GetClassSigners; + JVM_GetClassTypeAnnotations; + JVM_GetComponentType; + JVM_GetDeclaredClasses; + JVM_GetDeclaringClass; + JVM_GetEnclosingMethodInfo; + JVM_GetFieldAnnotations; + JVM_GetFieldIxModifiers; + JVM_GetFieldTypeAnnotations; + JVM_GetHostName; + JVM_GetInheritedAccessControlContext; + JVM_GetInterfaceVersion; + JVM_GetLastErrorString; + JVM_GetManagement; + JVM_GetMethodAnnotations; + JVM_GetMethodDefaultAnnotationValue; + JVM_GetMethodIxArgsSize; + JVM_GetMethodIxByteCode; + JVM_GetMethodIxByteCodeLength; + JVM_GetMethodIxExceptionIndexes; + JVM_GetMethodIxExceptionTableEntry; + JVM_GetMethodIxExceptionTableLength; + JVM_GetMethodIxExceptionsCount; + JVM_GetMethodIxLocalsCount; + JVM_GetMethodIxMaxStack; + JVM_GetMethodIxModifiers; + JVM_GetMethodIxNameUTF; + JVM_GetMethodIxSignatureUTF; + JVM_GetMethodParameterAnnotations; + JVM_GetMethodParameters; + JVM_GetMethodTypeAnnotations; + JVM_GetPrimitiveArrayElement; + JVM_GetProtectionDomain; + JVM_GetSockName; + JVM_GetSockOpt; + JVM_GetStackAccessControlContext; + JVM_GetStackTraceDepth; + JVM_GetStackTraceElement; + JVM_GetSystemPackage; + JVM_GetSystemPackages; + JVM_GetTemporaryDirectory; + JVM_GetThreadStateNames; + JVM_GetThreadStateValues; + JVM_GetVersionInfo; + JVM_Halt; + JVM_HoldsLock; + JVM_IHashCode; + JVM_InitAgentProperties; + JVM_InitProperties; + JVM_InitializeCompiler; + JVM_InitializeSocketLibrary; + JVM_InternString; + JVM_Interrupt; + JVM_InvokeMethod; + JVM_IsArrayClass; + JVM_IsConstructorIx; + JVM_IsInterface; + JVM_IsInterrupted; + JVM_IsNaN; + JVM_IsPrimitiveClass; + JVM_IsSameClassPackage; + JVM_IsSilentCompiler; + JVM_IsSupportedJNIVersion; + JVM_IsThreadAlive; + JVM_IsVMGeneratedMethodIx; + JVM_LatestUserDefinedLoader; + JVM_Listen; + JVM_LoadClass0; + JVM_LoadLibrary; + JVM_Lseek; + JVM_MaxObjectInspectionAge; + JVM_MaxMemory; + JVM_MonitorNotify; + JVM_MonitorNotifyAll; + JVM_MonitorWait; + JVM_NanoTime; + JVM_NativePath; + JVM_NewArray; + JVM_NewInstanceFromConstructor; + JVM_NewMultiArray; + JVM_OnExit; + JVM_Open; + JVM_RaiseSignal; + JVM_RawMonitorCreate; + JVM_RawMonitorDestroy; + JVM_RawMonitorEnter; + JVM_RawMonitorExit; + JVM_Read; + JVM_Recv; + JVM_RecvFrom; + JVM_RegisterSignal; + JVM_ReleaseUTF; + JVM_ResolveClass; + JVM_KnownToNotExist; + JVM_GetResourceLookupCacheURLs; + JVM_GetResourceLookupCache; + JVM_ResumeThread; + JVM_Send; + JVM_SendTo; + JVM_SetArrayElement; + JVM_SetClassSigners; + JVM_SetLength; + JVM_SetNativeThreadName; + JVM_SetPrimitiveArrayElement; + JVM_SetSockOpt; + JVM_SetThreadPriority; + JVM_Sleep; + JVM_Socket; + JVM_SocketAvailable; + JVM_SocketClose; + JVM_SocketShutdown; + JVM_StartThread; + JVM_StopThread; + JVM_SuspendThread; + JVM_SupportsCX8; + JVM_Sync; + JVM_Timeout; + JVM_TotalMemory; + JVM_TraceInstructions; + JVM_TraceMethodCalls; + JVM_UnloadLibrary; + JVM_Write; + JVM_Yield; + JVM_handle_linux_signal; + + # miscellaneous functions + jio_fprintf; + jio_printf; + jio_snprintf; + jio_vfprintf; + jio_vsnprintf; + fork1; + numa_warn; + numa_error; + + # Needed because there is no JVM interface for this. + sysThreadAvailableStackWithSlack; + + # This is for Forte Analyzer profiling support. + AsyncGetCallTrace; + + # JNI varargs entry points + __JNI_CallObjectMethod; + __JNI_CallObjectMethodV; + __JNI_CallNonvirtualObjectMethod; + __JNI_CallNonvirtualObjectMethodV; + __JNI_CallStaticObjectMethod; + __JNI_CallStaticObjectMethodV; + __JNI_CallBooleanMethod; + __JNI_CallBooleanMethodV; + __JNI_CallNonvirtualBooleanMethod; + __JNI_CallNonvirtualBooleanMethodV; + __JNI_CallStaticBooleanMethod; + __JNI_CallStaticBooleanMethodV; + __JNI_CallByteMethod; + __JNI_CallByteMethodV; + __JNI_CallNonvirtualByteMethod; + __JNI_CallNonvirtualByteMethodV; + __JNI_CallStaticByteMethod; + __JNI_CallStaticByteMethodV; + __JNI_CallCharMethod; + __JNI_CallCharMethodV; + __JNI_CallNonvirtualCharMethod; + __JNI_CallNonvirtualCharMethodV; + __JNI_CallStaticCharMethod; + __JNI_CallStaticCharMethodV; + __JNI_CallShortMethod; + __JNI_CallShortMethodV; + __JNI_CallNonvirtualShortMethod; + __JNI_CallNonvirtualShortMethodV; + __JNI_CallStaticShortMethod; + __JNI_CallStaticShortMethodV; + __JNI_CallIntMethod; + __JNI_CallIntMethodV; + __JNI_CallNonvirtualIntMethod; + __JNI_CallNonvirtualIntMethodV; + __JNI_CallStaticIntMethod; + __JNI_CallStaticIntMethodV; + __JNI_CallLongMethod; + __JNI_CallLongMethodV; + __JNI_CallNonvirtualLongMethod; + __JNI_CallNonvirtualLongMethodV; + __JNI_CallStaticLongMethod; + __JNI_CallStaticLongMethodV; + __JNI_CallFloatMethod; + __JNI_CallFloatMethodV; + __JNI_CallNonvirtualFloatMethod; + __JNI_CallNonvirtualFloatMethodV; + __JNI_CallStaticFloatMethod; + __JNI_CallStaticFloatMethodV; + __JNI_CallDoubleMethod; + __JNI_CallDoubleMethodV; + __JNI_CallNonvirtualDoubleMethod; + __JNI_CallNonvirtualDoubleMethodV; + __JNI_CallStaticDoubleMethod; + __JNI_CallStaticDoubleMethodV; + __JNI_NewObject; + __JNI_NewObjectV; + __JNI_CallVoidMethod; + __JNI_CallVoidMethodV; + __JNI_CallNonvirtualVoidMethod; + __JNI_CallNonvirtualVoidMethodV; + __JNI_CallStaticVoidMethod; + __JNI_CallStaticVoidMethodV; + + # INSERT VTABLE SYMBOLS HERE + + local: + *; +}; + diff --git a/src/libkrb5/libkrb5.clangproj b/src/libkrb5/libkrb5.clangproj new file mode 100644 index 0000000000..e0fc23950b --- /dev/null +++ b/src/libkrb5/libkrb5.clangproj @@ -0,0 +1,46 @@ + + + + + 78a745d7-706a-4b33-9d21-0eb7b5144c42 + + + krb5 + w2k_lsa_auth + osxkrb5 + dll + win-x64;win-x86;win-arm64;osx-x64;osx-arm64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libmanagement/libmanagement.clangproj b/src/libmanagement/libmanagement.clangproj index 24fedde391..6e8e5f2e2e 100644 --- a/src/libmanagement/libmanagement.clangproj +++ b/src/libmanagement/libmanagement.clangproj @@ -6,13 +6,36 @@ management + dll + - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/IKVM.Java/local/sun/nio/ch/NativeThread.java b/src/libmanagement/management.c similarity index 76% rename from src/IKVM.Java/local/sun/nio/ch/NativeThread.java rename to src/libmanagement/management.c index 319b5420b8..61ec956f0d 100644 --- a/src/IKVM.Java/local/sun/nio/ch/NativeThread.java +++ b/src/libmanagement/management.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,20 +23,16 @@ * questions. */ -package sun.nio.ch; +#include "management.h" +#include "jvm.h" +#include +#include +#define ERR_MSG_SIZE 128 -// Signalling operations on native threads - - -class NativeThread { - - static long current() { - // return 0 to ensure that async close of blocking sockets will close - // the underlying socket. - return 0; - } - - static void signal(long nt) { } +void throw_internal_error(JNIEnv *env, const char *msg) { + char errmsg[128]; + sprintf(errmsg, "errno: %d error: %s\n", errno, msg); + JNU_ThrowInternalError(env, errmsg); } diff --git a/src/libnet/libnet.clangproj b/src/libnet/libnet.clangproj index 7838a4d256..aaba7f2c37 100644 --- a/src/libnet/libnet.clangproj +++ b/src/libnet/libnet.clangproj @@ -6,49 +6,128 @@ net + dll c99 - $(IncludeDirectories);$(OpenJdkDir)jdk\src\share\native\java\net - $(IncludeDirectories);$(OpenJdkDir)jdk\src\$(OpenJdkTargetOsApiDir)\native\java\net - $(AdditionalCompileOptions);-Wno-int-conversion - + +
+
+ + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + - + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + (); + + foreach (var path in Paths) + { + if (Directory.Exists(path.ItemSpec)) + { + foreach (var file in Directory.GetFiles(path.ItemSpec, "*.c")) + { + var n = Path.GetFileName(file); + if (Excludes.Any(i => i.ItemSpec == n) == false) + items.Add(new TaskItem(file)); + } + } + } + + Items = items.ToArray(); + return true; + } + +} + ]]> + + + + + + + + + + + + + GetLibNetItems; + $(CompileDependsOn); + + + - \ No newline at end of file + diff --git a/src/libosxkrb5/jni_onload.c b/src/libnio/jni_onload.c similarity index 100% rename from src/libosxkrb5/jni_onload.c rename to src/libnio/jni_onload.c diff --git a/src/libnio/libnio.clangproj b/src/libnio/libnio.clangproj index d1131d3240..e0562d14b8 100644 --- a/src/libnio/libnio.clangproj +++ b/src/libnio/libnio.clangproj @@ -6,91 +6,147 @@ nio + dll c99 - $(IncludeDirectories);$(OpenJdkDir)jdk\src\share\native\sun\nio\ch - $(IncludeDirectories);$(OpenJdkDir)jdk\src\$(OpenJdkTargetOsApiDir)\native\sun\nio\ch - $(IncludeDirectories);$(OpenJdkDir)jdk\src\share\native\java\io - $(IncludeDirectories);$(OpenJdkDir)jdk\src\$(OpenJdkTargetOsApiDir)\native\java\io - $(IncludeDirectories);$(OpenJdkDir)jdk\src\share\native\java\net - $(IncludeDirectories);$(OpenJdkDir)jdk\src\$(OpenJdkTargetOsApiDir)\native\java\net - $(AdditionalCompileOptions);-fms-extensions - + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + (); + + foreach (var path in Paths) + foreach (var file in Files) + if (File.Exists(Path.Combine(path.ItemSpec, file.ItemSpec))) + items.Add(new TaskItem(Path.Combine(path.ItemSpec, file.ItemSpec))); + + Items = items.ToArray(); + return true; + } + +} + ]]> + + + + + + + + + + + + + GetLibNioItems; + $(CompileDependsOn); + + + \ No newline at end of file diff --git a/src/libnio/solaris/FileDispatcherImpl.c b/src/libnio/solaris/FileDispatcherImpl.c deleted file mode 100644 index 1dfe32035f..0000000000 --- a/src/libnio/solaris/FileDispatcherImpl.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "jni.h" -#include "jni_util.h" -#include "jvm.h" -#include "jlong.h" -#include "sun_nio_ch_FileDispatcherImpl.h" -#include "java_lang_Long.h" -#include -#include -#include -#include -#include -#if defined(__linux__) -#include -#include -#endif -#include "nio.h" -#include "nio_util.h" - -#ifdef _ALLBSD_SOURCE -#define stat64 stat -#define flock64 flock -#define off64_t off_t -#define F_SETLKW64 F_SETLKW -#define F_SETLK64 F_SETLK - -#define pread64 pread -#define pwrite64 pwrite -#define ftruncate64 ftruncate -#define fstat64 fstat - -#define fdatasync fsync -#endif - -static int preCloseFD = -1; /* File descriptor to which we dup other fd's - before closing them for real */ - - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) -{ - int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { - JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); - return; - } - preCloseFD = sp[0]; - close(sp[1]); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, - jobject fdo, jlong address, jint len) -{ - jint fd = fdval(env, fdo); - void *buf = (void *)jlong_to_ptr(address); - - return convertReturnVal(env, read(fd, buf, len), JNI_TRUE); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo, - jlong address, jint len, jlong offset) -{ - jint fd = fdval(env, fdo); - void *buf = (void *)jlong_to_ptr(address); - - return convertReturnVal(env, pread64(fd, buf, len, offset), JNI_TRUE); -} - -JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, - jobject fdo, jlong address, jint len) -{ - jint fd = fdval(env, fdo); - struct iovec *iov = (struct iovec *)jlong_to_ptr(address); - return convertLongReturnVal(env, readv(fd, iov, len), JNI_TRUE); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, - jobject fdo, jlong address, jint len, jboolean append) -{ - jint fd = fdval(env, fdo); - void *buf = (void *)jlong_to_ptr(address); - - return convertReturnVal(env, write(fd, buf, len), JNI_FALSE); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, - jlong address, jint len, jlong offset) -{ - jint fd = fdval(env, fdo); - void *buf = (void *)jlong_to_ptr(address); - - return convertReturnVal(env, pwrite64(fd, buf, len, offset), JNI_FALSE); -} - -JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, - jobject fdo, jlong address, jint len, jboolean append) -{ - jint fd = fdval(env, fdo); - struct iovec *iov = (struct iovec *)jlong_to_ptr(address); - return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE); -} - -static jlong -handle(JNIEnv *env, jlong rv, char *msg) -{ - if (rv >= 0) - return rv; - if (errno == EINTR) - return IOS_INTERRUPTED; - JNU_ThrowIOExceptionWithLastError(env, msg); - return IOS_THROWN; -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, - jobject fdo, jboolean md) -{ - jint fd = fdval(env, fdo); - int result = 0; - - if (md == JNI_FALSE) { - result = fdatasync(fd); - } else { -#ifdef _AIX - /* On AIX, calling fsync on a file descriptor that is opened only for - * reading results in an error ("EBADF: The FileDescriptor parameter is - * not a valid file descriptor open for writing."). - * However, at this point it is not possibly anymore to read the - * 'writable' attribute of the corresponding file channel so we have to - * use 'fcntl'. - */ - int getfl = fcntl(fd, F_GETFL); - if (getfl >= 0 && (getfl & O_ACCMODE) == O_RDONLY) { - return 0; - } -#endif - result = fsync(fd); - } - return handle(env, result, "Force failed"); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, - jobject fdo, jlong size) -{ - return handle(env, - ftruncate64(fdval(env, fdo), size), - "Truncation failed"); -} - -JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) -{ - jint fd = fdval(env, fdo); - struct stat64 fbuf; - - if (fstat64(fd, &fbuf) < 0) - return handle(env, -1, "Size failed"); - -#ifdef BLKGETSIZE64 - if (S_ISBLK(fbuf.st_mode)) { - uint64_t size; - if (ioctl(fd, BLKGETSIZE64, &size) < 0) - return handle(env, -1, "Size failed"); - return (jlong)size; - } -#endif - - return fbuf.st_size; -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, - jboolean block, jlong pos, jlong size, - jboolean shared) -{ - jint fd = fdval(env, fdo); - jint lockResult = 0; - int cmd = 0; - struct flock64 fl; - - fl.l_whence = SEEK_SET; - if (size == (jlong)java_lang_Long_MAX_VALUE) { - fl.l_len = (off64_t)0; - } else { - fl.l_len = (off64_t)size; - } - fl.l_start = (off64_t)pos; - if (shared == JNI_TRUE) { - fl.l_type = F_RDLCK; - } else { - fl.l_type = F_WRLCK; - } - if (block == JNI_TRUE) { - cmd = F_SETLKW64; - } else { - cmd = F_SETLK64; - } - lockResult = fcntl(fd, cmd, &fl); - if (lockResult < 0) { - if ((cmd == F_SETLK64) && (errno == EAGAIN || errno == EACCES)) - return sun_nio_ch_FileDispatcherImpl_NO_LOCK; - if (errno == EINTR) - return sun_nio_ch_FileDispatcherImpl_INTERRUPTED; - JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); - } - return 0; -} - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this, - jobject fdo, jlong pos, jlong size) -{ - jint fd = fdval(env, fdo); - jint lockResult = 0; - struct flock64 fl; - int cmd = F_SETLK64; - - fl.l_whence = SEEK_SET; - if (size == (jlong)java_lang_Long_MAX_VALUE) { - fl.l_len = (off64_t)0; - } else { - fl.l_len = (off64_t)size; - } - fl.l_start = (off64_t)pos; - fl.l_type = F_UNLCK; - lockResult = fcntl(fd, cmd, &fl); - if (lockResult < 0) { - JNU_ThrowIOExceptionWithLastError(env, "Release failed"); - } -} - - -static void closeFileDescriptor(JNIEnv *env, int fd) { - if (fd != -1) { - int result = close(fd); - if (result < 0) - JNU_ThrowIOExceptionWithLastError(env, "Close failed"); - } -} - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo) -{ - jint fd = fdval(env, fdo); - closeFileDescriptor(env, fd); -} - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo) -{ - jint fd = fdval(env, fdo); - if (preCloseFD >= 0) { - if (dup2(preCloseFD, fd) < 0) - JNU_ThrowIOExceptionWithLastError(env, "dup2 failed"); - } -} - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd) -{ - closeFileDescriptor(env, fd); -} diff --git a/src/libnio/windows/FileDispatcherImpl.c b/src/libnio/windows/FileDispatcherImpl.c deleted file mode 100644 index 0fdc2ab51f..0000000000 --- a/src/libnio/windows/FileDispatcherImpl.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include -#include "jni.h" -#include "jni_util.h" -#include "jvm.h" -#include "jlong.h" -#include "sun_nio_ch_FileDispatcherImpl.h" -#include -#include "nio.h" -#include "nio_util.h" -#include "jlong.h" - - -/************************************************************** - * FileDispatcherImpl.c - */ - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, jobject fdo, - jlong address, jint len) -{ - DWORD read = 0; - BOOL result = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - - if (h == INVALID_HANDLE_VALUE) { - JNU_ThrowIOExceptionWithLastError(env, "Invalid handle"); - return IOS_THROWN; - } - result = ReadFile(h, /* File handle to read */ - (LPVOID)address, /* address to put data */ - len, /* number of bytes to read */ - &read, /* number of bytes read */ - NULL); /* no overlapped struct */ - if (result == 0) { - int error = GetLastError(); - if (error == ERROR_BROKEN_PIPE) { - return IOS_EOF; - } - if (error == ERROR_NO_DATA) { - return IOS_UNAVAILABLE; - } - JNU_ThrowIOExceptionWithLastError(env, "Read failed"); - return IOS_THROWN; - } - return convertReturnVal(env, (jint)read, JNI_TRUE); -} - -JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, jobject fdo, - jlong address, jint len) -{ - DWORD read = 0; - BOOL result = 0; - jlong totalRead = 0; - LPVOID loc; - int i = 0; - DWORD num = 0; - struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address); - HANDLE h = (HANDLE)(handleval(env, fdo)); - - if (h == INVALID_HANDLE_VALUE) { - JNU_ThrowIOExceptionWithLastError(env, "Invalid handle"); - return IOS_THROWN; - } - - for(i=0; i 0) { - totalRead += read; - } - if (read < num) { - break; - } - } - - if (result == 0) { - int error = GetLastError(); - if (error == ERROR_BROKEN_PIPE) { - return IOS_EOF; - } - if (error == ERROR_NO_DATA) { - return IOS_UNAVAILABLE; - } - JNU_ThrowIOExceptionWithLastError(env, "Read failed"); - return IOS_THROWN; - } - - return convertLongReturnVal(env, totalRead, JNI_TRUE); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo, - jlong address, jint len, jlong offset) -{ - DWORD read = 0; - BOOL result = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - DWORD lowPos = 0; - long highPos = 0; - DWORD lowOffset = 0; - long highOffset = 0; - - if (h == INVALID_HANDLE_VALUE) { - JNU_ThrowIOExceptionWithLastError(env, "Invalid handle"); - return IOS_THROWN; - } - - lowPos = SetFilePointer(h, 0, &highPos, FILE_CURRENT); - if (lowPos == ((DWORD)-1)) { - if (GetLastError() != ERROR_SUCCESS) { - JNU_ThrowIOExceptionWithLastError(env, "Seek failed"); - return IOS_THROWN; - } - } - - lowOffset = (DWORD)offset; - highOffset = (DWORD)(offset >> 32); - lowOffset = SetFilePointer(h, lowOffset, &highOffset, FILE_BEGIN); - if (lowOffset == ((DWORD)-1)) { - if (GetLastError() != ERROR_SUCCESS) { - JNU_ThrowIOExceptionWithLastError(env, "Seek failed"); - return IOS_THROWN; - } - } - - result = ReadFile(h, /* File handle to read */ - (LPVOID)address, /* address to put data */ - len, /* number of bytes to read */ - &read, /* number of bytes read */ - NULL); /* struct with offset */ - - if (result == 0) { - int error = GetLastError(); - if (error == ERROR_BROKEN_PIPE) { - return IOS_EOF; - } - if (error == ERROR_NO_DATA) { - return IOS_UNAVAILABLE; - } - JNU_ThrowIOExceptionWithLastError(env, "Read failed"); - return IOS_THROWN; - } - - lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN); - if (lowPos == ((DWORD)-1)) { - if (GetLastError() != ERROR_SUCCESS) { - JNU_ThrowIOExceptionWithLastError(env, "Seek failed"); - return IOS_THROWN; - } - } - return convertReturnVal(env, (jint)read, JNI_TRUE); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, jobject fdo, - jlong address, jint len, jboolean append) -{ - BOOL result = 0; - DWORD written = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - - if (h != INVALID_HANDLE_VALUE) { - OVERLAPPED ov; - LPOVERLAPPED lpOv; - if (append == JNI_TRUE) { - ov.Offset = (DWORD)0xFFFFFFFF; - ov.OffsetHigh = (DWORD)0xFFFFFFFF; - ov.hEvent = NULL; - lpOv = &ov; - } else { - lpOv = NULL; - } - result = WriteFile(h, /* File handle to write */ - (LPCVOID)address, /* pointers to the buffers */ - len, /* number of bytes to write */ - &written, /* receives number of bytes written */ - lpOv); /* overlapped struct */ - } - - if ((h == INVALID_HANDLE_VALUE) || (result == 0)) { - JNU_ThrowIOExceptionWithLastError(env, "Write failed"); - } - - return convertReturnVal(env, (jint)written, JNI_FALSE); -} - -JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fdo, - jlong address, jint len, jboolean append) -{ - BOOL result = 0; - DWORD written = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - jlong totalWritten = 0; - - if (h != INVALID_HANDLE_VALUE) { - LPVOID loc; - int i = 0; - DWORD num = 0; - struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address); - OVERLAPPED ov; - LPOVERLAPPED lpOv; - if (append == JNI_TRUE) { - ov.Offset = (DWORD)0xFFFFFFFF; - ov.OffsetHigh = (DWORD)0xFFFFFFFF; - ov.hEvent = NULL; - lpOv = &ov; - } else { - lpOv = NULL; - } - for(i=0; i 0) { - totalWritten += written; - } - if (written < num) { - break; - } - } - } - - if ((h == INVALID_HANDLE_VALUE) || (result == 0)) { - JNU_ThrowIOExceptionWithLastError(env, "Write failed"); - } - - return convertLongReturnVal(env, totalWritten, JNI_FALSE); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, - jlong address, jint len, jlong offset) -{ - BOOL result = 0; - DWORD written = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - DWORD lowPos = 0; - long highPos = 0; - DWORD lowOffset = 0; - long highOffset = 0; - - lowPos = SetFilePointer(h, 0, &highPos, FILE_CURRENT); - if (lowPos == ((DWORD)-1)) { - if (GetLastError() != ERROR_SUCCESS) { - JNU_ThrowIOExceptionWithLastError(env, "Seek failed"); - return IOS_THROWN; - } - } - - lowOffset = (DWORD)offset; - highOffset = (DWORD)(offset >> 32); - lowOffset = SetFilePointer(h, lowOffset, &highOffset, FILE_BEGIN); - if (lowOffset == ((DWORD)-1)) { - if (GetLastError() != ERROR_SUCCESS) { - JNU_ThrowIOExceptionWithLastError(env, "Seek failed"); - return IOS_THROWN; - } - } - - result = WriteFile(h, /* File handle to write */ - (LPCVOID)address, /* pointers to the buffers */ - len, /* number of bytes to write */ - &written, /* receives number of bytes written */ - NULL); /* no overlapped struct */ - - if ((h == INVALID_HANDLE_VALUE) || (result == 0)) { - JNU_ThrowIOExceptionWithLastError(env, "Write failed"); - return IOS_THROWN; - } - - lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN); - if (lowPos == ((DWORD)-1)) { - if (GetLastError() != ERROR_SUCCESS) { - JNU_ThrowIOExceptionWithLastError(env, "Seek failed"); - return IOS_THROWN; - } - } - - return convertReturnVal(env, (jint)written, JNI_FALSE); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, - jobject fdo, jboolean md) -{ - int result = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - - if (h != INVALID_HANDLE_VALUE) { - result = FlushFileBuffers(h); - if (result == 0) { - int error = GetLastError(); - if (error != ERROR_ACCESS_DENIED) { - JNU_ThrowIOExceptionWithLastError(env, "Force failed"); - return IOS_THROWN; - } - } - } else { - JNU_ThrowIOExceptionWithLastError(env, "Force failed"); - return IOS_THROWN; - } - return 0; -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, - jobject fdo, jlong size) -{ - DWORD lowPos = 0; - long highPos = 0; - BOOL result = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - - lowPos = (DWORD)size; - highPos = (long)(size >> 32); - lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN); - if (lowPos == ((DWORD)-1)) { - if (GetLastError() != ERROR_SUCCESS) { - JNU_ThrowIOExceptionWithLastError(env, "Truncation failed"); - return IOS_THROWN; - } - } - result = SetEndOfFile(h); - if (result == 0) { - JNU_ThrowIOExceptionWithLastError(env, "Truncation failed"); - return IOS_THROWN; - } - return 0; -} - -JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) -{ - DWORD sizeLow = 0; - DWORD sizeHigh = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - - sizeLow = GetFileSize(h, &sizeHigh); - if (sizeLow == ((DWORD)-1)) { - if (GetLastError() != ERROR_SUCCESS) { - JNU_ThrowIOExceptionWithLastError(env, "Size failed"); - return IOS_THROWN; - } - } - return (((jlong)sizeHigh) << 32) | sizeLow; -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, - jboolean block, jlong pos, jlong size, - jboolean shared) -{ - HANDLE h = (HANDLE)(handleval(env, fdo)); - DWORD lowPos = (DWORD)pos; - long highPos = (long)(pos >> 32); - DWORD lowNumBytes = (DWORD)size; - DWORD highNumBytes = (DWORD)(size >> 32); - BOOL result; - DWORD flags = 0; - OVERLAPPED o; - o.hEvent = 0; - o.Offset = lowPos; - o.OffsetHigh = highPos; - if (block == JNI_FALSE) { - flags |= LOCKFILE_FAIL_IMMEDIATELY; - } - if (shared == JNI_FALSE) { - flags |= LOCKFILE_EXCLUSIVE_LOCK; - } - result = LockFileEx(h, flags, 0, lowNumBytes, highNumBytes, &o); - if (result == 0) { - int error = GetLastError(); - if (error != ERROR_LOCK_VIOLATION) { - JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); - return sun_nio_ch_FileDispatcherImpl_NO_LOCK; - } - if (flags & LOCKFILE_FAIL_IMMEDIATELY) { - return sun_nio_ch_FileDispatcherImpl_NO_LOCK; - } - JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); - return sun_nio_ch_FileDispatcherImpl_NO_LOCK; - } - return sun_nio_ch_FileDispatcherImpl_LOCKED; -} - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this, - jobject fdo, jlong pos, jlong size) -{ - HANDLE h = (HANDLE)(handleval(env, fdo)); - DWORD lowPos = (DWORD)pos; - long highPos = (long)(pos >> 32); - DWORD lowNumBytes = (DWORD)size; - DWORD highNumBytes = (DWORD)(size >> 32); - jint result = 0; - OVERLAPPED o; - o.hEvent = 0; - o.Offset = lowPos; - o.OffsetHigh = highPos; - result = UnlockFileEx(h, 0, lowNumBytes, highNumBytes, &o); - if (result == 0 && GetLastError() != ERROR_NOT_LOCKED) { - JNU_ThrowIOExceptionWithLastError(env, "Release failed"); - } -} - -static void closeFile(JNIEnv *env, jlong fd) { - HANDLE h = (HANDLE)fd; - if (h != INVALID_HANDLE_VALUE) { - int result = CloseHandle(h); - if (result < 0) - JNU_ThrowIOExceptionWithLastError(env, "Close failed"); - } -} - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo) -{ - jlong fd = handleval(env, fdo); - closeFile(env, fd); -} - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileDispatcherImpl_closeByHandle(JNIEnv *env, jclass clazz, - jlong fd) -{ - closeFile(env, fd); -} - -JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlong handle) -{ - HANDLE hProcess = GetCurrentProcess(); - HANDLE hFile = jlong_to_ptr(handle); - HANDLE hResult; - BOOL res = DuplicateHandle(hProcess, hFile, hProcess, &hResult, 0, FALSE, - DUPLICATE_SAME_ACCESS); - if (res == 0) - JNU_ThrowIOExceptionWithLastError(env, "DuplicateHandle failed"); - return ptr_to_jlong(hResult); -} diff --git a/src/libosx/libosx.clangproj b/src/libosx/libosx.clangproj index 9ffd0ac9b4..f5825c7df1 100644 --- a/src/libosx/libosx.clangproj +++ b/src/libosx/libosx.clangproj @@ -6,25 +6,27 @@ osx + dll osx-x64;osx-arm64 + - + + - - - + - + + diff --git a/src/libosxapp/libosxapp.clangproj b/src/libosxapp/libosxapp.clangproj index 5cad61f9cd..1d2387e3d4 100644 --- a/src/libosxapp/libosxapp.clangproj +++ b/src/libosxapp/libosxapp.clangproj @@ -5,8 +5,9 @@ 0E068B20-9C99-45C5-8D94-A1FF9EDD6739 - osx-x64;osx-arm64 osxapp + dll + osx-x64;osx-arm64 @@ -19,8 +20,6 @@ - - @@ -29,4 +28,4 @@ - \ No newline at end of file + diff --git a/src/libosxkrb5/libosxkrb5.clangproj b/src/libosxkrb5/libosxkrb5.clangproj deleted file mode 100644 index 28fe5f3841..0000000000 --- a/src/libosxkrb5/libosxkrb5.clangproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - f2969046-1672-4685-ae8d-53aed942dae9 - - - osx-x64;osx-arm64 - osxkrb5 - - - - - - - - - - - \ No newline at end of file diff --git a/src/libsctp/libsctp.clangproj b/src/libsctp/libsctp.clangproj new file mode 100644 index 0000000000..0f9c2fd7bc --- /dev/null +++ b/src/libsctp/libsctp.clangproj @@ -0,0 +1,29 @@ + + + + + d6d8258d-456a-4c72-aba1-1cabc37d471f + + + sctp + dll + linux-x64;linux-arm;linux-arm64;linux-musl-x64;linux-musl-arm;linux-musl-arm64 + c99 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/libsunec/libsunec.clangproj b/src/libsunec/libsunec.clangproj index f28e95473c..6cd4f7ac2b 100644 --- a/src/libsunec/libsunec.clangproj +++ b/src/libsunec/libsunec.clangproj @@ -6,17 +6,25 @@ sunec - $(IncludeDirectories);$(OpenJdkDir)jdk\src\share\native\sun\security\ec\impl - $(PreprocessorDefinitions);MP_API_COMPATIBLE;NSS_ECC_MORE_THAN_SUITE_B + dll + + + + + + + + + - \ No newline at end of file + diff --git a/src/libsunmscapi/libsunmscapi.clangproj b/src/libsunmscapi/libsunmscapi.clangproj index 331ed57088..17c2250e79 100644 --- a/src/libsunmscapi/libsunmscapi.clangproj +++ b/src/libsunmscapi/libsunmscapi.clangproj @@ -13,7 +13,7 @@ - + diff --git a/src/libunpack/jni.cpp b/src/libunpack/jni.cpp index 9625057dce..7ed278ff3d 100644 --- a/src/libunpack/jni.cpp +++ b/src/libunpack/jni.cpp @@ -313,7 +313,7 @@ Java_com_sun_java_util_jar_pack_NativeUnpack_finish(JNIEnv *env, jobject pObj) { CHECK_EXCEPTION_RETURN_VALUE(uPtr, 0); size_t consumed = uPtr->input_consumed(); free_unpacker(env, pObj, uPtr); - return consumed; + return (jlong)consumed; } JNIEXPORT jboolean JNICALL diff --git a/src/libunpack/libunpack.clangproj b/src/libunpack/libunpack.clangproj index dd28b90e89..2322eaa0c5 100644 --- a/src/libunpack/libunpack.clangproj +++ b/src/libunpack/libunpack.clangproj @@ -6,6 +6,7 @@ unpack + dll @@ -18,6 +19,12 @@ + + + + + + - \ No newline at end of file + diff --git a/src/libverify/libverify.clangproj b/src/libverify/libverify.clangproj index 2529b50f8d..712374410f 100644 --- a/src/libverify/libverify.clangproj +++ b/src/libverify/libverify.clangproj @@ -6,6 +6,7 @@ verify + dll c99 @@ -15,6 +16,9 @@ + + + diff --git a/src/libw2k_lsa_auth/jni_onload.c b/src/libw2k_lsa_auth/jni_onload.c deleted file mode 100644 index a66940e94c..0000000000 --- a/src/libw2k_lsa_auth/jni_onload.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -/** -* Dummy method to prevent dlsym from loading JNI_OnLoad from libiava. -*/ -JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - return JNI_VERSION_1_8; -} - -/** -* Dummy method to prevent dlsym from loading JNI_OnUnload from libiava. -*/ -JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved) { - -} diff --git a/src/libw2k_lsa_auth/libw2k_lsa_auth.clangproj b/src/libw2k_lsa_auth/libw2k_lsa_auth.clangproj deleted file mode 100644 index 4fe69ba6e0..0000000000 --- a/src/libw2k_lsa_auth/libw2k_lsa_auth.clangproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - 78a745d7-706a-4b33-9d21-0eb7b5144c42 - - - win-x64;win-x86;win-arm64 - w2k_lsa_auth - - - - - - - - - - - \ No newline at end of file diff --git a/src/orbd/orbd.csproj b/src/orbd/orbd.csproj index 4044ac1ad7..61d24228a0 100644 --- a/src/orbd/orbd.csproj +++ b/src/orbd/orbd.csproj @@ -14,6 +14,7 @@ + diff --git a/src/policytool/policytool.csproj b/src/policytool/policytool.csproj index edebbec2b2..906bb358fc 100644 --- a/src/policytool/policytool.csproj +++ b/src/policytool/policytool.csproj @@ -14,6 +14,7 @@ + diff --git a/src/rmic/rmic.csproj b/src/rmic/rmic.csproj index c13af86ed6..0e42cf1469 100644 --- a/src/rmic/rmic.csproj +++ b/src/rmic/rmic.csproj @@ -14,6 +14,7 @@ + diff --git a/src/schemagen/schemagen.csproj b/src/schemagen/schemagen.csproj index ea484fc107..9fd21a428e 100644 --- a/src/schemagen/schemagen.csproj +++ b/src/schemagen/schemagen.csproj @@ -14,6 +14,7 @@ + diff --git a/src/wsgen/wsgen.csproj b/src/wsgen/wsgen.csproj index 29c48154d7..8158dba76f 100644 --- a/src/wsgen/wsgen.csproj +++ b/src/wsgen/wsgen.csproj @@ -14,6 +14,7 @@ + diff --git a/src/wsimport/wsimport.csproj b/src/wsimport/wsimport.csproj index b6cd0e8769..11e25800ba 100644 --- a/src/wsimport/wsimport.csproj +++ b/src/wsimport/wsimport.csproj @@ -14,6 +14,7 @@ + diff --git a/src/xjc/xjc.csproj b/src/xjc/xjc.csproj index 8c9495a678..6256985dc3 100644 --- a/src/xjc/xjc.csproj +++ b/src/xjc/xjc.csproj @@ -5,7 +5,7 @@ Exe - net472;net6.0;net8.0 + net8.0;net472;net6.0; $(_SupportedImageRuntimes) true com.sun.tools.internal.xjc.Driver @@ -14,6 +14,7 @@ + diff --git a/targets/ClangOSXCodeSign.targets b/targets/ClangOSXCodeSign.targets index dbd6c146be..16d1dc5b15 100644 --- a/targets/ClangOSXCodeSign.targets +++ b/targets/ClangOSXCodeSign.targets @@ -12,14 +12,14 @@ - true + true codesign -fs - rcodesign sign - - - + + + diff --git a/targets/ClangProjectReference.targets b/targets/ClangProjectReference.targets index b7c18acf49..a59e6992d1 100644 --- a/targets/ClangProjectReference.targets +++ b/targets/ClangProjectReference.targets @@ -59,29 +59,30 @@ - + <_ClangProjectReferenceItems Include="@(_ResolvedClangProjectReferenceTargetOutput)" /> + - - runtimes\%(_ClangProjectReferenceItems.TargetIdentifier)\native\%(_ClangProjectReferenceItems.Filename)%(_ClangProjectReferenceItems.Extension) - %(_ClangProjectReferenceItems.Filename)%(_ClangProjectReferenceItems.Extension) + + runtimes\%(ClangOutputItems.TargetIdentifier)\native\%(ClangOutputItems.Filename)%(ClangOutputItems.Extension) + %(ClangOutputItems.Filename)%(ClangOutputItems.Extension) PreserveNewest - Never - runtimes\%(_ClangProjectReferenceItems.TargetIdentifier)\native\%(_ClangProjectReferenceItems.Filename)%(_ClangProjectReferenceItems.Extension) - true + Never + runtimes\%(ClangOutputItems.TargetIdentifier)\native\%(ClangOutputItems.Filename)%(ClangOutputItems.Extension) + true - + @@ -92,8 +93,8 @@ GetClangProjectReferenceOutputItems; - - + + GetClangProjectReferences; GetClangProjectReferenceItems; @@ -104,12 +105,12 @@ - - %(_ClangProjectReferenceItems.TargetName) - %(_ClangProjectReferenceItems.Version) + + %(ClangOutputItems.TargetName) + %(ClangOutputItems.Version) project - %(_ClangProjectReferenceItems.ProjectName)/%(_ClangProjectReferenceItems.Version) - %(_ClangProjectReferenceItems.TargetIdentifier) + %(ClangOutputItems.ProjectName)/%(ClangOutputItems.Version) + %(ClangOutputItems.TargetIdentifier) diff --git a/targets/lib.props b/targets/lib.props index 8986f098e4..d1ef7c5c17 100644 --- a/targets/lib.props +++ b/targets/lib.props @@ -12,7 +12,6 @@ - library true true $(_SupportedRuntimes) @@ -30,28 +29,29 @@ - - - - - + + + + - + - + true - x64 - x86 - arm64 - arm + x64 + x86 + arm64 + arm - - + + + + @@ -62,7 +62,7 @@ win.ci - + @@ -79,65 +79,59 @@ - - - - - + + $(MSBuildThisFileDirectory)..\ext\ikvm-native-sdk\linux-x64\ + - - - - - + + $(MSBuildThisFileDirectory)..\ext\ikvm-native-sdk\linux-arm64\ + - - - - - + + $(MSBuildThisFileDirectory)..\ext\ikvm-native-sdk\linux-arm\ + - - - - - + + $(MSBuildThisFileDirectory)..\ext\ikvm-native-sdk\linux-musl-x64\ + - - - - - + + $(MSBuildThisFileDirectory)..\ext\ikvm-native-sdk\linux-musl-arm64\ + + + + $(MSBuildThisFileDirectory)..\ext\ikvm-native-sdk\linux-musl-arm\ + - - - - + + + + - + - + true - + - + false true - + @@ -145,4 +139,4 @@ - + \ No newline at end of file diff --git a/targets/openjdk.buildtools.targets b/targets/openjdk.buildtools.targets new file mode 100644 index 0000000000..b7e1dd6142 --- /dev/null +++ b/targets/openjdk.buildtools.targets @@ -0,0 +1,86 @@ + + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + + + $([System.IO.Path]::GetFullPath('$(JAVA_HOME)\lib\tools.jar')) + + + + + + + $(IntermediateOutputPath)btclasses.javac.rsp + $(IntermediateOutputPath)btclasses\ + $(IntermediateOutputPath)$(MSBuildProjectName).OpenJdkBuildTools.stamp + + + + + + + + + + + + + + + <_OpenJdkBuildToolsJavaCompilerClasspath Include="$(OpenJdkToolsJarPath)" /> + + + + <_OpenJdkBuildToolsJavaCompilerClasspathArg>@(_OpenJdkBuildToolsJavaCompilerClasspath, '$([System.IO.Path]::PathSeparator)') + <_OpenJdkBuildToolsJavaCompilerClasspathArg>$(_OpenJdkBuildToolsJavaCompilerClasspathArg.Replace('\', '\\')) + + + + <_OpenJdkBuildToolsJavaCompilerArgs Include="-cp" /> + <_OpenJdkBuildToolsJavaCompilerArgs Include=""$([MSBuild]::Escape('$(_OpenJdkBuildToolsJavaCompilerClasspathArg)'))"" /> + <_OpenJdkBuildToolsJavaCompilerArgs Include="-source" /> + <_OpenJdkBuildToolsJavaCompilerArgs Include="1.8" /> + <_OpenJdkBuildToolsJavaCompilerArgs Include="-target" /> + <_OpenJdkBuildToolsJavaCompilerArgs Include="1.8" /> + <_OpenJdkBuildToolsJavaCompilerArgs Include="-nowarn" /> + <_OpenJdkBuildToolsJavaCompilerArgs Include="-d" /> + <_OpenJdkBuildToolsJavaCompilerArgs Include="$(OpenJdkBuildToolsOutputPath)" /> + <_OpenJdkBuildToolsJavaCompilerArgs Include="@(OpenJdkBuildToolsSource->'%(FullPath)')" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +