001/*******************************************************************************
002 * Copyright (c) 2024, 2026, Olivier Ayache.  All rights reserved.
003 *
004 * This file is part of AVPKit.
005 *
006 * AVPKit is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU Lesser General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * AVPKit is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with AVPKit.  If not, see <http://www.gnu.org/licenses/>.
018 *******************************************************************************/
019package com.avpkit.ferry;
020
021/**
022 * A set of utilities that can be used to find out
023 * information about the Native environment that
024 * we are running within.
025 * @author aclarke
026 *
027 */
028public class JNIEnv
029{
030  /**
031   * The CPU architecture (i.e. chip architecture).
032   * @author aclarke
033   *
034   */
035  enum CPUArch{
036    /** 32-bit systems such as the i386, i486, i586 or i686 */
037    X86,
038    /** 64-bit systems based on the x86 family */
039    X86_64,
040    /** 32-bit PowerPC based systems */
041    PPC,
042    /** 64-bit PowerPC based systems */
043    PPC64,
044    /** 32-bit ARM based systems */
045    ARM,
046    /** 64-bit ARM based systems */
047    ARM_64,
048    /** A chip architecture unknown to {@link Ferry}. */
049    UNKNOWN,
050  }
051  /** The Operating system family */
052  enum OSFamily {
053    /** Linux family of operating systems */
054    LINUX,
055    /** Macintosh (darwin) family of operating systems */
056    MAC,
057    /** Microsoft Windows family of operating systems */
058    WINDOWS,
059    /** An unknown OS that {@link Ferry} knows nothing about */
060    UNKNOWN,
061  }
062  /**
063   * Our singleton.
064   */
065  private static final JNIEnv mEnv = new JNIEnv();
066  
067  private final CPUArch mCPUArch;
068  private final OSFamily mOSFamily;
069  
070  /** Private. Only one {@link JNIEnv} is allowed per Java Virtual machine. */
071  private JNIEnv() {
072    mCPUArch = getCPUArch(System.getProperty("os.arch"));
073    mOSFamily = getOSFamily(System.getProperty("os.name"));
074  }
075  
076  /**
077   * Get the (static) {@link JNIEnv} for this JVM.
078   * @return the environment
079   */
080  public static JNIEnv getEnv() { return mEnv; }
081
082  /**
083   * Get the CPU architecture based on the passed in javaCPUArch specifier.
084   * 
085   * The string should be of a format returned from {@link System#getProperty(String)}
086   * for the property "os.arch".
087   * 
088   * @param javaCPU the string to parse
089   * @return the CPU architecture
090   * @see System#getProperty(String)
091   */
092  public static CPUArch getCPUArch(String javaCPU)
093  {
094    final CPUArch javaArch;
095    final String javaCPUArch = javaCPU != null ? javaCPU.toLowerCase() : "";
096    
097    // first parse the java arch
098    if (javaCPUArch.startsWith("x86_64") ||
099        javaCPUArch.startsWith("amd64") ||
100        javaCPUArch.startsWith("ia64")) {
101      javaArch = CPUArch.X86_64;
102    } else if (
103        javaCPUArch.startsWith("ppc64") ||
104        javaCPUArch.startsWith("powerpc64")
105        ) {
106      javaArch = CPUArch.PPC64;
107    } else if (
108        javaCPUArch.startsWith("ppc") ||
109        javaCPUArch.startsWith("powerpc")
110        ) {
111      javaArch = CPUArch.PPC;
112    } else if (
113        javaCPUArch.startsWith("arm")) {
114      javaArch = CPUArch.ARM;
115    } else if (
116        javaCPUArch.startsWith("aarch64")) {
117      javaArch = CPUArch.ARM_64;
118    } else if (
119        javaCPUArch.contains("86")
120        )
121    {
122      javaArch = CPUArch.X86;
123    } else {
124      javaArch = CPUArch.UNKNOWN;
125    }
126    return javaArch;
127  }
128  
129  /**
130   * Return a CPUArch from parsing a GNU autoconf triple.
131   * 
132   * For example "x86_64-w64-mingw32" will return {@link JNIEnv.CPUArch#X86_64}
133   * and "ppc-apple-darwin" will return {@link JNIEnv.CPUArch#PPC}.
134   * 
135   * @param gnuString the GNU string
136   * @return the architecture
137   */
138  public static CPUArch getCPUArchFromGNUString(String gnuString)
139  {
140    final String nativeCpu = gnuString.toLowerCase();
141    final CPUArch nativeArch;
142    // then the native arch
143    if (nativeCpu.startsWith("x86_64") ||
144        nativeCpu.startsWith("amd64") ||
145        nativeCpu.startsWith("ia64"))
146      nativeArch = CPUArch.X86_64;
147    else if (
148        nativeCpu.startsWith("ppc64") ||
149        nativeCpu.startsWith("powerpc64")
150        )
151      nativeArch = CPUArch.PPC64;
152    else if (
153        nativeCpu.startsWith("ppc") ||
154        nativeCpu.startsWith("powerpc")
155        )
156      nativeArch = CPUArch.PPC;
157    else if (
158        nativeCpu.startsWith("arm")
159        )
160      nativeArch = CPUArch.ARM;
161    else if (
162        nativeCpu.startsWith("aarch64")
163        )
164      nativeArch = CPUArch.ARM_64;
165    else if (
166        nativeCpu.contains("86")
167        )
168      nativeArch = CPUArch.X86;
169    else
170      nativeArch = CPUArch.UNKNOWN;
171 
172    return nativeArch;
173  }
174  
175  /**
176   * Get the OSFamily based on the passed in osName specifier.
177   * 
178   * The string should be of a format returned from {@link System#getProperty(String)}
179   * for the property "os.name".
180   * 
181   * @param osName the string to parse
182   * @return the OSFamily
183   * @see System#getProperty(String)
184   */
185  public static OSFamily getOSFamily(String osName)
186  {
187    final OSFamily retval;
188    
189    if (osName != null && osName.length() > 0)
190    {
191      if (osName.startsWith("Windows"))
192        retval = OSFamily.WINDOWS;
193      else if (osName.startsWith("Mac"))
194        retval = OSFamily.MAC;
195      else if (osName.startsWith("Linux"))
196        retval = OSFamily.LINUX;
197      else
198        retval = OSFamily.UNKNOWN;
199    } else
200      retval = OSFamily.UNKNOWN;
201    return retval;
202  }
203  
204  /**
205   * Return an OS Family from parsing a GNU autoconf triple.
206   * 
207   * For example "x86_64-w64-mingw32" will return {@link JNIEnv.OSFamily#WINDOWS}
208   * and "ppc-apple-darwin" will return {@link JNIEnv.OSFamily#MAC}.
209   * 
210   * @param gnuString the GNU string
211   * @return the OSFamily
212   */
213  public static OSFamily getOSFamilyFromGNUString(String gnuString)
214  {
215    final String nativeOs = (gnuString != null ? gnuString.toLowerCase() : "");
216    final OSFamily retval;
217    if (nativeOs.startsWith("mingw") || nativeOs.startsWith("cygwin"))
218      retval = OSFamily.WINDOWS;
219    else if (nativeOs.startsWith("darwin"))
220      retval = OSFamily.MAC;
221    else if (nativeOs.startsWith("linux") || nativeOs.startsWith("android"))
222      retval = OSFamily.LINUX;
223    else
224      retval = OSFamily.UNKNOWN;
225    return retval;
226  }
227
228  /**
229   * @return the {@link JNIEnv.CPUArch} of this Java Virtual Machine.
230   */
231  public CPUArch getCPUArch()
232  {
233    return mCPUArch;
234  }
235
236  /**
237   * @return the {@link JNIEnv.OSFamily} of this Java Virtual Machine.
238   */
239  public OSFamily getOSFamily()
240  {
241    return mOSFamily;
242  }
243}