Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/anotherbigidea/flash/readers/TagParser.java


1   /****************************************************************
2    * Copyright (c) 2001, David N. Main, All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or
5    * without modification, are permitted provided that the 
6    * following conditions are met:
7    *
8    * 1. Redistributions of source code must retain the above 
9    * copyright notice, this list of conditions and the following 
10   * disclaimer. 
11   * 
12   * 2. Redistributions in binary form must reproduce the above 
13   * copyright notice, this list of conditions and the following 
14   * disclaimer in the documentation and/or other materials 
15   * provided with the distribution.
16   * 
17   * 3. The name of the author may not be used to endorse or 
18   * promote products derived from this software without specific 
19   * prior written permission. 
20   * 
21   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 
22   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
23   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
24   * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
25   * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
27   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
28   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
29   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
30   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
31   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
32   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33   ****************************************************************/
34  package com.anotherbigidea.flash.readers;
35  
36  import java.io.*;
37  import java.util.*;
38  import java.util.zip.*;
39  import com.anotherbigidea.flash.interfaces.*;
40  import com.anotherbigidea.flash.*;
41  import com.anotherbigidea.flash.structs.*;
42  import com.anotherbigidea.io.*;
43  import com.anotherbigidea.flash.writers.*;
44  
45  /**
46   * Parse Tags and drive a SWFTagTypes interface.
47   */
48  public class TagParser implements SWFTags, SWFConstants, SWFFileSignature 
49  {
50    protected String mStringEncoding = SWFConstants.STRING_ENCODING_MX;
51    protected int mFlashVersion = SWFConstants.FLASH_MX_VERSION;
52    
53      protected SWFTagTypes mTagtypes;
54      //protected byte[] contents;  //for debugging
55      
56      public TagParser( SWFTagTypes tagtypes )
57      {
58          mTagtypes = tagtypes;
59      }    
60      
61      /**
62       * @see SWFFileSignature#signature(String)
63       */
64      public void signature( String sig ) {
65        if( mTagtypes instanceof SWFFileSignature ) {
66          ((SWFFileSignature) mTagtypes).signature( sig );
67        }
68      }
69      
70      /**
71       * Interface SWFTags
72       */
73      public void header( int version, long length,
74                          int twipsWidth, int twipsHeight,
75                          int frameRate, int frameCount ) throws IOException
76      {
77          mTagtypes.header( version, length, 
78                           twipsWidth, twipsHeight, 
79                           frameRate, frameCount );
80                           
81          //revert to old encoding for pre-MX
82          if( version < SWFConstants.FLASH_MX_VERSION ) {
83            mStringEncoding = SWFConstants.STRING_ENCODING_PRE_MX;
84          }
85          
86          mFlashVersion = version;
87      }
88      
89      /**
90       * Interface SWFTags
91      
92      public void tag( int tagType, boolean longTag, byte[] contents ) 
93          throws IOException
94      {
95          //this.contents = contents; //for debugging
96          
97          int length = ( contents != null ) ? contents.length : 0;
98          
99          InStream in = ( length > 0 ) ? new InStream( contents ) : null;
100         
101         //System.out.println( "IN  Tag " + tagType + " " + longTag + " " + length );
102         
103         switch( tagType )
104         {
105             case TAG_END:       tagtypes.tagEnd(); break;
106             case TAG_SHOWFRAME: tagtypes.tagShowFrame(); break;
107                                 
108             //case TAG_DEFINESHAPE : 
109             //case TAG_DEFINESHAPE2: 
110             //case TAG_DEFINESHAPE3: parseDefineShape( tagType, in ); break;
111                                    
112             case TAG_DOACTION      : parseDoAction( in ); break;
113             //case TAG_FREECHARACTER : tagtypes.tagFreeCharacter( in.readUI16() ); break;
114             //case TAG_PLACEOBJECT   : parsePlaceObject( in, length ); break;
115             case TAG_PLACEOBJECT2  : parsePlaceObject2( in ); break;
116             //case TAG_REMOVEOBJECT  : tagtypes.tagRemoveObject( in.readUI16(), in.readUI16() ); break;
117             //case TAG_REMOVEOBJECT2 : tagtypes.tagRemoveObject2( in.readUI16() ); break;
118             //case TAG_SETBACKGROUNDCOLOR : tagtypes.tagSetBackgroundColor( new Color(in) ); break;              
119             //case TAG_FRAMELABEL    : tagtypes.tagFrameLabel( in.readString() ); break;              
120             case TAG_DEFINESPRITE  : parseDefineSprite( in ); break;
121             //case TAG_PROTECT       : tagtypes.tagProtect( (length>0) ? in.read(length) : null ); break;
122             //case TAG_ENABLEDEBUG   : tagtypes.tagEnableDebug( (length>0) ? in.read(length) : null ); break;
123             //case TAG_DEFINEFONT    : parseDefineFont( in ); break;
124             //case TAG_DEFINEFONTINFO: parseFontInfo( in, length ); break;
125             //case TAG_DEFINEFONT2   : parseDefineFont2( in ); break;
126             //case TAG_DEFINETEXTFIELD: parseDefineTextField( in ); break;
127                                       
128             //case TAG_DEFINETEXT    : 
129             //case TAG_DEFINETEXT2   : parseDefineText( tagType, in ); break;
130 
131             case TAG_DEFINEBUTTON  : parseDefineButton( in ); break;
132             case TAG_DEFINEBUTTON2 : parseDefineButton2( in ); break;
133             //case TAG_DEFINEBUTTONCXFORM : parseButtonCXForm( in ); break;
134 
135             //case TAG_EXPORT : parseExport( in ); break;
136             //case TAG_IMPORT : parseImport( in ); break;
137 
138             //case TAG_DEFINEQUICKTIMEMOVIE : tagtypes.tagDefineQuickTimeMovie( in.readUI16(), in.readString() ); break;
139                                             
140             //case TAG_DEFINEBITSJPEG2     : parseDefineJPEG2( in, length ); break;
141             //case TAG_DEFINEBITSLOSSLESS  : parseDefineBitsLossless( in, length, false ); break;
142             //case TAG_DEFINEBITSLOSSLESS2 : parseDefineBitsLossless( in, length, true  ); break;
143                                        
144             //case TAG_DEFINEMORPHSHAPE : parseMorphShape( in ); break;
145                                         
146             //case TAG_NAMECHARACTER:     tagtypes.tagNameCharacter   ( contents ); break;
147             //case TAG_GENERATOR_TEXT:    tagtypes.tagGeneratorText   ( contents ); break;
148             //case TAG_TEMPLATECOMMAND:   tagtypes.tagGeneratorCommand( contents ); break;
149             //case TAG_FLASHGENERATOR:    tagtypes.tagGenerator       ( contents ); break;
150             //case TAG_GEN_EXTERNAL_FONT: tagtypes.tagGeneratorFont   ( contents ); break;
151             //case TAG_SERIALNUMBER:      tagtypes.tagSerialNumber( in.readString() ); break;                                        
152                                         
153             //case TAG_DEFINESOUND:       parseDefineSound( in ); break;
154             //case TAG_STARTSOUND:        parseStartSound( in ); break;
155             //case TAG_DEFINEBUTTONSOUND: parseDefineButtonSound( in ); break;
156             //case TAG_SOUNDSTREAMHEAD:   parseSoundStreamHead( true, in ); break;
157             //case TAG_SOUNDSTREAMHEAD2:  parseSoundStreamHead( false, in ); break;
158             //case TAG_SOUNDSTREAMBLOCK:  parseSoundStreamBlock( in ); break;
159                                         
160             //case TAG_DEFINEBITS:      parseDefineBits( in ); break;
161             //case TAG_JPEGTABLES:      parseDefineJPEGTables( in ); break;
162             //case TAG_DEFINEBITSJPEG3: parseDefineBitsJPEG3( in ); break;
163     
164             default: //--Unknown Tag Type
165                 tagtypes.tag( tagType, longTag, contents );
166                 break;
167         }                
168     } */
169     
170     /**
171      * Interface SWFTags
172      */
173     public void tag( int tagType, boolean longTag, byte[] contents ) 
174         throws IOException
175     {
176         //this.contents = contents; //for debugging
177         
178         int length = ( contents != null ) ? contents.length : 0;
179         
180         InStream in = ( length > 0 ) ? new InStream( contents ) : null;
181         
182         //System.out.println( "IN  Tag " + tagType + " " + longTag + " " + length );
183         
184         switch( tagType )
185         {
186             case TAG_END:       mTagtypes.tagEnd(); break;
187             case TAG_SHOWFRAME: mTagtypes.tagShowFrame(); break;
188                                 
189             case TAG_DEFINESHAPE : 
190             case TAG_DEFINESHAPE2: 
191             case TAG_DEFINESHAPE3: parseDefineShape( tagType, in ); break;
192                                    
193             case TAG_DOACTION      : parseDoAction( in ); break;
194       case TAG_DOINITACTION  : parseDoInitAction( in ); break;
195             case TAG_FREECHARACTER : mTagtypes.tagFreeCharacter( in.readUI16() ); break;
196             case TAG_PLACEOBJECT   : parsePlaceObject( in, length ); break;
197             case TAG_PLACEOBJECT2  : parsePlaceObject2( in ); break;
198             case TAG_REMOVEOBJECT  : mTagtypes.tagRemoveObject( in.readUI16(), in.readUI16() ); break;
199             case TAG_REMOVEOBJECT2 : mTagtypes.tagRemoveObject2( in.readUI16() ); break;
200             case TAG_SETBACKGROUNDCOLOR : mTagtypes.tagSetBackgroundColor( new Color(in) ); break;              
201             case TAG_FRAMELABEL    : parseFrameLabel( in, contents ); break;              
202             case TAG_DEFINESPRITE  : parseDefineSprite( in ); break;
203             case TAG_PROTECT       : mTagtypes.tagProtect( (length>0) ? in.read(length) : null ); break;
204             case TAG_ENABLEDEBUG   : mTagtypes.tagEnableDebug( (length>0) ? in.read(length) : null ); break;
205             case TAG_DEFINEFONT    : parseDefineFont( in ); break;
206             case TAG_DEFINEFONTINFO: parseFontInfo( in, length, false ); break;
207       case TAG_DEFINEFONTINFO2: parseFontInfo( in, length, true ); break;
208             case TAG_DEFINEFONT2   : parseDefineFont2( in ); break;
209             case TAG_DEFINETEXTFIELD: parseDefineTextField( in ); break;
210                                       
211             case TAG_DEFINETEXT    : 
212             case TAG_DEFINETEXT2   : parseDefineText( tagType, in ); break;
213 
214             case TAG_DEFINEBUTTON  : parseDefineButton( in ); break;
215             case TAG_DEFINEBUTTON2 : parseDefineButton2( in ); break;
216             case TAG_DEFINEBUTTONCXFORM : parseButtonCXForm( in ); break;
217 
218             case TAG_EXPORT : parseExport( in ); break;
219             case TAG_IMPORT : parseImport( in ); break;
220 
221             case TAG_DEFINEQUICKTIMEMOVIE : mTagtypes.tagDefineQuickTimeMovie( in.readUI16(), in.readString( mStringEncoding ) ); break;
222                                             
223             case TAG_DEFINEBITSJPEG2     : parseDefineJPEG2( in, length ); break;
224             case TAG_DEFINEBITSLOSSLESS  : parseDefineBitsLossless( in, length, false ); break;
225             case TAG_DEFINEBITSLOSSLESS2 : parseDefineBitsLossless( in, length, true  ); break;
226                                        
227             case TAG_DEFINEMORPHSHAPE : parseMorphShape( in ); break;
228                                         
229             case TAG_NAMECHARACTER:     mTagtypes.tagNameCharacter   ( contents ); break;
230             case TAG_GENERATOR_TEXT:    mTagtypes.tagGeneratorText   ( contents ); break;
231             case TAG_TEMPLATECOMMAND:   mTagtypes.tagGeneratorCommand( contents ); break;
232             case TAG_FLASHGENERATOR:    mTagtypes.tagGenerator       ( contents ); break;
233             case TAG_GEN_EXTERNAL_FONT: mTagtypes.tagGeneratorFont   ( contents ); break;
234             case TAG_SERIALNUMBER:      mTagtypes.tagSerialNumber( in.readString( mStringEncoding ) ); break;                                        
235                                         
236             case TAG_DEFINESOUND:       parseDefineSound( in ); break;
237             case TAG_STARTSOUND:        parseStartSound( in ); break;
238             case TAG_DEFINEBUTTONSOUND: parseDefineButtonSound( in ); break;
239             case TAG_SOUNDSTREAMHEAD:   parseSoundStreamHead( true, in ); break;
240             case TAG_SOUNDSTREAMHEAD2:  parseSoundStreamHead( false, in ); break;
241             case TAG_SOUNDSTREAMBLOCK:  parseSoundStreamBlock( in ); break;
242                                         
243             case TAG_DEFINEBITS:      parseDefineBits( in ); break;
244             case TAG_JPEGTABLES:      parseDefineJPEGTables( in ); break;
245             case TAG_DEFINEBITSJPEG3: parseDefineBitsJPEG3( in ); break;
246 
247       case TAG_ENABLEDEBUGGER2 : parseEnableDebugger2( in, length ); break;
248     
249             default: //--Unknown Tag Type
250                 mTagtypes.tag( tagType, longTag, contents );
251                 break;
252         }                
253     }//*/
254 
255   protected void parseEnableDebugger2( InStream in, int length ) throws IOException {
256     int reserved = in.readUI16();
257     mTagtypes.tagEnableDebug2( (length>2) ? in.read(length-2) : null );    
258   }
259 
260   protected void parseFrameLabel( InStream in, byte[] contents ) throws IOException {
261     
262     if( contents != null && contents.length >= 2 ) {
263       int len = contents.length;
264       if( contents[len-1] == 1 && contents[len-2] == 0 ) {
265         //is an anchor label
266         mTagtypes.tagFrameLabel( in.readString( mStringEncoding ), true );    
267         return;    
268       }
269     }
270     
271     mTagtypes.tagFrameLabel( in.readString( mStringEncoding ) );
272   }
273 
274     protected void parseDefineSound( InStream in ) throws IOException
275     {
276         int id          = in.readUI16();
277         int format      = (int)in.readUBits( 4 );
278         int frequency   = (int)in.readUBits( 2 );
279         boolean bits16  = in.readUBits(1) != 0;
280         boolean stereo  = in.readUBits(1) != 0;
281         int sampleCount = (int)in.readUI32();
282         
283         byte[] soundData = in.read();
284         
285         mTagtypes.tagDefineSound( id, format, frequency, bits16, stereo,
286                                  sampleCount, soundData );
287     }
288     
289     protected void parseStartSound( InStream in ) throws IOException
290     {
291         int id = in.readUI16();
292         SoundInfo info = new SoundInfo( in );
293         
294         mTagtypes.tagStartSound( id, info );
295     }
296     
297     protected void parseDefineButtonSound( InStream in ) throws IOException
298     {
299         int id = in.readUI16();
300         
301         int       rollOverSoundId   = in.readUI16();
302         SoundInfo rollOverSoundInfo = (rollOverSoundId==0) ? null : new SoundInfo( in );
303         
304         int       rollOutSoundId   = in.readUI16();
305         SoundInfo rollOutSoundInfo = (rollOutSoundId==0) ? null : new SoundInfo( in );
306         
307         int       pressSoundId   = in.readUI16();
308         SoundInfo pressSoundInfo = (pressSoundId==0) ? null : new SoundInfo( in );
309         
310         int       releaseSoundId   = in.readUI16();
311         SoundInfo releaseSoundInfo = (releaseSoundId==0) ? null : new SoundInfo( in );
312         
313         mTagtypes.tagDefineButtonSound( id, 
314                      rollOverSoundId, rollOverSoundInfo,
315                      rollOutSoundId,  rollOutSoundInfo,
316                      pressSoundId,    pressSoundInfo,
317                      releaseSoundId,  releaseSoundInfo );
318 
319     }
320     
321     protected void parseSoundStreamHead( boolean adpcmOnly, InStream in ) throws IOException
322     {
323         int     reserved       = (int)in.readUBits(4);
324         int     playbackFreq   = (int)in.readUBits(2);
325         boolean playback16bits = ( in.readUBits(1) != 0 );
326         boolean playbackStereo = ( in.readUBits(1) != 0 );
327         
328         int     format       = (int)in.readUBits(4);
329         int     streamFreq   = (int)in.readUBits(2);
330         boolean stream16bits = ( in.readUBits(1) != 0 );
331         boolean streamStereo = ( in.readUBits(1) != 0 );        
332         int     avgSampleCount = (int)in.readUI16();
333         
334         //--MP3 Streams sometimes have an extra word here...
335         //if( format == SWFConstants.SOUND_FORMAT_MP3 )
336         //{
337         //    int unknown = in.readUI16();
338         //}
339         //--but other SDK's don't know about this so we can't assume it
340         //  will always be present in a SWF.
341         
342         if( adpcmOnly )
343         {
344             mTagtypes.tagSoundStreamHead( playbackFreq, playback16bits, playbackStereo,
345                                          format, streamFreq, stream16bits, streamStereo,
346                                          avgSampleCount );
347         }
348         else
349         {
350             mTagtypes.tagSoundStreamHead2( playbackFreq, playback16bits, playbackStereo,
351                                           format, streamFreq, stream16bits, streamStereo,
352                                           avgSampleCount );
353         }
354     }
355     
356     protected void parseSoundStreamBlock( InStream in ) throws IOException
357     {
358         mTagtypes.tagSoundStreamBlock( in.read() );
359     }
360 
361     protected void parseDefineBits( InStream in ) throws IOException
362     {
363         mTagtypes.tagDefineBits( in.readUI16(), in.read() );
364     }
365     
366     protected void parseDefineJPEGTables( InStream in ) throws IOException
367     {
368         mTagtypes.tagJPEGTables( in.read() );
369     }
370     
371     protected void parseDefineBitsJPEG3( InStream in ) throws IOException
372     {
373         int id   = in.readUI16();
374         int size = (int)in.readUI32();
375         
376         byte[] imageData = in.read( size );
377         byte[] alphaData = in.read();
378         
379         mTagtypes.tagDefineBitsJPEG3( id, imageData, alphaData );
380     }    
381     
382     protected void parseMorphShape( InStream in ) throws IOException
383     {
384         int id = in.readUI16();
385         
386         Rect startBounds = new Rect( in );
387         Rect endBounds   = new Rect( in );
388         
389         int edgeOffset = (int)in.readUI32();
390         
391         SWFShape shape = mTagtypes.tagDefineMorphShape( id, startBounds, endBounds );
392         
393         if( shape == null ) return;
394         
395         //--Read the Fill Styles
396         int fillCount = in.readUI8();
397         if( fillCount == 0xff ) fillCount = in.readUI16();
398         
399         for( int i = 0; i < fillCount; i++ )
400         {
401             parseMorphFillStyle( in, shape );
402         }
403         
404         //--Read the Line Styles
405         int lineCount = in.readUI8();
406         if( lineCount == 0xff ) lineCount = in.readUI16();
407         
408         for( int i = 0; i < lineCount; i++ )
409         {
410             parseMorphLineStyle( in, shape );
411         }
412 
413         //--read the start shape
414         parseShape( in, shape, false, true );
415 
416         //--read the end shape
417         parseShape( in, shape, false, true );        
418     }
419  
420     protected void parseMorphLineStyle( InStream in, SWFShape shape ) throws IOException
421     {
422         int startWidth = in.readUI16();        
423         int endWidth   = in.readUI16();
424         
425         AlphaColor startColor = new AlphaColor(in);
426         AlphaColor endColor   = new AlphaColor(in);
427 
428         shape.defineLineStyle( startWidth, startColor );        
429         shape.defineLineStyle( endWidth,   endColor   );        
430     }
431     
432     protected void parseMorphFillStyle( InStream in, SWFShape shape ) throws IOException
433     {
434         int fillType = in.readUI8();
435         
436         if( fillType == FILL_SOLID )
437         {
438             AlphaColor startColor = new AlphaColor(in);
439             AlphaColor endColor   = new AlphaColor(in);
440                         
441             shape.defineFillStyle( startColor );
442             shape.defineFillStyle( endColor   );
443         }
444         else if( fillType == FILL_LINEAR_GRADIENT 
445               || fillType == FILL_RADIAL_GRADIENT )
446         {
447             Matrix startMatrix = new Matrix( in );
448             Matrix endMatrix   = new Matrix( in );
449             
450             int numRatios = in.readUI8();
451             
452             int[]        startRatios = new int[ numRatios ];
453             AlphaColor[] startColors = new AlphaColor[ numRatios ];
454 
455             int[]        endRatios = new int[ numRatios ];
456             AlphaColor[] endColors = new AlphaColor[ numRatios ];
457                         
458             for( int i = 0; i < numRatios; i++ )
459             {
460                 startRatios[i] = in.readUI8();
461                 startColors[i] = new AlphaColor(in);
462                 endRatios[i]   = in.readUI8();
463                 endColors[i]   = new AlphaColor(in);
464             }            
465             
466             shape.defineFillStyle( startMatrix, startRatios, startColors, 
467                                    fillType == FILL_RADIAL_GRADIENT );
468 
469             shape.defineFillStyle( endMatrix, endRatios, endColors, 
470                                    fillType == FILL_RADIAL_GRADIENT );
471         }
472         else if( fillType == FILL_TILED_BITMAP 
473               || fillType == FILL_CLIPPED_BITMAP )
474         {
475             int bitmapId = in.readUI16();
476             Matrix startMatrix = new Matrix( in );
477             Matrix endMatrix   = new Matrix( in );
478             
479             shape.defineFillStyle( bitmapId, startMatrix, 
480                                    fillType == FILL_CLIPPED_BITMAP );
481 
482             shape.defineFillStyle( bitmapId, endMatrix, 
483                                    fillType == FILL_CLIPPED_BITMAP );
484         }                            
485     }
486     
487     protected void parseDefineJPEG2( InStream in, int length ) throws IOException
488     {
489         int id = in.readUI16();        
490         
491         //--read the image data
492         byte[] image = in.read( length - 2 );
493         
494         mTagtypes.tagDefineBitsJPEG2( id, image );
495     }
496     
497     protected void parseDefineBitsLossless( InStream in, int length, 
498                                             boolean hasAlpha )
499         throws IOException
500     {
501         int id     = in.readUI16();        
502         int format = in.readUI8();
503         int width  = in.readUI16();
504         int height = in.readUI16();
505         
506         int size = 0;
507         
508         switch( format )
509         {
510             case BITMAP_FORMAT_8_BIT:  size = in.readUI8() + 1; break;
511             case BITMAP_FORMAT_16_BIT: size = in.readUI16() + 1; break;
512             case BITMAP_FORMAT_32_BIT: size = 0; break;
513             default: throw new IOException( "unknown bitmap format: " + format );
514         }                
515         
516         byte[] data = in.read( length - (int)in.getBytesRead() );
517         
518         //--unzip the data
519         ByteArrayInputStream bin = new ByteArrayInputStream(data);
520         InflaterInputStream inflater = new InflaterInputStream( bin );
521         InStream dataIn = new InStream( inflater );
522         
523         Color[] colors = hasAlpha ? new AlphaColor[ size ] : new Color[ size ];
524         
525         for( int i = 0; i < size; i++ )
526         {
527             colors[i] = hasAlpha ? new AlphaColor( dataIn ) : new Color( dataIn );
528         }
529         
530         byte[] imageData = dataIn.read();
531         
532         if( hasAlpha )
533         {
534             mTagtypes.tagDefineBitsLossless2( id, format, width, height, 
535                                              (AlphaColor[])colors, imageData );
536         }
537         else
538         {
539             mTagtypes.tagDefineBitsLossless( id, format, width, height, colors, imageData );
540         }
541     }
542     
543     protected void parseExport( InStream in ) throws IOException
544     {
545         int count     = in.readUI16();
546         
547         String[] exportNames = new String[ count ];
548         int[]    exportIds   = new int[ count ];
549         
550         for( int i = 0; i < count; i++ )
551         {
552             exportIds[i]   = in.readUI16();
553             exportNames[i] = in.readString( mStringEncoding );
554         }        
555         
556         mTagtypes.tagExport( exportNames, exportIds );
557     }
558     
559     protected void parseImport( InStream in ) throws IOException
560     {
561         String movieName     = in.readString( mStringEncoding );
562         int count     = in.readUI16();
563         
564         String[] importNames = new String[ count ];
565         int[]    importIds   = new int[ count ];
566         
567         for( int i = 0; i < count; i++ )
568         {
569             importIds[i]   = in.readUI16();
570             importNames[i] = in.readString( mStringEncoding );
571         }
572         
573         mTagtypes.tagImport( movieName, importNames, importIds );
574     }
575     
576     protected void parseDefineButton2( InStream in ) throws IOException
577     {
578         int id = in.readUI16();
579                 
580         boolean trackAsMenu = ( in.readUI8() != 0 );
581         
582         int actionOffset = in.readUI16();  //skip first offset
583         
584         //--Read multiple button records
585         Vector buttonRecords = ButtonRecord2.read( in );
586                
587         SWFActions actions = mTagtypes.tagDefineButton2( id, trackAsMenu, buttonRecords );
588         
589         if( actions == null ) return;
590         
591         //--Read multiple action records        
592         while( actionOffset != 0 )
593         {
594             actionOffset = in.readUI16();                
595                         
596             //--Read the condition flags for this action array
597             int actionConditions = in.readUI16();
598                         
599             actions.start( actionConditions );
600             
601             ActionParser parser = new ActionParser( actions, mFlashVersion );
602             parser.parse( in );
603         }                
604         
605         actions.done();
606     }    
607     
608     protected void parseButtonCXForm( InStream in ) throws IOException
609     {
610         int buttonId = in.readUI16();
611         ColorTransform transform = new ColorTransform( in );
612         
613         mTagtypes.tagButtonCXForm( buttonId, transform );
614     }
615     
616     protected void parseDefineButton( InStream in ) throws IOException
617     {
618         int id = in.readUI16();
619         Vector buttonRecords = ButtonRecord.read( in );
620         
621         SWFActions actions = mTagtypes.tagDefineButton( id, buttonRecords );
622         
623         if( actions == null ) return;
624         
625         actions.start( 0 );  //no conditions
626         ActionParser parser = new ActionParser( actions, mFlashVersion );
627         parser.parse( in );
628         actions.done();        
629     }
630     
631     protected void parseDefineText( int type, InStream in ) throws IOException
632     {
633         int    id     = in.readUI16();        
634         Rect   bounds = new Rect( in );
635         Matrix matrix = new Matrix( in );
636         
637         SWFText text = ( type == TAG_DEFINETEXT ) ? 
638                            mTagtypes.tagDefineText( id, bounds, matrix ) :
639                            mTagtypes.tagDefineText2( id, bounds, matrix );
640         
641         if( text == null ) return;
642         
643         int glyphBits   = in.readUI8();
644         int advanceBits = in.readUI8();
645         
646         //--Read multiple text records
647         int firstByte;
648         
649         while( ( firstByte = in.readUI8()) != 0 )
650         {
651             if( (firstByte & 0x80) == 0 ) //Glyph Record
652             {
653                 //--Get number of glyph entries
654                 int glyphCount = firstByte & 0x7f;
655         
656                 int[] glyphs   = new int[ glyphCount ];
657                 int[] advances = new int[ glyphCount ];
658             
659                 //--Read the glyph entries
660                 for( int i = 0; i < glyphCount; i++ )
661                 {
662                     glyphs[i]   = (int)in.readUBits( glyphBits );
663                     advances[i] = in.readSBits( advanceBits );
664                 }            
665 
666                 text.text( glyphs, advances );
667             }
668             else //Style Record
669             {
670                 int flags = firstByte;
671             
672                 int fontId = 0;
673                 
674                 if( ( flags & TEXT_HAS_FONT ) != 0 )
675                 {
676                     fontId = in.readUI16();
677                 }
678             
679                 if( ( flags & TEXT_HAS_COLOR ) != 0 )
680                 {
681                     text.color( (type == TAG_DEFINETEXT2) ? 
682                                     new AlphaColor( in ) : 
683                                     new Color( in ));
684                 }
685 
686                 if( ( flags & TEXT_HAS_XOFFSET ) != 0 )
687                 {
688                     text.setX( in.readSI16() );
689                 }
690 
691                 if( ( flags & TEXT_HAS_YOFFSET ) != 0 ) //x & y are in reverse order from flag bits
692                 {
693                     text.setY ( in.readSI16() );
694                 }
695 
696                 if( ( flags & TEXT_HAS_FONT ) != 0 )
697                 {
698                     int textHeight = in.readUI16();
699                     
700                     text.font( fontId, textHeight );
701                 }
702             }
703         }             
704 
705         text.done();
706     }
707     
708     protected void parseDefineTextField( InStream in ) throws IOException
709     {
710         int id = in.readUI16();
711 
712         Rect boundary = new Rect( in );
713         
714         int flags     = in.readUI16();
715         int fontId    = in.readUI16();
716         int fontSize  = in.readUI16();
717         AlphaColor textColor = new AlphaColor( in );
718         
719         int charLimit = ( (flags & TEXTFIELD_LIMIT_CHARS ) != 0 ) ? in.readUI16() : 0;
720         
721         int alignment   = in.readUI8();
722         int leftMargin  = in.readUI16();
723         int rightMargin = in.readUI16();
724         int indentation = in.readUI16();
725         int lineSpacing = in.readUI16();
726                 
727         String fieldName = in.readString( mStringEncoding );
728         String initialText = ( (flags & TEXTFIELD_HAS_TEXT ) != 0 ) ? in.readString( mStringEncoding ) : null;
729         
730         mTagtypes.tagDefineTextField( id, fieldName, initialText, boundary, flags,
731                                      textColor, alignment, fontId, fontSize,
732                                      charLimit, leftMargin, rightMargin, 
733                                      indentation, lineSpacing );
734     }
735     
736     protected void parseDefineFont2( InStream in ) throws IOException
737     {
738         int id            = in.readUI16();
739         int flags         = in.readUI8();
740         int reservedFlags = in.readUI8();
741         
742         int nameLength = in.readUI8();
743         String name = new String( in.read( nameLength ) );
744         
745         int glyphCount = in.readUI16();
746         Vector glyphs = new Vector();
747         
748         int[] offsets = new int[ glyphCount + 1 ];
749         boolean is32 = ( flags & FONT2_32OFFSETS ) != 0;
750         for( int i = 0; i <= glyphCount; i++ )
751         {
752             offsets[i] = is32 ? (int)in.readUI32() : in.readUI16();
753         }        
754         
755         for( int i = 1; i <= glyphCount; i++ )
756         {
757             int glyphSize = offsets[i] - offsets[i-1];
758             byte[] glyphBytes = in.read( glyphSize );
759             glyphs.addElement( glyphBytes );
760         }
761         
762         boolean isWide = (( flags & FONT2_WIDECHARS ) != 0 ) || ( glyphCount > 256 );
763         
764         int[] codes = new int[ glyphCount ];
765         for( int i = 0; i < glyphCount; i++ )
766         {
767             codes[i] = isWide ? in.readUI16() : in.readUI8();
768         }        
769         
770         System.out.println( "glyphCount=" + glyphCount + " flags=" + Integer.toBinaryString( flags ) );
771         
772         int ascent = 0;
773         int descent = 0;
774         int leading = 0;
775         int[]  advances = new int[0];
776         Rect[] bounds   = new Rect[0];
777         int[]  kerningCodes1      = new int[0];
778         int[]  kerningCodes2      = new int[0];
779         int[]  kerningAdjustments = new int[0];
780         
781         if( ( flags & FONT2_HAS_LAYOUT ) != 0 )
782         {
783             ascent  = in.readSI16();
784             descent = in.readSI16();
785             leading = in.readSI16();
786 
787             advances = new int[ glyphCount ];
788             
789             for( int i = 0; i < glyphCount; i++ )
790             {
791                 advances[i] = in.readSI16();
792             }        
793             
794             bounds = new Rect[ glyphCount ];
795             
796             for( int i = 0; i < glyphCount; i++ )
797             {
798                 bounds[i] = new Rect( in );
799             }        
800          
801             int kerningCount = in.readUI16();
802             
803             kerningCodes1      = new int[ kerningCount ];
804             kerningCodes2      = new int[ kerningCount ];
805             kerningAdjustments = new int[ kerningCount ];
806             
807             for( int i = 0; i < kerningCount; i++ )
808             {
809                 kerningCodes1     [i] = isWide ? in.readUI16() : in.readUI8();
810                 kerningCodes2     [i] = isWide ? in.readUI16() : in.readUI8();
811                 kerningAdjustments[i] = in.readSI16();
812             }        
813         }    
814         
815         SWFVectors vectors = mTagtypes.tagDefineFont2( id, flags, name, glyphCount,
816                                                       ascent, descent, leading,
817                                                       codes, advances, bounds,
818                                                       kerningCodes1,
819                                                       kerningCodes2,
820                                                       kerningAdjustments );
821         
822         if( vectors == null ) return;
823         
824         if( glyphs.isEmpty() )
825         {
826             vectors.done();
827         }
828         else
829         {
830             for( Enumeration enum = glyphs.elements(); enum.hasMoreElements(); )
831             {
832                 byte[] glyphBytes = (byte[])enum.nextElement();
833                 
834                 InStream glyphIn = new InStream( glyphBytes );
835                 
836                 parseShape( glyphIn, vectors, false, false );
837             }
838         }
839     }
840     
841     protected void parseFontInfo( InStream in, int length, boolean isFI2 ) throws IOException
842     {
843         int fontId = in.readUI16();
844         
845         //--Read the font name
846         int nameLength = in.readUI8();
847         byte[] chars = in.read( nameLength );
848         String fontName = new String( chars );
849         
850         //--Read the font flags
851         int flags = in.readUI8();
852         
853         //--Read language code
854         int langCode = isFI2 ? in.readUI8() : 0;
855         
856         //--Adjust the body length
857         length -= 4 + nameLength;
858         
859         //--Read the Glyph-to-code table
860         boolean wide = (flags & FONT_WIDECHARS) != 0;
861         
862         int[] codes = new int[ wide ? ( length / 2 ) : length ];
863         
864         for( int i = 0; i < codes.length; i++ )
865         {
866             codes[i] = wide ? in.readUI16() : in.readUI8();
867         }             
868         if( isFI2 ) mTagtypes.tagDefineFontInfo2( fontId, fontName, flags, codes, langCode );
869         else        mTagtypes.tagDefineFontInfo ( fontId, fontName, flags, codes );
870     }
871     
872     protected void parseDefineFont( InStream in ) throws IOException
873     {
874         int id          = in.readUI16();
875         int firstOffset = in.readUI16();
876         int numGlyphs   = firstOffset / 2;
877         
878         SWFVectors vectors = mTagtypes.tagDefineFont( id, numGlyphs );
879         
880         if( vectors == null ) return;
881         
882         //--Skip the offset table
883         for( int i = 1; i < numGlyphs; i++ )
884         {
885             in.readUI16();
886         }
887         
888         for( int i = 0; i < numGlyphs; i++ )
889         {
890             parseShape( in, vectors,  false, false );
891         }        
892     }
893     
894     protected void parseDefineSprite( InStream in ) throws IOException
895     {
896         int id         = in.readUI16();
897         int frameCount = in.readUI16();
898         
899         SWFTagTypes sstt = mTagtypes.tagDefineSprite( id );
900         
901         if( sstt == null ) return;
902         
903         TagParser parser = new TagParser( sstt );
904         SWFReader reader = new SWFReader( parser, in );
905         reader.readTags();
906     }
907     
908     protected void parsePlaceObject2( InStream in ) throws IOException
909     {
910         boolean hasClipActions    = in.readUBits(1) != 0;
911         boolean isClipBracket     = in.readUBits(1) != 0;
912         boolean hasName           = in.readUBits(1) != 0;
913         boolean hasRatio          = in.readUBits(1) != 0;
914         boolean hasColorTransform = in.readUBits(1) != 0;
915         boolean hasMatrix         = in.readUBits(1) != 0;
916         boolean hasCharacter      = in.readUBits(1) != 0;
917         boolean isMove            = in.readUBits(1) != 0;
918     
919         int depth = in.readUI16();
920         
921         int            charId    = hasCharacter      ? in.readUI16()            : 0;
922         Matrix         matrix    = hasMatrix         ? new Matrix( in )         : null;
923         AlphaTransform cxform    = hasColorTransform ? new AlphaTransform( in ) : null;
924         int            ratio     = hasRatio          ? in.readUI16()            : -1;        
925         int            clipDepth = isClipBracket     ? in.readUI16()            : 0;
926         String         name      = hasName           ? in.readString( mStringEncoding )  : null;  
927         
928         int clipActionFlags = 0;
929         
930         if( hasClipActions )
931         {
932             in.readUI16();  //unknown
933             clipActionFlags = in.readUI16();  //compound flags
934         }
935         
936         SWFActions actions = mTagtypes.tagPlaceObject2(
937                                  isMove, clipDepth, depth, charId, 
938                                  matrix, cxform, ratio, name, 
939                                  clipActionFlags );
940         
941         if( hasClipActions && actions != null )
942         {
943             int flags = 0;
944         
945             while( (flags = in.readUI16()) != 0 )
946             {
947                 int length = (int)in.readUI32();
948 
949                 actions.start( flags );
950                 ActionParser parser = new ActionParser( actions, mFlashVersion );
951                 
952                 parser.parse( in );
953             }
954 
955             actions.done();
956         }
957     }
958         
959     protected void parsePlaceObject( InStream in, int length ) throws IOException
960     {
961         mTagtypes.tagPlaceObject( 
962             in.readUI16(),  //char id
963             in.readUI16(),  //depth
964             new Matrix( in ),
965             ( in.getBytesRead() < length ) ? new AlphaTransform( in ) : null );
966     }
967     
968     protected void parseDoAction( InStream in ) throws IOException 
969     {
970         SWFActions actions = mTagtypes.tagDoAction();
971         
972         if( actions == null ) return;
973         
974         actions.start( 0 );  //no conditions
975         ActionParser parser = new ActionParser( actions, mFlashVersion );
976         parser.parse( in );
977         actions.done();
978     }
979 
980   protected void parseDoInitAction( InStream in ) throws IOException 
981   {
982     int spriteId = in.readUI16();
983     SWFActions actions = mTagtypes.tagDoInitAction( spriteId );
984         
985     if( actions == null ) return;
986         
987     actions.start( 0 );  //no conditions
988     ActionParser parser = new ActionParser( actions, mFlashVersion );
989     parser.parse( in );
990     actions.done();
991   }
992     
993     protected void parseDefineShape( int type, InStream in ) throws IOException
994     {
995         int  id    = in.readUI16();
996         Rect rect  = new Rect( in );
997         
998         SWFShape shape = null;
999         
1000        switch( type )
1001        {
1002            case TAG_DEFINESHAPE : shape = mTagtypes.tagDefineShape( id, rect ); break;
1003            case TAG_DEFINESHAPE2: shape = mTagtypes.tagDefineShape2( id, rect ); break;
1004            case TAG_DEFINESHAPE3: shape = mTagtypes.tagDefineShape3( id, rect ); break;
1005            default: break;
1006        }
1007        
1008        if( shape == null ) return;
1009        
1010        parseShape( in, shape,
1011                    true /*has style*/, 
1012                    type == TAG_DEFINESHAPE3 /*has alpha*/ );        
1013    }
1014    
1015    protected void parseShape( InStream in, SWFVectors vectors,
1016                               boolean hasStyle, boolean hasAlpha )
1017        throws IOException
1018    {       
1019        SWFShape shape = (vectors instanceof SWFShape) ?
1020                            (SWFShape)vectors : 
1021                            null;
1022        
1023        in.synchBits();
1024        
1025        if( hasStyle ) parseStyles( in, shape, hasAlpha );
1026        
1027        in.synchBits();
1028        
1029        int[] numFillBits = new int[] { (int)in.readUBits(4) };
1030        int[] numLineBits = new int[] { (int)in.readUBits(4) };  
1031        
1032        //--Read the shape records
1033        while( true )
1034        {
1035            int type = (int)in.readUBits(1);
1036            
1037            if( type == 1 ) // Edge shape-record
1038            {
1039                boolean isCurved = in.readUBits(1) == 0L;
1040                    
1041                if( isCurved )  //curve
1042                {
1043                    int numBits  = ((int)in.readUBits(4)) + 2;
1044
1045                    int cx = in.readSBits( numBits );
1046                    int cy = in.readSBits( numBits );
1047                    int dx = in.readSBits( numBits );
1048                    int dy = in.readSBits( numBits );                    
1049                    
1050                    vectors.curve( cx, cy, dx, dy );
1051                }
1052                else  //line
1053                {
1054                    int numBits  = ((int)in.readUBits(4)) + 2;
1055            
1056                    boolean generalLine = in.readUBits(1) == 1;
1057                       
1058                    int dx = 0;
1059                    int dy = 0;
1060                    
1061                    if( generalLine )
1062                    {
1063                        dx = in.readSBits( numBits );
1064                        dy = in.readSBits( numBits );
1065                    }
1066                    else // a non-general line
1067                    {
1068                        boolean vertLine = in.readUBits(1) == 1;
1069                                    
1070                        if( vertLine )
1071                        {
1072                            dy = in.readSBits( numBits );
1073                        }
1074                        else //horizontal line
1075                        {
1076                            dx = in.readSBits( numBits );
1077                        }
1078                    }
1079                    
1080                    vectors.line( dx, dy );
1081                }                
1082            }
1083            else //End of records or Change Record
1084            {
1085                int flags = (int)in.readUBits(5);
1086                
1087                if( flags == 0 ) break; //end of records
1088                
1089                parseChangeRecord( in, flags, vectors, shape, hasAlpha,
1090                                   numFillBits, numLineBits );                
1091            }            
1092        }      
1093        
1094        vectors.done();
1095    }
1096    
1097    protected void parseChangeRecord( InStream in, int flags, SWFVectors vectors,
1098                                      SWFShape shape, boolean hasAlpha,
1099                                      int[] numFillBits, int[] numLineBits )
1100        throws IOException
1101    {
1102        //System.out.println( "In Change --> " + Integer.toBinaryString( flags ));
1103        
1104        boolean hasNewStyles  = (flags & 0x10) != 0;
1105        boolean hasLineStyle  = (flags & 0x08) != 0;
1106        boolean hasFillStyle1 = (flags & 0x04) != 0; //note reverse order
1107        boolean hasFillStyle0 = (flags & 0x02) != 0; //note reverse order
1108        boolean hasMoveTo     = (flags & 0x01) != 0;
1109        
1110        if( hasMoveTo )
1111        {
1112            int moveBits = (int)in.readUBits(5);
1113            int moveX = in.readSBits( moveBits );
1114            int moveY = in.readSBits( moveBits );
1115            
1116            //System.out.println( "X=" + moveX + ", Y=" + moveY );
1117            
1118            vectors.move( moveX, moveY );
1119        }
1120                
1121        if( hasFillStyle0 )
1122        {
1123            int fillStyle0 = (int)in.readUBits( numFillBits[0] );
1124
1125            //System.out.println( "fill0=" + fillStyle0 );
1126            
1127            if( shape != null ) shape.setFillStyle0( fillStyle0 );
1128        }
1129                
1130        if( hasFillStyle1 )
1131        {
1132            int fillStyle1 = (int)in.readUBits( numFillBits[0] );
1133
1134            //System.out.println( "fill1=" + fillStyle1 );
1135            
1136            if( shape != null ) shape.setFillStyle1( fillStyle1 );
1137        }
1138                
1139        if( hasLineStyle )
1140        {
1141            int lineStyle = (int)in.readUBits( numLineBits[0] );
1142
1143            //System.out.println( "line=" + lineStyle ); 
1144
1145            if( shape != null ) shape.setLineStyle( lineStyle );
1146        }
1147                                
1148        if( hasNewStyles )
1149        {
1150            parseStyles( in, shape, hasAlpha );
1151                
1152            numFillBits[0] = (int)in.readUBits(4);
1153            numLineBits[0] = (int)in.readUBits(4);  
1154        }        
1155    }
1156    
1157    protected void parseStyles( InStream in, SWFShape shape, boolean hasAlpha ) 
1158        throws IOException
1159    {
1160        int numFillStyles = in.readUI8();
1161        if( numFillStyles == 0xff )  //larger number format
1162        {
1163            numFillStyles = in.readUI16();
1164        }
1165            
1166        for( int i = 0; i < numFillStyles; i++ )
1167        {
1168            parseFillStyle( in, shape, hasAlpha );
1169        }            
1170
1171        int numLineStyles = in.readUI8();
1172        if( numLineStyles == 0xff )  //larger number format
1173        {
1174            numLineStyles = in.readUI16();
1175        }
1176               
1177        for( int i = 0; i < numLineStyles; i++ )
1178        {
1179            parseLineStyle( in, shape, hasAlpha );
1180        }
1181    }
1182    
1183    public void parseLineStyle( InStream in, SWFShape shape, boolean hasAlpha )
1184        throws IOException 
1185    {
1186        int width = in.readUI16();
1187        Color color = hasAlpha ? new AlphaColor(in) : new Color(in);
1188
1189        if( shape != null ) shape.defineLineStyle( width, color );
1190    }
1191
1192    public void parseFillStyle( InStream in, SWFShape shape, boolean hasAlpha )
1193        throws IOException 
1194    {
1195        int fillType = in.readUI8();
1196        
1197        if( fillType == FILL_SOLID )
1198        {
1199            Color color = hasAlpha ? new AlphaColor(in) : new Color(in);
1200            
1201            if( shape != null ) shape.defineFillStyle( color );
1202        }
1203        else if( fillType == FILL_LINEAR_GRADIENT 
1204              || fillType == FILL_RADIAL_GRADIENT )
1205        {
1206            Matrix matrix   = new Matrix( in );            
1207            
1208            int numRatios = in.readUI8();
1209            
1210            int[]   ratios = new int[ numRatios ];
1211            Color[] colors = new Color[ numRatios ];
1212            
1213            for( int i = 0; i < numRatios; i++ )
1214            {
1215                ratios[i] = in.readUI8();
1216                colors[i] = hasAlpha ? new AlphaColor(in) : new Color(in);
1217            }            
1218            
1219            if( shape != null )
1220            {
1221                shape.defineFillStyle( matrix, ratios, colors, 
1222                                       fillType == FILL_RADIAL_GRADIENT );
1223            }                        
1224        }
1225        else if( fillType == FILL_TILED_BITMAP 
1226              || fillType == FILL_CLIPPED_BITMAP )
1227        {
1228            int bitmapId = in.readUI16();
1229            Matrix matrix = new Matrix( in );
1230            
1231            if( shape != null )
1232            {
1233                shape.defineFillStyle( bitmapId, matrix, 
1234                                       fillType == FILL_CLIPPED_BITMAP );
1235            }            
1236        }                    
1237    }
1238    
1239    public static void main( String[] args ) throws IOException
1240    {
1241        FileInputStream  in  = new FileInputStream ( args[0] );
1242        FileOutputStream out = new FileOutputStream( args[1] );
1243        
1244        SWFWriter writer = new SWFWriter( out );
1245        TagWriter tagwtr = new TagWriter( writer );
1246        
1247        TagParser parser = new TagParser( tagwtr );
1248        SWFReader reader = new SWFReader( parser, in );
1249        
1250        reader.readFile();
1251        out.flush();
1252        out.close();
1253        in.close();
1254    }    
1255}