summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVmwareFileFormat.java
blob: 356a0348141493174883b7a4084907ce26b00a53 (plain) (tree)
1
                                                 
















                                         

                                           

                             
                  
 

                                  
 









                                                        
                                                                                                                       


                                                                                                  
                                                            



                         
                                                                                                                                




















                                                                        
                                                                                                                                     













                                                                                
                                                                                                                                       



                                           
                                                         
                                                                                                      
         
                     
                                                
                                                                                   


                                                                        
 


                                                                                                                               
                                                                                                                                  
                                                                                                      

                                                               


                                                                                  
                                         
                                                                                                       
                         




                                                                                               


                                                                                                     

                                                                                                          
                                                                                                                            

         





                                                                                     

                                                                         
                                                                                                   

                                     







                                                                                    
                          

         






                                                         
                                                        



                           
                                                             
         
                                         









                                                                                                                                       


                                                                                                                                                     



                                                                                         

                                    








                                                         

                                                                                                                                                      
 
                                                        







                                                                  
                                                                                  





















                                                                           




                                        







                                                    

                                
         
                                            


                                                                               



                                                        



                                     


                                       





                                                  




















                                                                 
         
 
package org.openslx.virtualization.configuration;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openslx.util.Util;

class KeyValuePair
{
	public final String key;
	public final String value;

	public KeyValuePair( String key, String value )
	{
		this.key = key;
		this.value = value;
	}
}

public class VirtualizationConfigurationVmwareFileFormat
{

	private static final Logger LOGGER = LogManager.getLogger( VirtualizationConfigurationVmwareFileFormat.class );

	private Map<String, ConfigEntry> entries = new TreeMap<>( String.CASE_INSENSITIVE_ORDER );

	public VirtualizationConfigurationVmwareFileFormat()
	{
		// (void)
	}

	public VirtualizationConfigurationVmwareFileFormat( File file ) throws IOException, VirtualizationConfigurationException
	{
		int todo = (int)Math.min( 100000, file.length() );
		int offset = 0;
		byte[] data = new byte[ todo ];
		FileInputStream fr = null;
		try {
			fr = new FileInputStream( file );
			while ( todo > 0 ) {
				int ret = fr.read( data, offset, todo );
				if ( ret <= 0 )
					break;
				todo -= ret;
				offset += ret;
			}
		} finally {
			Util.safeClose( fr );
		}
		init( data, offset );

	}

	public VirtualizationConfigurationVmwareFileFormat( InputStream is ) throws IOException, VirtualizationConfigurationException
	{
		int todo = Math.max( 4000, Math.min( 100000, is.available() ) );
		int offset = 0;
		byte[] data = new byte[ todo ];
		while ( todo > 0 ) {
			int ret = is.read( data, offset, todo );
			if ( ret <= 0 )
				break;
			todo -= ret;
			offset += ret;
		}
		init( data, offset );
	}

	public VirtualizationConfigurationVmwareFileFormat( byte[] vmxContent, int length ) throws VirtualizationConfigurationException
	{
		init( vmxContent, length );
	}

	// function is used for both .vmx and .vmdk files
	private void init( byte[] vmxContent, int length ) throws VirtualizationConfigurationException
	{
		try {
			boolean isValid = false;
			BufferedReader reader = getVmxReader( vmxContent, length );
			String line;
			while ( ( line = reader.readLine() ) != null ) {
				KeyValuePair entry = parse( line );

				if ( entry != null ) {
					// TODO: This is supposed to be case insensitive.
					// Check if there are other consequences from lowercase entries in converted vmx files.
					if ( entry.key.equals( "virtualHW.version" ) || entry.key.equals( "ddb.virtualHWVersion" )
							|| entry.key.equals( "virtualhw.version" ) ) {
						isValid = true;
					}
					set( entry.key, unescape( entry.value ) );
				}
			}
			if ( !isValid ) {
				throw new VirtualizationConfigurationException( "Not in VMX format." );
			}
		} catch ( IOException e ) {
			LOGGER.warn( "Exception when loading vmx from byte array (how!?)", e );
		}
	}

	public static BufferedReader getVmxReader( byte[] vmxContent, int length ) throws IOException
	{
		Charset cs = getCharset( vmxContent, length );
		if ( cs == null )
			cs = StandardCharsets.UTF_8; // YES BECAUSE THIS IS NOT VMX AND EVERYTHING IS SHIT
		return new BufferedReader( new InputStreamReader( new ByteArrayInputStream( vmxContent, 0, length ), cs ) );
	}

	/**
	 * Get charset of config. Returns null if input doesn't look like a vmx file.
	 * @param vmxContent
	 * @param length
	 * @return
	 */
	public static Charset getCharset( byte[] vmxContent, int length )
	{
		String csName = detectCharset( new ByteArrayInputStream( vmxContent, 0, length ) );
		if ( csName == null )
			return null;
		Charset cs = null;
		try {
			cs = Charset.forName( csName );
		} catch ( Exception e ) {
			LOGGER.warn( "Could not instantiate charset " + csName, e );
		}
		if ( cs == null )
			cs = StandardCharsets.ISO_8859_1;
		return cs;
	}

	private String unescape( String value )
	{
		String ret = value;
		if ( ret.contains( "|22" ) ) {
			ret = ret.replace( "|22", "\"" );
		}
		if ( ret.contains( "|7C" ) ) {
			ret = ret.replace( "|7C", "|" );
		}
		return ret;
	}

	private static String detectCharset( InputStream is )
	{
		boolean isVmware = false;
		try {
			BufferedReader csDetectReader = new BufferedReader( new InputStreamReader( is, StandardCharsets.ISO_8859_1 ) );
			String line;
			while ( ( line = csDetectReader.readLine() ) != null ) {
				KeyValuePair entry = parse( line );
				if ( entry == null )
					continue;
				if ( entry.key.equals( ".encoding" ) || entry.key.equals( "encoding" ) ) {
					return entry.value;
				}
				if ( entry.key.equals( "virtualHW.version" ) || entry.key.equals( "memsize" ) || entry.key.equals( "displayName") ) {
					isVmware = true;
				}
			}
		} catch ( Exception e ) {
			LOGGER.warn( "Could not detect charset, fallback to latin1", e );
		}
		if ( !isVmware )
			return null;
		// Dumb fallback
		return "ISO-8859-1";
	}

	public Set<Entry<String, ConfigEntry>> entrySet()
	{
		return entries.entrySet();
	}

	private static final Pattern settingMatcher1 = Pattern.compile( "^\\s*(#?[a-z0-9\\.\\:_]+)\\s*=\\s*\"(.*)\"\\s*$", Pattern.CASE_INSENSITIVE );
	private static final Pattern settingMatcher2 = Pattern.compile( "^\\s*(#?[a-z0-9\\.\\:_]+)\\s*=\\s*([^\"]*)\\s*$", Pattern.CASE_INSENSITIVE );

	private static KeyValuePair parse( String line )
	{
		Matcher matcher = settingMatcher1.matcher( line );
		if ( !matcher.matches() ) {
			matcher = settingMatcher2.matcher( line );
		}
		if ( !matcher.matches() ) {
			return null;
		}
		return new KeyValuePair( matcher.group( 1 ), matcher.group( 2 ) );

	}

	public ConfigEntry set( String key, String value, boolean replace )
	{
		if ( !replace && entries.containsKey( key ) )
			return null;
		ConfigEntry ce = new ConfigEntry( value );
		entries.put( key, ce );
		return ce;
	}

	public ConfigEntry set( String key, String value )
	{
		return set( key, value, true );
	}

	public ConfigEntry set( KeyValuePair entry )
	{
		return set( entry.key, entry.value );
	}

	public void remove( String key )
	{
		entries.remove( key );
	}

	public String get( String key )
	{
		ConfigEntry ce = entries.get( key );
		if ( ce == null )
			return null;
		return ce.value;
	}

	@Override
	public String toString()
	{
		set( ".encoding", "UTF-8" );
		StringBuilder sb = new StringBuilder( 300 );
		for ( Entry<String, ConfigEntry> entry : entries.entrySet() ) {
			ConfigEntry value = entry.getValue();
			sb.append( entry.getKey() );
			sb.append( " = \"" );
			sb.append( value.getEscaped() );
			sb.append( "\"\n" );
		}
		return sb.toString();
	}

	public static class ConfigEntry
	{
		private String value;

		public ConfigEntry( String value )
		{
			this.value = value;
		}

		public String getEscaped()
		{
			String ret = value;
			if ( ret.contains( "|" ) ) {
				ret = ret.replace( "|", "|7C" );
			}
			if ( ret.contains( "\"" ) ) {
				ret = ret.replace( "\"", "|22" );
			}
			return ret;
		}

		public String getValue()
		{
			return value;
		}

		public void setValue( String value )
		{
			this.value = value;
		}
	}
}