Package org.apache.portals.gems.flash

Source Code of org.apache.portals.gems.flash.SWFHeader

/**
* SWFHeader is (c) 2006 Paul Brooks Andrus and is released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
* http://www.brooksandrus.com/blog/2006/08/01/lightweight-swf-header-reader-java/
* com.brooksandrus.utils.swf
*
* Modified to efficiently read only the swf header (Steve Milek)
*
*/
package org.apache.portals.gems.flash;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* @author brooks
*
*/
public class SWFHeader
{
    protected Logger log = LoggerFactory.getLogger( SWFHeader.class );
    public static final String COMPRESSED   = "compressed";
    public static final String UNCOMPRESSED = "uncompressed";
   
    private String       signature;
    private String       compressionType;
    private int          version;
    private long         size;
    private int          nbits;
    private int          xmax;
    private int          ymax;
    private int          width;
    private int          height;
    private int          frameRate;
    private int          frameCount;

    public SWFHeader()
    {
        super();
    }  
  
    public boolean parseHeader( String fileName )
    {
        if ( fileName == null )
        {
            log.error( "Name for SWF file is null" );
            return false;
        }
        return manageInputStreamAndParseHeader( null, new File( fileName ) );
    }
  
    public boolean parseHeader( File file )
    {
        return manageInputStreamAndParseHeader( null, file );
    }
  
    public boolean parseHeader( InputStream is )
    {
        return manageInputStreamAndParseHeader( is, null );
    }
  
    private boolean manageInputStreamAndParseHeader( InputStream is, File file )
    {
        boolean inputIsSWF = false;
        try
        {
            if ( is == null && file != null )
            {
                is = new FileInputStream( file );
            }
            inputIsSWF = doParseHeader( is );
        }
        catch ( FileNotFoundException fnfEx )
        {
            log.error( "SWF file could not be found", fnfEx );
            inputIsSWF = false;
        }
        catch ( Exception e )
        {
            log.error( "Failed to parse SWF input", e );
            inputIsSWF = false;
        }
        finally
        {
            try
            {
                if ( is != null )
                {
                    is.close();
                }
            }
            catch ( Exception ex )
            {
                log.error( "Failed to close SWF InputStream", ex );
                inputIsSWF = false;
            }
        }
        return inputIsSWF;
    }
 
    private boolean doParseHeader( InputStream is ) throws Exception
    {
        byte[] temp = new byte[128];   // header is 47 bytes - we must read more in case compression is used (see uncompressHeader comments)
       
        byte[] swf = null;

        is.read( temp );

        if ( !isSWF( temp ) )
        {
            log.error( "Input does not match SWF format - incorrect file signature" );
            return false;
        }
        else
        {
            signature = "" + ( char ) temp[0] + ( char ) temp[1]
                + ( char ) temp[2];
        }

        if ( isCompressed( temp[0] ) )
        {
            swf = uncompressHeader( temp );
            compressionType = SWFHeader.COMPRESSED;
        }
        else
        {
            swf = temp;
            compressionType = SWFHeader.UNCOMPRESSED;
        }

        //System.out.println( "swf byte array length: " + swf.length );
      
        // version is the 4th byte of a swf;
        version = swf[3];

        // bytes 5 - 8 represent the size in bytes of a swf
        size = readSize( swf );

        // Stage dimensions are stored in a rect

        nbits = ( ( swf[8] & 0xff ) >> 3 );

        PackedBitObj pbo = readPackedBits( swf, 8, 5, nbits );
      
        PackedBitObj pbo2 = readPackedBits( swf, pbo.nextByteIndex,
                                            pbo.nextBitIndex, nbits );

        PackedBitObj pbo3 = readPackedBits( swf, pbo2.nextByteIndex,
                                            pbo2.nextBitIndex, nbits );

        PackedBitObj pbo4 = readPackedBits( swf, pbo3.nextByteIndex,
                                            pbo3.nextBitIndex, nbits );

        xmax = pbo2.value;
        ymax = pbo4.value;

        width = convertTwipsToPixels( xmax );
        height = convertTwipsToPixels( ymax );

        int bytePointer = pbo4.nextByteIndex + 2;

        frameRate = swf[bytePointer];
        bytePointer++;
      
      
        int fc1 = swf[bytePointer] & 0xFF;
        bytePointer++;
      
        int fc2 = swf[bytePointer] & 0xFF;
        bytePointer++;
      
        frameCount = ( fc2 << 8 ) + fc1;
      
        dumpHeaderToStdOut();

        return true;
    }

    public void read( byte[] output, byte[] input, int offset )
    {
        System.arraycopy( input, offset, output, 0, output.length - offset );
    }

    public PackedBitObj readPackedBits( byte[] bytes, int byteMarker,
                                        int bitMarker, int length )
    {
        int total = 0;
        int shift = 7 - bitMarker;
        int counter = 0;
        int bitIndex = bitMarker;
        int byteIndex = byteMarker;
     
        while ( counter < length )
        {
            for ( int i = bitMarker; i < 8; i++ )
            {
                int bit = ( ( bytes[byteMarker] & 0xff ) >> shift ) & 1;
                total = ( total << 1 ) + bit;
                bitIndex = i;
                shift--;
                counter++;
           
                if ( counter == length )
                {
                    break;
                }
            }
            byteIndex = byteMarker;
            byteMarker++;
            bitMarker = 0;
            shift = 7;
        }
        return new PackedBitObj( bitIndex, byteIndex, total );
    }

    public int convertTwipsToPixels( int twips )
    {
        return twips / 20;
    }

    public int convertPixelsToTwips( int pixels )
    {
        return pixels * 20;
    }

    public boolean isSWF( byte[] signature )
    {
        String sig = "" + ( char ) signature[0] + ( char ) signature[1]
            + ( char ) signature[2];

        if ( sig.equals( "FWS" ) || sig.equals( "CWS" ) )
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public boolean isCompressed( int firstByte )
    {
        if ( firstByte == 67 )
        {
            return true;
        }
        else
        {
            return false;
        }
    }
  
    public boolean isCompressed()
    {
        boolean result = false;
        if ( signature.equalsIgnoreCase( "CWS" ) )
        {
            result = true;
        }
        return result;
    }

    // Inflator class will be upset if we let it read to the end of input and it discovers that
    // the zip format is not properly terminated - therefore, we must provide Inflater with more input
    // than what we intend to inflate
    protected byte[] uncompressHeader( byte[] bytes ) throws DataFormatException
   
        Inflater decompressor = new Inflater();
        byte[] compressed = strip( bytes );
        decompressor.setInput( compressed );   // feed the Inflater the bytes
        byte[] buffer = new byte[ 56 ];
        int count = decompressor.inflate( buffer );   // decompress the data into the buffer
        decompressor.end();
       
        //create an array to hold the header and body bytes
        byte[] swf = new byte[ 8 + count ];
        //copy the first 8 bytes which are uncompressed into the swf array
        System.arraycopy( bytes, 0, swf, 0, 8 );
        //copy the uncompressed data into the swf array
        System.arraycopy( buffer, 0, swf, 8, count );
        //the first byte of the swf indicates whether the swf is compressed or not
        swf[0] = 70;
     
        return swf;
    }

    // This version of uncompressHeader may be safer (because it uses InflaterInputStream),
    // but until there is some evidence of this we will stick with the direct approach of
    // using Inflater (above).
    /*
      protected byte[] uncompressHeader( byte[] headerBytes ) throws IOException
      {
      byte[] compressed = strip( headerBytes );
      InflaterInputStream iis = new InflaterInputStream( new ByteArrayInputStream( compressed ) );
      byte[] buffer = new byte[56];
      int bytesRead = iis.read( buffer, 0, buffer.length );
      iis.close();

      byte[] swfHeader = new byte[ 8 + bytesRead ];
       
      // copy the first 8 bytes which are uncompressed into the swf array
      System.arraycopy( headerBytes, 0, swfHeader, 0, 8 );
       
      // copy the uncompressed data into the swf array
      System.arraycopy( buffer, 0, swfHeader, 8, bytesRead );
       
      // the first byte of the swf indicates whether the swf is compressed or not
      swfHeader[0] = 70;
       
      return swfHeader;
      }
    */

    public int readSize( byte[] bytes )
    {
        int s = 0;
        for ( int i = 0; i < 4; i++ )
        {
            s = ( s << 8 ) + bytes[i + 4];
        }

        // We can use Integer.reverseBytes(int) in Java 1.5+.
        //s = Integer.reverseBytes( s ) - 1;
        s = (((s >>> 24)           ) |
            ((s >>   8) &   0xFF00) |
            ((s <<   8) & 0xFF0000) |
            ((s << 24))) - 1;

        return s;
    }
   
    public byte[] strip( byte[] bytes )
    {
        byte[] compressable = new byte[bytes.length - 8];
        System.arraycopy( bytes, 8, compressable, 0, bytes.length - 8 );//fills a byte array with data needing decompression
        return compressable;
    }

   
    /**
     * @param args
     */
    public static void main( String[] args )
    {
        if ( args.length != 1 )
        {
            System.err.println( "usage: swf_file" );
        }
        else
        {
            try
            {
                SWFHeader swfH = new SWFHeader();
                if ( swfH.parseHeader( args[0] ) )
                {
                    swfH.dumpHeaderToStdOut();
                }
            }
            catch ( Exception e )
            {
                System.err.println( e.getMessage() );
            }
        }
       
    }

    public void dumpHeaderToStdOut()
    {
        System.out.println( "signature:   " + getSignature() );
        System.out.println( "version:     " + getVersion() );
        System.out.println( "compression: " + getCompressionType() );
        System.out.println( "size:        " + getSize() );
        System.out.println( "nbits:       " + getNbits() );
        System.out.println( "xmax:        " + getXmax() );
        System.out.println( "ymax:        " + getYmax() );
        System.out.println( "width:       " + getWidth() );
        System.out.println( "height:      " + getHeight() );
        System.out.println( "frameRate:   " + getFrameRate() );
        System.out.println( "frameCount:  " + getFrameCount() );
    }

    /**
     * @return the frameCount
     */
    public int getFrameCount()
    {
        return frameCount;
    }

    /**
     * @return the frameRate
     */
    public int getFrameRate()
    {
        return frameRate;
    }

    /**
     * @return the nbits
     */
    public int getNbits()
    {
        return nbits;
    }

    /**
     * @return the signature
     */
    public String getSignature()
    {
        return signature;
    }

    /**
     * @return the size
     */
    public long getSize()
    {
        return size;
    }

    /**
     * @return the version
     */
    public int getVersion()
    {
        return version;
    }

    /**
     * @return the xmax
     */
    public int getXmax()
    {
        return xmax;
    }

    /**
     * @return the ymax
     */
    public int getYmax()
    {
        return ymax;
    }

    /**
     * @return the compressionType
     */
    public String getCompressionType()
    {
        return compressionType;
    }

    /**
     * @return the height
     */
    public int getHeight()
    {
        return height;
    }

    /**
     * @return the width
     */
    public int getWidth()
    {
        return width;
    }

}
TOP

Related Classes of org.apache.portals.gems.flash.SWFHeader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.