themeinstaller/source/src/com/nokia/tools/themeinstaller/mediaconverter/MediaConverter.java
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:32:13 +0100
branchRCL_3
changeset 33 04b7640f6fb5
parent 0 05da4621cfb2
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201032 Kit: 201035

/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  This class is used for converting media files
 *
*/

package com.nokia.tools.themeinstaller.mediaconverter;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;

import com.nokia.tools.themeinstaller.odtconverter.ConverterProperties;

/**
 * Base class for different MediaConverters
 * Media converters are used for e.g. converting jpg to mbm
 * @author jutarhon
 *
 */
public class MediaConverter
    {
    protected static final String MEDIA_CONVERTER_APPLICATION= "media_converter";
    private static final String WINDOWS_EXCUTABLE_EXTENSION = "exe";
    private static final String LINUX_OS_NAME = "linux";
    private static final String OPERATING_SYSTEM_PROPERTY = "os.name";
    protected static final char SPACE = ' ';
    protected static final char DOT = '.';
    private static final String BMP = "bmp";
    private static final String COLOR_SETTING = "color_setting";
    protected static String DEFAULT_SUCCESS_LINE = "Success.";

    protected ConverterProperties iProperties;
    private Process iProcess;

    protected String iExtraParameters = null;

    /**
     * Default constructor.
     * @throws IOException If loading properties fails
     */
    public MediaConverter() throws IOException
        {
        iProperties = new ConverterProperties();
        }

    /**
     * Returns possible set extra parameters for running converter application
     * or null if not set
     * @return the iExtraParameters
     */
    public String getExtraParameters()
        {
        return iExtraParameters;
        }

    /**
     * Sets extra parameters for running converter application
     * Set null for unsetting
     * @param aExtraParameters Extra parameters to set
     */
    public void setExtraParameters( String aExtraParameters )
        {
        iExtraParameters = aExtraParameters;
        }

    /**
     * Returns command line parameters for specified filenames
     * including the actual executable
     * example: bmconv.exe target.mbm source.jpg
     * @param aFilenames List of filenames to added to command line
     * @param aTargetFile Filename for target bitmap
     * @return Executable parameters
     */
    protected String getExecParameters( List aFilenames, String aTargetFile )
        {
        StringBuffer sb = new StringBuffer();

        // Get the execution location
        URL resource =
                getClass().getProtectionDomain().getCodeSource().getLocation();
        File bin = new File( resource.getPath() );

        // Find the bmconv from the installation directory
        sb.append( bin.getParent() + File.separatorChar );

        // Windows uses bmconv.exe and Linux bmconv
        if ( System.getProperty( OPERATING_SYSTEM_PROPERTY ).equalsIgnoreCase(
                LINUX_OS_NAME ) )
            {
            sb.append( iProperties.getProperty( MEDIA_CONVERTER_APPLICATION ) );
            }
        else
            {
            sb.append( iProperties.getProperty( MEDIA_CONVERTER_APPLICATION )
                    + DOT + WINDOWS_EXCUTABLE_EXTENSION );
            }

        sb.append( SPACE );
        if( iExtraParameters != null )
            {
            sb.append( iExtraParameters );
            sb.append( SPACE );
            }
        sb.append( aTargetFile );
        sb.append( SPACE );
        for ( Iterator iterator = aFilenames.iterator(); iterator.hasNext(); )
            {
            sb.append( iProperties.getProperty( COLOR_SETTING ) );
            sb.append( iterator.next() );
            if( iterator.hasNext() )
                {
                sb.append( SPACE );
                }
            }
        return sb.toString();
        }
    /**
     * Getter for environment variables in form "key=value"
     * To be overwritten in derived class if environment variables are needed
     * @return String array of "key=value" pairs.
     */
    protected String[] getEnvironmentVariables()
        {
        return null;
        }

    /**
     * Returns success line that is excepted in output
     * @return Success line
     */
    protected String getSuccesIndicationLine()
        {
        return DEFAULT_SUCCESS_LINE;
        }

    /**
     * Cancels the executing conversion operation
     */
    public void cancelConversion()
        {
        if( iProcess != null )
            {
            iProcess.destroy();
            }
        }

    /**
     * Converts one ore more files to target file
     * @param aFilenames Files to be converted
     * @param aTargetFile Target file
     * @throws IOException If IO error occurs or tool fails conversion
     */
    public void convertMedia( List aFilenames,
                              String aTargetFile ) throws IOException
        {
        ArrayList newFiles = new ArrayList();

        checkMedias( aFilenames, newFiles );
        Runtime rt = Runtime.getRuntime();
        iProcess = rt.exec( getExecParameters( aFilenames, aTargetFile ),
                                getEnvironmentVariables() );
        try
            {
            iProcess.waitFor();
            }
        catch ( InterruptedException e )
            {
            throw new IOException( "Conversion interrupted" );
            }

        if( iProcess.exitValue() != 0 )
            {
            InputStream input = null;
            BufferedReader in = null;
            StringBuffer sb = null;
            try
                {
                // reading the error logs
                input = iProcess.getErrorStream();
                in = new BufferedReader( new InputStreamReader( input ) );
                sb = new StringBuffer();
                String line = null;
                while ( ( line = in.readLine() ) != null )
                    {
                    sb.append( line );
                    sb.append( '\n' );
                    }
                }
            finally
                {
                if( input != null )
                    {
                    input.close();
                    }
                if( in != null )
                    {
                    in.close();
                    }
                }

            deleteTemporaryFiles( newFiles );
            throw new IOException( "Conversion failed with error code: " +
                                   iProcess.exitValue() +
                                   "\nError log: " + sb.toString() );
            }
        // read the output logs, and check that there is success indication (in case that tool does not
        // support sending error code)
        boolean success = false;
        String line = null;
        String lastLine = null;
        InputStream input = null;
        BufferedReader in = null;
        try
            {
            input = iProcess.getInputStream();
            in = new BufferedReader( new InputStreamReader( input ) );
            while ( ( line = in.readLine() ) != null )
                {
                if( line.equals( getSuccesIndicationLine() ) )
                    {
                    success = true;
                    break;
                    }
                lastLine = line;
                }
            }
        finally
            {
            if( input != null )
                {
                input.close();
                }
            if( in != null )
                {
                in.close();
                }
            }
        iProcess = null;
        // Delete temporary files
        deleteTemporaryFiles( newFiles );
        // did not found success line
        if( !success )
            {
            throw new IOException( "Running media converter failed: " + lastLine );
            }
        }

    /**
     * Delete temporary files
     * @param newFiles List of temporary files
     * @throws IOException If file deletion fails
     */
    protected void deleteTemporaryFiles( List aNewFiles ) throws IOException
        {
        for ( Iterator iterator = aNewFiles.iterator(); iterator.hasNext(); )
            {
            String filename = ( String ) iterator.next();
            File file = new File( filename );
            if( !file.delete() )
                {
                throw new IOException( "Temporary file deletion failed: " + filename );
                }
            }
        }

    /**
     * Checks that input medias does not contain illegal files and converts
     * other image formats to BMP
     * @param aFilenames List of files to be added in MBM file
     * @param aNewFiles List of created temporary files
     * @throws IOException thrown if some of encoders are missing, or some error in image reading/writing
     */
    protected void checkMedias( List aFilenames,
                                List aNewFiles ) throws IOException
        {
        // load BMP writer
        Iterator writers = ImageIO.getImageWritersByFormatName( BMP );
        if( !writers.hasNext() )
            {
            throw new IOException( "BMP encoder not found" );
            }
        ImageWriter bmpWriter = ( ImageWriter ) writers.next();

        ArrayList newNames = new ArrayList();
        // Go through all files and check if there is something else than BMP
        for ( Iterator iterator = aFilenames.iterator();
              iterator.hasNext(); )
            {
            String imageName = ( String ) iterator.next();
            ImageInputStream input = ImageIO.createImageInputStream(
                    new File( imageName ) );

            String destinationImage = null;
            try
                {
                Iterator readers = ImageIO.getImageReaders( input );
                if( !readers.hasNext() )
                    {
                    throw new IOException( "Unknown file" );
                    }
                ImageReader ir = ( ImageReader ) readers.next();
                //Convert file if it is not BMP
                destinationImage = imageName;
                if( !ir.getFormatName().equalsIgnoreCase( BMP ) )
                    {
                    // read original image
                    ir.setInput( input );
                    IIOImage image = ir.readAll( 0, null );
                    destinationImage = imageName.substring(
                            0, imageName.lastIndexOf( DOT ) + 1 ) + BMP;
                    File destFile = new File( destinationImage );
                    int index = 1;
                    // create unique name to not overwrite any existing files
                    while( destFile.exists() )
                        {
                        destinationImage = imageName.substring( 0,
                                           imageName.lastIndexOf( DOT ) )
                                           + index++ + DOT + BMP;
                        destFile = new File( destinationImage );
                        }
                    // Write image back in BMP format
                    ImageOutputStream output =
                            ImageIO.createImageOutputStream( destFile );
                    try
                        {
                        bmpWriter.setOutput( output );
                        bmpWriter.write( image );
                        }
                    finally
                        {
                        if( output != null )
                            {
                            output.close();
                            }
                        }
                    aNewFiles.add( destinationImage );
                    }
                }
            finally
                {
                if( input != null )
                    {
                    input.close();
                    }
                }

            newNames.add( destinationImage );
            }
        // change new names to list
        aFilenames.clear();
        aFilenames.addAll( newNames );
        }
    }