blob: 43ea91cb559bd35da220fa3576c02cb63dfb1bd1 [file] [log] [blame]
package org.apache.maven.doxia.module.rtf;
/*
* 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.
*/
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Vector;
/**
* A Windows MetaFile writer.
*
* @version $Id$
*/
class WMFWriter
{
/**
* See the libwmf library documentation
* (http://www.wvware.com/wmf_doc_index.html)
* for a description of WMF format.
*/
private static Record trailer = new Record( 0, null );
/**
* standard header fields
*/
private short fileType;
private short headerSize;
private short version;
private int fileSize;
private short numOfObjects;
private int maxRecordSize;
private short numOfParams;
private Vector records;
WMFWriter()
{
fileType = 2;
headerSize = 9;
version = 0x0300;
fileSize = headerSize + trailer.size();
numOfObjects = 0;
maxRecordSize = trailer.size();
numOfParams = 0;
records = new Vector();
}
void add( Record record )
{
records.addElement( record );
int size = record.size();
fileSize += size;
if ( size > maxRecordSize )
{
maxRecordSize = size;
}
}
int size()
{
return fileSize;
}
void write( String fileName )
throws IOException
{
BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream( fileName ) );
write( out );
out.flush();
out.close();
}
void write( OutputStream out )
throws IOException
{
write16( fileType, out );
write16( headerSize, out );
write16( version, out );
write32( fileSize, out );
write16( numOfObjects, out );
write32( maxRecordSize, out );
write16( numOfParams, out );
for ( int i = 0, n = records.size(); i < n; ++i )
{
Record record = (Record) records.elementAt( i );
record.write( out );
}
trailer.write( out );
}
/**
* Writes a 16-bit integer in little-endian format.
*/
static void write16( int word, OutputStream out )
throws IOException
{
out.write( word );
out.write( word >> 8 );
}
/**
* Writes a 32-bit integer in little-endian format.
*/
static void write32( int dword, OutputStream out )
throws IOException
{
out.write( dword );
out.write( dword >> 8 );
out.write( dword >> 16 );
out.write( dword >> 24 );
}
void print( Writer out )
throws IOException
{
print16( fileType, out );
print16( headerSize, out );
print16( version, out );
print32( fileSize, out );
print16( numOfObjects, out );
print32( maxRecordSize, out );
print16( numOfParams, out );
out.write( System.getProperty( "line.separator" ) );
for ( int i = 0, n = records.size(); i < n; ++i )
{
Record record = (Record) records.elementAt( i );
record.print( out );
}
trailer.print( out );
}
static void print16( int word, Writer out )
throws IOException
{
byte[] buf = new byte[2];
buf[0] = (byte) word;
buf[1] = (byte) ( word >> 8 );
print( buf, 0, 2, out );
}
static void print32( int dword, Writer out )
throws IOException
{
byte[] buf = new byte[4];
buf[0] = (byte) dword;
buf[1] = (byte) ( dword >> 8 );
buf[2] = (byte) ( dword >> 16 );
buf[3] = (byte) ( dword >> 24 );
print( buf, 0, 4, out );
}
static void print( byte[] buf, int off, int len, Writer out )
throws IOException
{
char[] cbuf = new char[2 * len];
for ( int i = off, j = 0, n = off + len; i < n; ++i )
{
int d = ( buf[i] >> 4 ) & 0x0f;
if ( d < 10 )
{
cbuf[j++] = (char) ( '0' + d );
}
else
{
cbuf[j++] = (char) ( 'a' + ( d - 10 ) );
}
d = buf[i] & 0x0f;
if ( d < 10 )
{
cbuf[j++] = (char) ( '0' + d );
}
else
{
cbuf[j++] = (char) ( 'a' + ( d - 10 ) );
}
}
out.write( cbuf );
}
static void print( byte[] buf, int off, int len, Writer out, int lw )
throws IOException
{
String ls = System.getProperty( "line.separator" );
for ( int i = off; len > 0; )
{
int n = Math.min( len, lw / 2 );
print( buf, i, n, out );
out.write( ls );
len -= n;
i += n;
}
}
/**
* Standard data record.
*/
static class Record
{
protected int size;
private short function;
private short[] parameters;
Record( int function, int[] parameters )
{
this.function = (short) function;
if ( parameters != null )
{
this.parameters = new short[parameters.length];
for ( int i = 0; i < parameters.length; ++i )
{
this.parameters[i] = (short) parameters[i];
}
}
size = 3 + ( parameters == null ? 0 : parameters.length );
}
int size()
{
return size;
}
void write( OutputStream out )
throws IOException
{
write32( size, out );
write16( function, out );
if ( parameters != null )
{
for ( int i = 0; i < parameters.length; ++i )
{
write16( parameters[i], out );
}
}
}
void print( Writer out )
throws IOException
{
print32( size, out );
print16( function, out );
if ( parameters != null )
{
for ( int i = 0; i < parameters.length; ++i )
{
print16( parameters[i], out );
}
}
}
}
/**
* DIB data structure.
*/
static class Dib
{
/**
* compression types
*/
static final int BI_RGB = 0;
static final int BI_RLE8 = 1;
static final int BI_RLE4 = 2;
static final int BI_BITFIELDS = 3;
/*
* information header fields
*/
final int biSize = 40; // header size
int biWidth; // image width
int biHeight; // image height
final short biPlanes = 1; // number of planes
short biBitCount; // number of bits per pixel
int biCompression; // compression type
int biSizeImage; // image data size
int biXPelsPerMeter; // horizontal resolution
int biYPelsPerMeter; // vertical resolution
int biClrUsed; // number of colors
int biClrImportant; // number of required colors
byte[] palette; // color palette
byte[] bitmap; // bitmap data
int size()
{
int size = biSize;
if ( palette != null )
{
size += palette.length;
}
if ( bitmap != null )
{
if ( biSizeImage != 0 )
{
size += biSizeImage;
}
else
{
size += bitmap.length;
}
}
return size / 2;
}
void write( OutputStream out )
throws IOException
{
write32( biSize, out );
write32( biWidth, out );
write32( biHeight, out );
write16( biPlanes, out );
write16( biBitCount, out );
write32( biCompression, out );
write32( biSizeImage, out );
write32( biXPelsPerMeter, out );
write32( biYPelsPerMeter, out );
write32( biClrUsed, out );
write32( biClrImportant, out );
if ( palette != null )
{
out.write( palette );
}
if ( bitmap != null )
{
if ( biSizeImage != 0 )
{
out.write( bitmap, 0, biSizeImage );
}
else
{
out.write( bitmap );
}
}
}
void print( Writer out )
throws IOException
{
String ls = System.getProperty( "line.separator" );
print32( biSize, out );
print32( biWidth, out );
print32( biHeight, out );
print16( biPlanes, out );
print16( biBitCount, out );
out.write( ls );
print32( biCompression, out );
print32( biSizeImage, out );
print32( biXPelsPerMeter, out );
print32( biYPelsPerMeter, out );
print32( biClrUsed, out );
print32( biClrImportant, out );
out.write( ls );
if ( palette != null )
{
WMFWriter.print( palette, 0, palette.length, out, 64 );
}
if ( bitmap != null )
{
int len = ( biSizeImage != 0 ) ? biSizeImage : bitmap.length;
WMFWriter.print( bitmap, 0, len, out, 76 );
}
}
static int rlEncode8( byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff )
{
int i1, i2, j, k, n;
int len;
for ( i1 = inOff, j = outOff, n = ( inOff + inLen ); i1 < n; )
{
for ( i2 = ( i1 + 1 ), len = 1; i2 < n; ++i2, ++len )
{
if ( inBuf[i2] != inBuf[i2 - 1] )
{
break;
}
}
if ( len > 1 )
{
while ( len > 255 )
{
outBuf[j++] = (byte) 255;
outBuf[j++] = inBuf[i1];
len -= 255;
}
if ( len > 0 )
{
outBuf[j++] = (byte) len;
outBuf[j++] = inBuf[i1];
}
i1 = i2;
continue;
}
for ( ++i2; i2 < n; ++i2, ++len )
{
if ( inBuf[i2] == inBuf[i2 - 1] )
{
break;
}
}
while ( len > 255 )
{
outBuf[j++] = 0;
outBuf[j++] = (byte) 255;
for ( k = 0; k < 255; ++k )
{
outBuf[j++] = inBuf[i1++];
}
outBuf[j++] = (byte) 0;
len -= 255;
}
if ( len > 2 )
{
outBuf[j++] = 0;
outBuf[j++] = (byte) len;
for ( k = 0; k < len; ++k )
{
outBuf[j++] = inBuf[i1++];
}
if ( len % 2 != 0 )
{
outBuf[j++] = 0;
}
}
else
{
while ( len > 0 )
{
outBuf[j++] = 1;
outBuf[j++] = inBuf[i1++];
len -= 1;
}
}
}
return j - outOff;
}
}
static class DibBitBltRecord
extends Record
{
/**
* parameter count
*/
static final int P_COUNT = 8;
/**
* parameter indexes
*/
static final int P_ROP_L = 0;
static final int P_ROP_H = 1;
static final int P_YSRC = 2;
static final int P_XSRC = 3;
static final int P_HEIGHT = 4;
static final int P_WIDTH = 5;
static final int P_YDST = 6;
static final int P_XDST = 7;
private Dib dib;
DibBitBltRecord( int[] parameters, Dib dib )
{
super( 0x0940, parameters );
size += dib.size();
this.dib = dib;
}
/** {@inheritDoc} */
void write( OutputStream out )
throws IOException
{
super.write( out );
dib.write( out );
}
/** {@inheritDoc} */
void print( Writer out )
throws IOException
{
super.print( out );
dib.print( out );
}
}
}