View Javadoc

1   package org.apache.maven.doxia.module.rtf;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.BufferedOutputStream;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.io.OutputStream;
26  import java.io.Writer;
27  import java.util.Vector;
28  
29  /**
30   * A Windows MetaFile writer.
31   *
32   * @version $Id: WMFWriter.java 638290 2008-03-18 09:45:22Z bentmann $
33   */
34  class WMFWriter
35  {
36      /**
37       * See the libwmf library documentation
38       * (http://www.wvware.com/wmf_doc_index.html)
39       * for a description of WMF format.
40       */
41      private static Record trailer = new Record( 0, null );
42  
43      /**
44       * standard header fields
45       */
46      private short fileType;
47  
48      private short headerSize;
49  
50      private short version;
51  
52      private int fileSize;
53  
54      private short numOfObjects;
55  
56      private int maxRecordSize;
57  
58      private short numOfParams;
59  
60      private Vector records;
61  
62      WMFWriter()
63      {
64          fileType = 2;
65          headerSize = 9;
66          version = 0x0300;
67          fileSize = headerSize + trailer.size();
68          numOfObjects = 0;
69          maxRecordSize = trailer.size();
70          numOfParams = 0;
71  
72          records = new Vector();
73      }
74  
75      void add( Record record )
76      {
77          records.addElement( record );
78  
79          int size = record.size();
80          fileSize += size;
81          if ( size > maxRecordSize )
82          {
83              maxRecordSize = size;
84          }
85      }
86  
87      int size()
88      {
89          return fileSize;
90      }
91  
92      void write( String fileName )
93          throws IOException
94      {
95          BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream( fileName ) );
96          write( out );
97          out.flush();
98          out.close();
99      }
100 
101     void write( OutputStream out )
102         throws IOException
103     {
104         write16( fileType, out );
105         write16( headerSize, out );
106         write16( version, out );
107         write32( fileSize, out );
108         write16( numOfObjects, out );
109         write32( maxRecordSize, out );
110         write16( numOfParams, out );
111 
112         for ( int i = 0, n = records.size(); i < n; ++i )
113         {
114             Record record = (Record) records.elementAt( i );
115             record.write( out );
116         }
117 
118         trailer.write( out );
119     }
120 
121     /**
122      * Writes a 16-bit integer in little-endian format.
123      */
124     static void write16( int word, OutputStream out )
125         throws IOException
126     {
127         out.write( word );
128         out.write( word >> 8 );
129     }
130 
131     /**
132      * Writes a 32-bit integer in little-endian format.
133      */
134     static void write32( int dword, OutputStream out )
135         throws IOException
136     {
137         out.write( dword );
138         out.write( dword >> 8 );
139         out.write( dword >> 16 );
140         out.write( dword >> 24 );
141     }
142 
143     void print( Writer out )
144         throws IOException
145     {
146         print16( fileType, out );
147         print16( headerSize, out );
148         print16( version, out );
149         print32( fileSize, out );
150         print16( numOfObjects, out );
151         print32( maxRecordSize, out );
152         print16( numOfParams, out );
153         out.write( System.getProperty( "line.separator" ) );
154 
155         for ( int i = 0, n = records.size(); i < n; ++i )
156         {
157             Record record = (Record) records.elementAt( i );
158             record.print( out );
159         }
160 
161         trailer.print( out );
162     }
163 
164     static void print16( int word, Writer out )
165         throws IOException
166     {
167         byte[] buf = new byte[2];
168         buf[0] = (byte) word;
169         buf[1] = (byte) ( word >> 8 );
170         print( buf, 0, 2, out );
171     }
172 
173     static void print32( int dword, Writer out )
174         throws IOException
175     {
176         byte[] buf = new byte[4];
177         buf[0] = (byte) dword;
178         buf[1] = (byte) ( dword >> 8 );
179         buf[2] = (byte) ( dword >> 16 );
180         buf[3] = (byte) ( dword >> 24 );
181         print( buf, 0, 4, out );
182     }
183 
184     static void print( byte[] buf, int off, int len, Writer out )
185         throws IOException
186     {
187         char[] cbuf = new char[2 * len];
188 
189         for ( int i = off, j = 0, n = off + len; i < n; ++i )
190         {
191             int d = ( buf[i] >> 4 ) & 0x0f;
192             if ( d < 10 )
193             {
194                 cbuf[j++] = (char) ( '0' + d );
195             }
196             else
197             {
198                 cbuf[j++] = (char) ( 'a' + ( d - 10 ) );
199             }
200             d = buf[i] & 0x0f;
201             if ( d < 10 )
202             {
203                 cbuf[j++] = (char) ( '0' + d );
204             }
205             else
206             {
207                 cbuf[j++] = (char) ( 'a' + ( d - 10 ) );
208             }
209         }
210 
211         out.write( cbuf );
212     }
213 
214     static void print( byte[] buf, int off, int len, Writer out, int lw )
215         throws IOException
216     {
217         String ls = System.getProperty( "line.separator" );
218         for ( int i = off; len > 0; )
219         {
220             int n = Math.min( len, lw / 2 );
221             print( buf, i, n, out );
222             out.write( ls );
223             len -= n;
224             i += n;
225         }
226     }
227 
228     /**
229      * Standard data record.
230      */
231     static class Record
232     {
233         protected int size;
234 
235         private short function;
236 
237         private short[] parameters;
238 
239         Record( int function, int[] parameters )
240         {
241             this.function = (short) function;
242             if ( parameters != null )
243             {
244                 this.parameters = new short[parameters.length];
245                 for ( int i = 0; i < parameters.length; ++i )
246                 {
247                     this.parameters[i] = (short) parameters[i];
248                 }
249             }
250             size = 3 + ( parameters == null ? 0 : parameters.length );
251         }
252 
253         int size()
254         {
255             return size;
256         }
257 
258         void write( OutputStream out )
259             throws IOException
260         {
261             write32( size, out );
262             write16( function, out );
263             if ( parameters != null )
264             {
265                 for ( int i = 0; i < parameters.length; ++i )
266                 {
267                     write16( parameters[i], out );
268                 }
269             }
270         }
271 
272         void print( Writer out )
273             throws IOException
274         {
275             print32( size, out );
276             print16( function, out );
277             if ( parameters != null )
278             {
279                 for ( int i = 0; i < parameters.length; ++i )
280                 {
281                     print16( parameters[i], out );
282                 }
283             }
284         }
285 
286     }
287 
288     /**
289      * DIB data structure.
290      */
291     static class Dib
292     {
293         /**
294          * compression types
295          */
296         static final int BI_RGB = 0;
297 
298         static final int BI_RLE8 = 1;
299 
300         static final int BI_RLE4 = 2;
301 
302         static final int BI_BITFIELDS = 3;
303 
304         /*
305          * information header fields
306          */
307         final int biSize = 40;        // header size
308 
309         int biWidth;            // image width
310 
311         int biHeight;            // image height
312 
313         final short biPlanes = 1;    // number of planes
314 
315         short biBitCount;        // number of bits per pixel
316 
317         int biCompression;        // compression type
318 
319         int biSizeImage;            // image data size
320 
321         int biXPelsPerMeter;        // horizontal resolution
322 
323         int biYPelsPerMeter;        // vertical resolution
324 
325         int biClrUsed;            // number of colors
326 
327         int biClrImportant;        // number of required colors
328 
329         byte[] palette;            // color palette
330 
331         byte[] bitmap;            // bitmap data
332 
333         int size()
334         {
335             int size = biSize;
336             if ( palette != null )
337             {
338                 size += palette.length;
339             }
340             if ( bitmap != null )
341             {
342                 if ( biSizeImage != 0 )
343                 {
344                     size += biSizeImage;
345                 }
346                 else
347                 {
348                     size += bitmap.length;
349                 }
350             }
351             return size / 2;
352         }
353 
354         void write( OutputStream out )
355             throws IOException
356         {
357             write32( biSize, out );
358             write32( biWidth, out );
359             write32( biHeight, out );
360             write16( biPlanes, out );
361             write16( biBitCount, out );
362             write32( biCompression, out );
363             write32( biSizeImage, out );
364             write32( biXPelsPerMeter, out );
365             write32( biYPelsPerMeter, out );
366             write32( biClrUsed, out );
367             write32( biClrImportant, out );
368             if ( palette != null )
369             {
370                 out.write( palette );
371             }
372             if ( bitmap != null )
373             {
374                 if ( biSizeImage != 0 )
375                 {
376                     out.write( bitmap, 0, biSizeImage );
377                 }
378                 else
379                 {
380                     out.write( bitmap );
381                 }
382             }
383         }
384 
385         void print( Writer out )
386             throws IOException
387         {
388             String ls = System.getProperty( "line.separator" );
389 
390             print32( biSize, out );
391             print32( biWidth, out );
392             print32( biHeight, out );
393             print16( biPlanes, out );
394             print16( biBitCount, out );
395             out.write( ls );
396 
397             print32( biCompression, out );
398             print32( biSizeImage, out );
399             print32( biXPelsPerMeter, out );
400             print32( biYPelsPerMeter, out );
401             print32( biClrUsed, out );
402             print32( biClrImportant, out );
403             out.write( ls );
404 
405             if ( palette != null )
406             {
407                 WMFWriter.print( palette, 0, palette.length, out, 64 );
408             }
409 
410             if ( bitmap != null )
411             {
412                 int len = ( biSizeImage != 0 ) ? biSizeImage : bitmap.length;
413                 WMFWriter.print( bitmap, 0, len, out, 76 );
414             }
415         }
416 
417         static int rlEncode8( byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff )
418         {
419             int i1, i2, j, k, n;
420             int len;
421 
422             for ( i1 = inOff, j = outOff, n = ( inOff + inLen ); i1 < n; )
423             {
424                 for ( i2 = ( i1 + 1 ), len = 1; i2 < n; ++i2, ++len )
425                 {
426                     if ( inBuf[i2] != inBuf[i2 - 1] )
427                     {
428                         break;
429                     }
430                 }
431 
432                 if ( len > 1 )
433                 {
434                     while ( len > 255 )
435                     {
436                         outBuf[j++] = (byte) 255;
437                         outBuf[j++] = inBuf[i1];
438                         len -= 255;
439                     }
440                     if ( len > 0 )
441                     {
442                         outBuf[j++] = (byte) len;
443                         outBuf[j++] = inBuf[i1];
444                     }
445                     i1 = i2;
446                     continue;
447                 }
448 
449                 for ( ++i2; i2 < n; ++i2, ++len )
450                 {
451                     if ( inBuf[i2] == inBuf[i2 - 1] )
452                     {
453                         break;
454                     }
455                 }
456 
457                 while ( len > 255 )
458                 {
459                     outBuf[j++] = 0;
460                     outBuf[j++] = (byte) 255;
461                     for ( k = 0; k < 255; ++k )
462                     {
463                         outBuf[j++] = inBuf[i1++];
464                     }
465                     outBuf[j++] = (byte) 0;
466                     len -= 255;
467                 }
468 
469                 if ( len > 2 )
470                 {
471                     outBuf[j++] = 0;
472                     outBuf[j++] = (byte) len;
473                     for ( k = 0; k < len; ++k )
474                     {
475                         outBuf[j++] = inBuf[i1++];
476                     }
477                     if ( len % 2 != 0 )
478                     {
479                         outBuf[j++] = 0;
480                     }
481                 }
482                 else
483                 {
484                     while ( len > 0 )
485                     {
486                         outBuf[j++] = 1;
487                         outBuf[j++] = inBuf[i1++];
488                         len -= 1;
489                     }
490                 }
491             }
492 
493             return j - outOff;
494         }
495     }
496 
497     static class DibBitBltRecord
498         extends Record
499     {
500         /**
501          * parameter count
502          */
503         static final int P_COUNT = 8;
504 
505         /**
506          * parameter indexes
507          */
508         static final int P_ROP_L = 0;
509 
510         static final int P_ROP_H = 1;
511 
512         static final int P_YSRC = 2;
513 
514         static final int P_XSRC = 3;
515 
516         static final int P_HEIGHT = 4;
517 
518         static final int P_WIDTH = 5;
519 
520         static final int P_YDST = 6;
521 
522         static final int P_XDST = 7;
523 
524         private Dib dib;
525 
526         DibBitBltRecord( int[] parameters, Dib dib )
527         {
528             super( 0x0940, parameters );
529             size += dib.size();
530             this.dib = dib;
531         }
532 
533         /** {@inheritDoc} */
534         void write( OutputStream out )
535             throws IOException
536         {
537             super.write( out );
538             dib.write( out );
539         }
540 
541         /** {@inheritDoc} */
542         void print( Writer out )
543             throws IOException
544         {
545             super.print( out );
546             dib.print( out );
547         }
548     }
549 }