/* Copyright (C) 2009 Mobile Sorcery AB
This program is free software; you can redistribute it and/or modify it
under the terms of the Eclipse Public License v1.0.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse Public License v1.0 for
more details.
You should have received a copy of the Eclipse Public License v1.0 along
with this program. It is also available at http://www.eclipse.org/legal/epl-v10.html
*/
package com.mobilesorcery.sdk.builder.linux.deb;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
/**
* A singleton class which provides helper methods for building
* linux packages.
*
* @author Ali Mosavian
*/
public class BuilderUtil
{
private byte[] m_copyBuffer;
/**
* Private constructor
*
*/
private BuilderUtil ( )
{
m_copyBuffer= new byte[4*1024];
}
/**
* Calculates the combined size of a directory tree/structure
*
* @param i The tree to calculate for
*
* @throws IOException If there's an I/O error
*/
public long calcCombinedSize ( File i )
{
// Is it a file?
if ( i.isFile( ) == true )
return i.length( );
// It's a directory
long size = 0;
for ( File f : i.listFiles( ) )
size += calcCombinedSize( f );
return size;
}
/**
* Adds a directory structure to a gzipped tar.
*
* @param o The output file that the tar+gz will be written to
* @param i The directory to add
*
* @throws IOException If there's an I/O error
*/
public void tarGZipDirectory ( File o, File i )
throws IOException
{
FileOutputStream fos = new FileOutputStream( o );
GzipCompressorOutputStream gzos = new GzipCompressorOutputStream( fos );
TarArchiveOutputStream tos = new TarArchiveOutputStream( gzos );
// Recursivly add to tar
doAddFileToTar( tos, "./", i );
// Close
tos.close( );
gzos.close( );
fos.close( );
}
/**
* Recursivly add a directory structure to a tar output stream
*
* @param t Tar output stream
* @param r Relative path up to this point
* @param c Current file
*/
private void doAddFileToTar ( TarArchiveOutputStream t,
String r,
File c )
throws IOException
{
// Update relative path
r += (r.isEmpty( ) ? "" : (r.endsWith( "/") ? "" : "/")) + c.getName( );
// Is it a file?
if ( c.isFile( ) == true )
{
ArchiveEntry e = t.createArchiveEntry( c, r );
t.putArchiveEntry( e );
copyFileToOutputStream( t, c );
t.closeArchiveEntry( );
return;
}
// It's a directory
for ( File f : c.listFiles( ) )
doAddFileToTar( t, r, f );
}
/**
* Simple method for copying file bytes to output stream
*
* @param t
* @param f
*/
public void copyFileToOutputStream ( OutputStream t,
File f )
throws FileNotFoundException, IOException
{
int read;
int size = ( int )f.length( );
FileInputStream fis = new FileInputStream( f );
while ( size > 0 )
{
read = fis.read( m_copyBuffer, 0, Math.min( size, m_copyBuffer.length ) );
t.write( m_copyBuffer, 0, read );
size -= read;
}
}
/**
* Simple method for copying String bytes to output stream
*
* @param t
* @param s
*/
public void copyStringToOutputStream ( OutputStream t,
String s )
throws IOException
{
t.write( s.getBytes( ) );
}
/**
* Simple method for copying file bytes to output stream
*
* @param f File to output
* @param i Inputstream
* @param b Bytes to copy
*/
public void copyInputStreamToFile ( File f,
InputStream i,
long b )
throws FileNotFoundException, IOException
{
int written;
int size = (int)b;
FileOutputStream fos = new FileOutputStream( f );
while ( size > 0 )
{
written = i.read( m_copyBuffer, 0, Math.min( size, m_copyBuffer.length ) );
fos.write( m_copyBuffer, 0, written );
size -= written;
}
fos.close( );
}
/**
* Simple method for copying file bytes to output stream
*
* @param t
* @param f
*/
public void copyFile ( File o,
File i )
throws FileNotFoundException, IOException
{
int read;
int size = ( int )i.length( );
FileInputStream fis = new FileInputStream( i );
FileOutputStream fos = new FileOutputStream( o );
while ( size > 0 )
{
read = fis.read( m_copyBuffer, 0, Math.min( size, m_copyBuffer.length ) );
fos.write( m_copyBuffer, 0, read );
size -= read;
}
}
/**
* Adds a directory structure to a gzipped tar.
*
* @param o The output file that the tar+gz will be written to
* @param i The directory to add
*
* @throws IOException If there's an I/O error
*/
public void calcMD5Directory ( File o,
File i )
throws IOException,
NoSuchAlgorithmException
{
FileOutputStream fos;
StringBuilder sb = new StringBuilder( );
// Recursivly calculate md5 sums for directory structure
doAddFileToMD5Sums( sb, "", i );
// Write
fos = new FileOutputStream( o );
fos.write( sb.toString( ).getBytes( ) );
fos.close( );
}
/**
* Adds a directory structure to a gzipped tar.
*
* @param o The output file that the tar+gz will be written to
* @param i The directory to add
*
* @throws IOException If there's an I/O error
*/
private void doAddFileToMD5Sums ( StringBuilder o,
String r,
File c )
throws IOException,
FileNotFoundException,
NoSuchAlgorithmException
{
// Update relative path
r += (r.isEmpty( ) ? "" : (r.endsWith( "/") ? "" : "/")) + c.getName( );
// Is it a file?
if ( c.isFile( ) == true )
{
String md5 = calcFileMD5Sum( c );
o.append( md5 );
for ( int i = 0; i < 1+(32-md5.length( )); i++ )
o.append( " " );
o.append( r )
.append( "\n" );
return;
}
// It's a directory
for ( File f : c.listFiles( ) )
doAddFileToMD5Sums( o, r, f );
}
/**
* Calculates the md5 has for a file and returns the
* hash as a hex string
*
* @param f File to hash
* @return 128 bit hash in hex
*
* @throws NoSuchAlgorithmException
* @throws FileNotFoundException
* @throws IOException
*/
public String calcFileMD5Sum ( File f )
throws NoSuchAlgorithmException,
FileNotFoundException,
IOException
{
MessageDigest m = MessageDigest.getInstance( "MD5" );
FileInputStream fos = new FileInputStream( f );
// Hash file
int size = (int)f.length( );
while ( size > 0 )
{
int count = fos.read( m_copyBuffer );
m.update( m_copyBuffer, 0, count );
size -= count;
}
fos.close( );
BigInteger hash = new BigInteger( 1, m.digest( ) );
return hash.toString( 16 );
}
/**
* Returns singleton instance
* Note: Not thread safe
*
*/
private static BuilderUtil m_instance = null;
public static BuilderUtil getInstance ( )
{
if ( m_instance == null )
m_instance = new BuilderUtil( );
return m_instance;
}
}