| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.felix.framework.util.manifestparser; |
| |
| import java.nio.ByteOrder; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Dictionary; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.apache.felix.framework.Logger; |
| import org.apache.felix.framework.util.FelixConstants; |
| import org.osgi.framework.BundleException; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.Filter; |
| import org.osgi.framework.FrameworkUtil; |
| import org.osgi.framework.Version; |
| import org.osgi.framework.VersionRange; |
| |
| public class NativeLibraryClause |
| { |
| private static final String OS_AIX = "aix"; |
| private static final String OS_DIGITALUNIX = "digitalunix"; |
| private static final String OS_EPOC = "epoc32"; |
| private static final String OS_HPUX = "hpux"; |
| private static final String OS_IRIX = "irix"; |
| private static final String OS_LINUX = "linux"; |
| private static final String OS_MACOS = "macos"; |
| private static final String OS_MACOSX = "macosx"; |
| private static final String OS_NETBSD = "netbsd"; |
| private static final String OS_NETWARE = "netware"; |
| private static final String OS_OPENBSD = "openbsd"; |
| private static final String OS_OS2 = "os2"; |
| private static final String OS_QNX = "qnx"; |
| private static final String OS_SOLARIS = "solaris"; |
| private static final String OS_SUNOS = "sunos"; |
| private static final String OS_VXWORKS = "vxworks"; |
| private static final String OS_WINDOWS_2000 = "windows2000"; |
| private static final String OS_WINDOWS_2003 = "windows2003"; |
| private static final String OS_WINDOWS_7 = "windows7"; |
| private static final String OS_WINDOWS_8 = "windows8"; |
| private static final String OS_WINDOWS_9 = "windows9"; |
| private static final String OS_WINDOWS_10 = "windows10"; |
| private static final String OS_WINDOWS_95 = "windows95"; |
| private static final String OS_WINDOWS_98 = "windows98"; |
| private static final String OS_WINDOWS_CE = "windowsce"; |
| private static final String OS_WINDOWS_NT = "windowsnt"; |
| private static final String OS_WINDOWS_SERVER_2008 = "windowsserver2008"; |
| private static final String OS_WINDOWS_SERVER_2012 = "windowsserver2012"; |
| private static final String OS_WINDOWS_SERVER_2016 = "windowsserver2016"; |
| private static final String OS_WINDOWS_VISTA = "windowsvista"; |
| private static final String OS_WINDOWS_XP = "windowsxp"; |
| private static final String OS_WIN_32 = "win32"; |
| |
| private static final String PROC_X86_64 = "x86-64"; |
| private static final String PROC_X86 = "x86"; |
| private static final String PROC_68K = "68k"; |
| private static final String PROC_ARM_LE = "arm_le"; |
| private static final String PROC_ARM_BE = "arm_be"; |
| private static final String PROC_ARM = "arm"; |
| private static final String PROC_ALPHA = "alpha"; |
| private static final String PROC_IGNITE = "ignite"; |
| private static final String PROC_MIPS = "mips"; |
| private static final String PROC_PARISC = "parisc"; |
| private static final String PROC_POWER_PC = "powerpc"; |
| private static final String PROC_SPARC = "sparc"; |
| |
| |
| private static final Map<String, List<String>> OS_ALIASES = new HashMap<String, List<String>>(); |
| |
| private static final Map<String, List<String>> PROC_ALIASES = new HashMap<String, List<String>>(); |
| |
| private final String[] m_libraryEntries; |
| private final String[] m_osnames; |
| private final String[] m_processors; |
| private final String[] m_osversions; |
| private final String[] m_languages; |
| private final String m_selectionFilter; |
| |
| public NativeLibraryClause(String[] libraryEntries, String[] osnames, |
| String[] processors, String[] osversions, String[] languages, |
| String selectionFilter) |
| { |
| m_libraryEntries = libraryEntries; |
| m_osnames = osnames; |
| m_processors = processors; |
| m_osversions = osversions; |
| m_languages = languages; |
| m_selectionFilter = selectionFilter; |
| } |
| |
| public NativeLibraryClause(NativeLibraryClause library) |
| { |
| this(library.m_libraryEntries, library.m_osnames, library.m_osversions, |
| library.m_processors, library.m_languages, |
| library.m_selectionFilter); |
| } |
| |
| /** |
| * Initialize the processor and os name aliases from Felix Config. |
| * |
| * @param configMap |
| */ |
| public static synchronized void initializeNativeAliases(Map configMap) |
| { |
| Map<String, String> osNameKeyMap = getAllKeysWithPrefix(FelixConstants.NATIVE_OS_NAME_ALIAS_PREFIX, configMap); |
| |
| Map<String, String> processorKeyMap = getAllKeysWithPrefix(FelixConstants.NATIVE_PROC_NAME_ALIAS_PREFIX, configMap); |
| |
| parseNativeAliases(osNameKeyMap, OS_ALIASES); |
| parseNativeAliases(processorKeyMap, PROC_ALIASES); |
| } |
| |
| private static void parseNativeAliases(Map<String, String> aliasStringMap, Map<String, List<String>> aliasMap) |
| { |
| for(Map.Entry<String, String> aliasEntryString: aliasStringMap.entrySet()) |
| { |
| String currentAliasKey = aliasEntryString.getKey(); |
| |
| String currentNormalizedName = currentAliasKey.substring(currentAliasKey.lastIndexOf(".")+1); |
| |
| String currentAliasesString = aliasEntryString.getValue(); |
| |
| if(currentAliasesString != null) |
| { |
| String[] aliases = currentAliasesString.split(","); |
| List<String> fullAliasList = new ArrayList<String>(); |
| //normalized name is always first. |
| fullAliasList.add(currentNormalizedName); |
| fullAliasList.addAll(Arrays.asList(aliases)); |
| aliasMap.put(currentNormalizedName, fullAliasList); |
| for(String currentAlias: aliases) |
| { |
| List<String> aliasList = aliasMap.get(currentAlias); |
| if(aliasList == null) |
| { |
| aliasMap.put(currentAlias, fullAliasList); |
| } |
| else |
| { |
| for(String newAliases: aliases) |
| { |
| if(!aliasList.contains(newAliases)) |
| { |
| aliasList.add(newAliases); |
| } |
| } |
| } |
| } |
| } |
| else |
| { |
| List<String> aliasList = aliasMap.get(currentNormalizedName); |
| if(aliasList == null) |
| { |
| aliasMap.put(currentNormalizedName, new ArrayList<String>(Collections.singletonList(currentNormalizedName))); |
| } |
| else |
| { |
| //if the alias is also a normalized name make sure it's first |
| aliasList.add(0, currentNormalizedName); |
| } |
| } |
| } |
| } |
| |
| private static Map<String, String> getAllKeysWithPrefix(String prefix, Map<String, String> configMap) |
| { |
| Map<String, String> keysWithPrefix = new HashMap<String, String>(); |
| for(Map.Entry<String, String> currentEntry: configMap.entrySet()) |
| { |
| if(currentEntry.getKey().startsWith(prefix)) |
| { |
| keysWithPrefix.put(currentEntry.getKey(), currentEntry.getValue()); |
| } |
| } |
| return keysWithPrefix; |
| } |
| |
| public String[] getLibraryEntries() |
| { |
| return m_libraryEntries; |
| } |
| |
| public String[] getOSNames() |
| { |
| return m_osnames; |
| } |
| |
| public String[] getProcessors() |
| { |
| return m_processors; |
| } |
| |
| public String[] getOSVersions() |
| { |
| return m_osversions; |
| } |
| |
| public String[] getLanguages() |
| { |
| return m_languages; |
| } |
| |
| public String getSelectionFilter() |
| { |
| return m_selectionFilter; |
| } |
| |
| public boolean match(Map configMap) throws BundleException |
| { |
| String osName = (String) configMap.get(FelixConstants.FRAMEWORK_OS_NAME); |
| String processorName = (String) configMap.get(FelixConstants.FRAMEWORK_PROCESSOR); |
| String osVersion = (String) configMap.get(FelixConstants.FRAMEWORK_OS_VERSION); |
| String language = (String) configMap.get(FelixConstants.FRAMEWORK_LANGUAGE); |
| |
| // Check library's osname. |
| if ((getOSNames() != null) && |
| (getOSNames().length > 0) && |
| !checkOSNames(osName, getOSNames())) |
| { |
| return false; |
| } |
| |
| // Check library's processor. |
| if ((getProcessors() != null) && |
| (getProcessors().length > 0) && |
| !checkProcessors(processorName, getProcessors())) |
| { |
| return false; |
| } |
| |
| // Check library's osversion if specified. |
| if ((getOSVersions() != null) && |
| (getOSVersions().length > 0) && |
| !checkOSVersions(osVersion, getOSVersions())) |
| { |
| return false; |
| } |
| |
| // Check library's language if specified. |
| if ((getLanguages() != null) && |
| (getLanguages().length > 0) && |
| !checkLanguages(language, getLanguages())) |
| { |
| return false; |
| } |
| |
| // Check library's selection-filter if specified. |
| if ((getSelectionFilter() != null) && |
| !checkSelectionFilter(configMap, getSelectionFilter())) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private boolean checkOSNames(String osName, String[] osnames) |
| { |
| List<String> capabilityOsNames = getOsNameWithAliases(osName); |
| if (capabilityOsNames != null && osnames != null) |
| { |
| for (String curOsName : osnames) |
| { |
| if (capabilityOsNames.contains(curOsName)) |
| { |
| return true; |
| } |
| |
| } |
| } |
| return false; |
| } |
| |
| private boolean checkProcessors(String processorName, String[] processors) |
| { |
| List<String> capabilitiesProcessors = getProcessorWithAliases(processorName); |
| if (capabilitiesProcessors != null && processors != null) |
| { |
| for (String currentProcessor : processors) |
| { |
| if (capabilitiesProcessors.contains(currentProcessor)) |
| { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| private boolean checkOSVersions(String osVersion, String[] osversions) |
| throws BundleException |
| { |
| Version currentOSVersion = Version.parseVersion(normalizeOSVersion(osVersion)); |
| for (int i = 0; (osversions != null) && (i < osversions.length); i++) |
| { |
| try |
| { |
| VersionRange range = new VersionRange(osversions[i]); |
| if (range.includes(currentOSVersion)) |
| { |
| return true; |
| } |
| } |
| catch (Exception ex) |
| { |
| throw new BundleException( |
| "Error evaluating osversion: " + osversions[i], ex); |
| } |
| } |
| return false; |
| } |
| |
| private boolean checkLanguages(String currentLanguage, String[] languages) |
| { |
| for (int i = 0; (languages != null) && (i < languages.length); i++) |
| { |
| if (languages[i].equals(currentLanguage)) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean checkSelectionFilter(Map configMap, String expr) |
| throws BundleException |
| { |
| // Get all framework properties |
| Dictionary dict = new Hashtable(); |
| for (Iterator i = configMap.keySet().iterator(); i.hasNext(); ) |
| { |
| Object key = i.next(); |
| dict.put(key, configMap.get(key)); |
| } |
| // Compute expression |
| try |
| { |
| Filter filter = FrameworkUtil.createFilter(expr); |
| return filter.match(dict); |
| } |
| catch (Exception ex) |
| { |
| throw new BundleException( |
| "Error evaluating filter expression: " + expr, ex); |
| } |
| } |
| |
| public static NativeLibraryClause parse(Logger logger, String s) |
| { |
| try |
| { |
| if ((s == null) || (s.length() == 0)) |
| { |
| return null; |
| } |
| |
| s = s.trim(); |
| if (s.equals(FelixConstants.BUNDLE_NATIVECODE_OPTIONAL)) |
| { |
| return new NativeLibraryClause(null, null, null, null, null, null); |
| } |
| |
| // The tokens are separated by semicolons and may include |
| // any number of libraries along with one set of associated |
| // properties. |
| StringTokenizer st = new StringTokenizer(s, ";"); |
| String[] libEntries = new String[st.countTokens()]; |
| List osNameList = new ArrayList(); |
| List osVersionList = new ArrayList(); |
| List processorList = new ArrayList(); |
| List languageList = new ArrayList(); |
| String selectionFilter = null; |
| int libCount = 0; |
| while (st.hasMoreTokens()) |
| { |
| String token = st.nextToken().trim(); |
| if (token.indexOf('=') < 0) |
| { |
| // Remove the slash, if necessary. |
| libEntries[libCount] = (token.charAt(0) == '/') |
| ? token.substring(1) |
| : token; |
| libCount++; |
| } |
| else |
| { |
| // Check for valid native library properties; defined as |
| // a property name, an equal sign, and a value. |
| // NOTE: StringTokenizer can not be used here because |
| // a value can contain one or more "=" too, e.g., |
| // selection-filter="(org.osgi.framework.windowing.system=gtk)" |
| String property = null; |
| String value = null; |
| if (!(token.indexOf("=") > 1)) |
| { |
| throw new IllegalArgumentException( |
| "Bundle manifest native library entry malformed: " + token); |
| } |
| else |
| { |
| property = (token.substring(0, token.indexOf("="))) |
| .trim().toLowerCase(); |
| value = (token.substring(token.indexOf("=") + 1, token |
| .length())).trim(); |
| } |
| |
| // Values may be quoted, so remove quotes if present. |
| if (value.charAt(0) == '"') |
| { |
| // This should always be true, otherwise the |
| // value wouldn't be properly quoted, but we |
| // will check for safety. |
| if (value.charAt(value.length() - 1) == '"') |
| { |
| value = value.substring(1, value.length() - 1); |
| } |
| else |
| { |
| value = value.substring(1); |
| } |
| } |
| |
| if (value != null) |
| { |
| value = value.toLowerCase(); |
| } |
| |
| // Add the value to its corresponding property list. |
| if (property.equals(Constants.BUNDLE_NATIVECODE_OSNAME)) |
| { |
| osNameList.add(value); |
| } |
| else if (property.equals(Constants.BUNDLE_NATIVECODE_OSVERSION)) |
| { |
| osVersionList.add(normalizeOSVersionRange(value)); |
| } |
| else if (property.equals(Constants.BUNDLE_NATIVECODE_PROCESSOR)) |
| { |
| processorList.add(value); |
| } |
| else if (property.equals(Constants.BUNDLE_NATIVECODE_LANGUAGE)) |
| { |
| languageList.add(value); |
| } |
| else if (property.equals(Constants.SELECTION_FILTER_ATTRIBUTE)) |
| { |
| // TODO: NATIVE - I believe we can have multiple selection filters too. |
| selectionFilter = value; |
| } |
| } |
| } |
| |
| if (libCount == 0) |
| { |
| return null; |
| } |
| |
| // Shrink lib file array. |
| String[] actualLibEntries = new String[libCount]; |
| System.arraycopy(libEntries, 0, actualLibEntries, 0, libCount); |
| return new NativeLibraryClause( |
| actualLibEntries, |
| (String[]) osNameList.toArray(new String[osNameList.size()]), |
| (String[]) processorList.toArray(new String[processorList.size()]), |
| (String[]) osVersionList.toArray(new String[osVersionList.size()]), |
| (String[]) languageList.toArray(new String[languageList.size()]), |
| selectionFilter); |
| } |
| catch (RuntimeException ex) |
| { |
| logger.log(Logger.LOG_ERROR, |
| "Error parsing native library header.", ex); |
| throw ex; |
| } |
| } |
| |
| public static List<String> getOsNameWithAliases(String osName) |
| { |
| //Can't assume this has been normalized |
| osName = normalizeOSName(osName); |
| |
| List<String> result = OS_ALIASES.get(osName); |
| |
| if(result == null) |
| { |
| result = Collections.singletonList(osName); |
| } |
| |
| return Collections.unmodifiableList(result); |
| } |
| |
| public static List<String> getProcessorWithAliases(String processor) |
| { |
| //Can't assume this has been normalized |
| processor = normalizeProcessor(processor); |
| |
| List<String> result = PROC_ALIASES.get(processor); |
| |
| if(result == null) |
| { |
| result = Collections.singletonList(processor); |
| } |
| return Collections.unmodifiableList(result); |
| } |
| |
| public static String normalizeOSName(String value) |
| { |
| value = value.toLowerCase(); |
| |
| if (OS_ALIASES.containsKey(value)) |
| { |
| // we found an alias match return the first value which is the normalized name |
| return OS_ALIASES.get(value).get(0); |
| } |
| |
| //If we don't find a match do it the old way for compatibility |
| if (value.startsWith("win")) |
| { |
| String os = OS_WIN_32; |
| if (value.indexOf("32") >= 0 || value.indexOf("*") >= 0) |
| { |
| os = OS_WIN_32; |
| } |
| else if (value.indexOf("95") >= 0) |
| { |
| os = OS_WINDOWS_95; |
| } |
| else if (value.indexOf("98") >= 0) |
| { |
| os = OS_WINDOWS_98; |
| } |
| else if (value.indexOf("nt") >= 0) |
| { |
| os = OS_WINDOWS_NT; |
| } |
| else if (value.indexOf("2000") >= 0) |
| { |
| os = OS_WINDOWS_2000; |
| } |
| else if (value.indexOf("2003") >= 0) |
| { |
| os = OS_WINDOWS_2003; |
| } |
| else if (value.indexOf("2008") >= 0) |
| { |
| os = OS_WINDOWS_SERVER_2008; |
| } |
| else if (value.indexOf("2012") >= 0) |
| { |
| os = OS_WINDOWS_SERVER_2012; |
| } |
| else if (value.indexOf("2016") >= 0) |
| { |
| os = OS_WINDOWS_SERVER_2016; |
| } |
| else if (value.indexOf("xp") >= 0) |
| { |
| os = OS_WINDOWS_XP; |
| } |
| else if (value.indexOf("ce") >= 0) |
| { |
| os = OS_WINDOWS_CE; |
| } |
| else if (value.indexOf("vista") >= 0) |
| { |
| os = OS_WINDOWS_VISTA; |
| } |
| else if ((value.indexOf(" 7") >= 0) || value.startsWith(OS_WINDOWS_7) |
| || value.equals("win7")) |
| { |
| os = OS_WINDOWS_7; |
| } |
| else if ((value.indexOf(" 8") >= 0) || value.startsWith(OS_WINDOWS_8) |
| || value.equals("win8")) |
| { |
| os = OS_WINDOWS_8; |
| } |
| else if ((value.indexOf(" 9") >= 0) || value.startsWith(OS_WINDOWS_9) |
| || value.equals("win9")) |
| { |
| os = OS_WINDOWS_9; |
| } |
| else if ((value.indexOf(" 10") >= 0) || value.startsWith(OS_WINDOWS_10) |
| || value.equals("win10")) |
| { |
| os = OS_WINDOWS_10; |
| } |
| |
| return os; |
| } |
| else if (value.startsWith(OS_LINUX)) |
| { |
| return OS_LINUX; |
| } |
| else if (value.startsWith(OS_AIX)) |
| { |
| return OS_AIX; |
| } |
| else if (value.startsWith(OS_DIGITALUNIX)) |
| { |
| return OS_DIGITALUNIX; |
| } |
| else if (value.startsWith(OS_HPUX)) |
| { |
| return OS_HPUX; |
| } |
| else if (value.startsWith(OS_IRIX)) |
| { |
| return OS_IRIX; |
| } |
| else if (value.startsWith(OS_MACOSX) || value.startsWith("mac os x")) |
| { |
| return OS_MACOSX; |
| } |
| else if (value.startsWith(OS_MACOS) || value.startsWith("mac os")) |
| { |
| return OS_MACOS; |
| } |
| else if (value.startsWith(OS_NETWARE)) |
| { |
| return OS_NETWARE; |
| } |
| else if (value.startsWith(OS_OPENBSD)) |
| { |
| return OS_OPENBSD; |
| } |
| else if (value.startsWith(OS_NETBSD)) |
| { |
| return OS_NETBSD; |
| } |
| else if (value.startsWith(OS_OS2) || value.startsWith("os/2")) |
| { |
| return OS_OS2; |
| } |
| else if (value.startsWith(OS_QNX) || value.startsWith("procnto")) |
| { |
| return OS_QNX; |
| } |
| else if (value.startsWith(OS_SOLARIS)) |
| { |
| return OS_SOLARIS; |
| } |
| else if (value.startsWith(OS_SUNOS)) |
| { |
| return OS_SUNOS; |
| } |
| else if (value.startsWith(OS_VXWORKS)) |
| { |
| return OS_VXWORKS; |
| } |
| else if (value.startsWith(OS_EPOC)) |
| { |
| return OS_EPOC; |
| } |
| return value; |
| } |
| |
| public static String normalizeProcessor(String value) |
| { |
| value = value.toLowerCase(); |
| |
| if(PROC_ALIASES.containsKey(value)) |
| { |
| return PROC_ALIASES.get(value).get(0); |
| } |
| |
| if (value.startsWith(PROC_X86_64) || value.startsWith("amd64") || |
| value.startsWith("em64") || value.startsWith("x86_64")) |
| { |
| return PROC_X86_64; |
| } |
| else if (value.startsWith(PROC_X86) || value.startsWith("pentium") |
| || value.startsWith("i386") || value.startsWith("i486") |
| || value.startsWith("i586") || value.startsWith("i686")) |
| { |
| return PROC_X86; |
| } |
| else if (value.startsWith(PROC_68K)) |
| { |
| return PROC_68K; |
| } |
| else if (value.startsWith(PROC_ARM_LE)) |
| { |
| return PROC_ARM_LE; |
| } |
| else if (value.startsWith(PROC_ARM_BE)) |
| { |
| return PROC_ARM_BE; |
| } |
| else if (value.startsWith(PROC_ARM)) |
| { |
| return ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ? PROC_ARM_BE : PROC_ARM_LE; |
| } |
| else if (value.startsWith(PROC_ALPHA)) |
| { |
| return PROC_ALPHA; |
| } |
| else if (value.startsWith(PROC_IGNITE) || value.startsWith("psc1k")) |
| { |
| return PROC_IGNITE; |
| } |
| else if (value.startsWith(PROC_MIPS)) |
| { |
| return PROC_MIPS; |
| } |
| else if (value.startsWith(PROC_PARISC)) |
| { |
| return PROC_PARISC; |
| } |
| else if (value.startsWith(PROC_POWER_PC) || value.startsWith("power") |
| || value.startsWith("ppc")) |
| { |
| return PROC_POWER_PC; |
| } |
| else if (value.startsWith(PROC_SPARC)) |
| { |
| return PROC_SPARC; |
| } |
| |
| return value; |
| } |
| |
| public static String normalizeOSVersionRange(String value) |
| { |
| if (value.indexOf(',') >= 0) |
| { |
| try |
| { |
| String s = value.substring(1, value.length() - 1); |
| String vlo = s.substring(0, s.indexOf(',')).trim(); |
| String vhi = s.substring(s.indexOf(',') + 1, s.length()).trim(); |
| return new VersionRange(value.charAt(0), new Version(cleanupVersion(vlo)), new Version( |
| cleanupVersion(vhi)), value.charAt(value.length() - 1)).toString(); |
| } |
| |
| catch (Exception ex) |
| { |
| return Version.emptyVersion.toString(); |
| } |
| } |
| |
| return normalizeOSVersion(value); |
| } |
| |
| public static String normalizeOSVersion(String value) |
| { |
| return new Version(cleanupVersion(value)).toString(); |
| } |
| |
| private static final Pattern FUZZY_VERSION = Pattern.compile( "(\\d+)(\\.(\\d+)(\\.(\\d+))?)?([^a-zA-Z0-9](.*))?", |
| Pattern.DOTALL ); |
| |
| private static String cleanupVersion( String version ) |
| { |
| StringBuilder result = new StringBuilder(); |
| Matcher m = FUZZY_VERSION.matcher( version ); |
| if ( m.matches() ) |
| { |
| String major = m.group( 1 ); |
| String minor = m.group( 3 ); |
| String micro = m.group( 5 ); |
| String qualifier = m.group( 7 ); |
| |
| if ( major != null ) |
| { |
| result.append( major ); |
| if ( minor != null ) |
| { |
| result.append( "." ); |
| result.append( minor ); |
| if ( micro != null ) |
| { |
| result.append( "." ); |
| result.append( micro ); |
| if ( qualifier != null && qualifier.length() > 0 ) |
| { |
| result.append( "." ); |
| cleanupModifier( result, qualifier ); |
| } |
| } |
| else if ( qualifier != null && qualifier.length() > 0) |
| { |
| result.append( ".0." ); |
| cleanupModifier( result, qualifier ); |
| } |
| else |
| { |
| result.append( ".0" ); |
| } |
| } |
| else if ( qualifier != null && qualifier.length() > 0 ) |
| { |
| result.append( ".0.0." ); |
| cleanupModifier( result, qualifier ); |
| } |
| else |
| { |
| result.append( ".0.0" ); |
| } |
| } |
| } |
| else |
| { |
| result.append( "0.0.0." ); |
| cleanupModifier( result, version ); |
| } |
| return result.toString(); |
| } |
| |
| |
| private static void cleanupModifier( StringBuilder result, String modifier ) |
| { |
| for ( int i = 0; i < modifier.length(); i++ ) |
| { |
| char c = modifier.charAt( i ); |
| if ( ( c >= '0' && c <= '9' ) || ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' |
| || c == '-' ) |
| result.append( c ); |
| else |
| result.append( '_' ); |
| } |
| } |
| |
| } |