Source code: com/anotherbigidea/flash/writers/SWFWriter.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.writers;
35
36 import java.io.*;
37 import com.anotherbigidea.io.*;
38 import com.anotherbigidea.flash.*;
39 import com.anotherbigidea.flash.structs.Rect;
40 import com.anotherbigidea.flash.interfaces.*;
41
42 /**
43 * Implements the SWFTags interface and writes a SWF file to the output stream
44 */
45 public class SWFWriter implements SWFTags, SWFFileSignature
46 {
47 protected OutStream mOut;
48 protected OutputStream mOutputstream;
49 protected ByteArrayOutputStream mByteout;
50 protected String mSignature = null;
51
52 //--deferred header values
53 protected int frameCount;
54 protected int version;
55 protected Rect frameSize;
56 protected int height;
57 protected int rate;
58
59 /**
60 * Write to a file.
61 */
62 public SWFWriter( String filename ) throws IOException {
63 this( new FileOutputStream( filename ) );
64 }
65
66 /**
67 * Write to an output stream - closing it at the end.
68 */
69 public SWFWriter( OutputStream outputstream )
70 {
71 mOutputstream = outputstream;
72 mOut = new OutStream( outputstream );
73 }
74
75 /**
76 * Write to an out stream - closing it at the end.
77 */
78 public SWFWriter( OutStream outstream )
79 {
80 mOut = outstream;
81 }
82
83 /**
84 * Sets the file signature if it has not been set already.
85 * The setCompression(..) method calls this and thus prevents any further
86 * changes to the signature - overriding any signature passed down from the
87 * SWFReader.
88 *
89 * @see SWFFileSignature#signature(String)
90 */
91 public void signature( String sig ) {
92 if( mSignature != null ) return;
93 mSignature = sig;
94 }
95
96 /**
97 * Set Flash MX+ zip-compression on or off.
98 * It sets the file signature and thus prevents any different signature
99 * from being specified. Only the first call to this method has any effect,
100 * and only if signature(..) has not been called yet.
101 *
102 * @param compressionOn true for compression, false for no compression.
103 */
104 public void setCompression( boolean compressionOn ) {
105 signature( compressionOn ?
106 SWFFileSignature.SIGNATURE_COMPRESSED :
107 SWFFileSignature.SIGNATURE_NORMAL );
108 }
109
110 /**
111 * Writes the header unless the length or framecount are unknown (as
112 * signified by a negative value), in which case the header values are
113 * stored and written later, when the unknown value(s) can be determined.
114 *
115 * @see SWFHeader#header(int, long, int, int, int, int)
116 */
117 public void header( int version, long length,
118 int twipsWidth, int twipsHeight,
119 int frameRate, int frameCount ) throws IOException
120 {
121 frameSize = new Rect( 0, 0, twipsWidth, twipsHeight );
122
123 //--Unknown values
124 if( length < 0 || frameCount < 0 )
125 {
126 //--defer the header
127 this.version = version;
128 this.rate = frameRate;
129 this.frameCount = 0;
130
131 //--set up a byte array for the output
132 if( mByteout == null )
133 {
134 mByteout = new ByteArrayOutputStream( 20000 );
135 mOut = new OutStream( mByteout );
136 }
137
138 return;
139 }
140
141 writeHeader( version, length, frameRate, frameCount );
142 }
143
144 /**
145 * @see SWFTags#tag(int, boolean, byte[])
146 */
147 public void tag( int tagType, boolean longTag,
148 byte[] contents ) throws IOException
149 {
150 //System.out.println( "OUT Tag " + tagType + " " + longTag + " " + ( (contents==null) ? 0 : contents.length) );
151 //System.out.println();
152
153 int length = (contents != null ) ? contents.length : 0;
154 longTag = ( length > 62 ) || longTag;
155
156 int hdr = ( tagType << 6 ) + ( longTag ? 0x3f : length );
157
158 mOut.writeUI16( hdr );
159
160 if( longTag ) mOut.writeUI32( length );
161
162 if( contents != null ) mOut.write( contents );
163
164 if( tagType == SWFConstants.TAG_SHOWFRAME ) frameCount++;
165 if( tagType == SWFConstants.TAG_END ) finish();
166 }
167
168 protected void writeHeader( int version, long length,
169 int frameRate, int frameCount ) throws IOException
170 {
171 writeSignature();
172 mOut.writeUI8( version );
173 mOut.writeUI32( length );
174
175 //may be compressed from this point onwards
176 if( mSignature.equals( SWFFileSignature.SIGNATURE_COMPRESSED ) ) {
177 mOut.writeCompressed();
178 }
179
180 frameSize.write( mOut );
181 mOut.writeUI16( frameRate << 8 );
182 mOut.writeUI16( frameCount );
183 }
184
185 private void writeSignature() throws IOException {
186 if( mSignature == null ) signature( SWFFileSignature.SIGNATURE_NORMAL );
187 mOut.write( mSignature.getBytes( "US-ASCII" ));
188 }
189
190 /**
191 * Finish writing
192 */
193 protected void finish() throws IOException
194 {
195 //--Writing to a byte array - need to recalculate lengths
196 if( mByteout != null )
197 {
198 byte[] bytes = mByteout.toByteArray();
199
200 long length = 12L + frameSize.getLength() + bytes.length;
201
202 mOut = new OutStream( mOutputstream );
203
204 writeHeader( version, length, rate, frameCount );
205
206 mOut.write( bytes );
207 }
208
209 mOut.close();
210 }
211 }