/*
* JSwiff is an open source Java API for Macromedia Flash file generation
* and manipulation
*
* Copyright (C) 2004-2006 Ralf Terdic (contact@jswiff.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.jswiff;
import com.jswiff.io.OutputBitStream;
import com.jswiff.swfrecords.tags.FileAttributes;
import com.jswiff.swfrecords.tags.Metadata;
import com.jswiff.swfrecords.tags.SetBackgroundColor;
import com.jswiff.swfrecords.tags.Tag;
import com.jswiff.swfrecords.tags.TagConstants;
import com.jswiff.swfrecords.tags.TagWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
/**
* This class writes an SWF document (an <code>SWFDocument</code> instance) to
* an output stream. Usage:
*
* <pre>
* <code>
* SWFWriter writer = new SWFWriter(doc, outputStream);
* writer.write();
* </code>
* </pre>
*/
public class SWFWriter {
private OutputBitStream bitStream;
private SWFDocument document;
private boolean japanese;
/**
* Creates a new SWF writer which writes the specified SWF document to the
* stream supplied here.
*
* @param document
* the SWF document to be written
* @param stream
* the output stream the SWF file is written to
*/
public SWFWriter(SWFDocument document, OutputStream stream) {
bitStream = new OutputBitStream(stream);
this.document = document;
}
/**
* Specifies whether strings should be encoded using Japanese encoding
* (Shift-JIS). This is relevant only for SWF 5 or earlier, where strings
* are encoded using either ANSI or Shift-JIS. In Flash Player, the decoding
* choice is made depending on the locale, as this information is not stored
* in the SWF. Later SWF versions use Unicode (UTF-8) and ignore this
* option.
*
* @param japanese
* <code>true</code> if Shift-JIS encoding is to be used
*/
public void setJapanese(boolean japanese) {
this.japanese = japanese;
}
/**
* Writes the SWF to the stream passed to the constructor. The stream is
* then closed.
*
* @throws IOException
* if an I/O error occured
*/
public void write() throws IOException {
try {
byte[] docPropertiesTagsBuffer = getDocPropertiesTagsBuffer();
byte[] tagsBuffer = TagWriter.writeTags(document.getTags(), document.getVersion(), japanese);
byte[] headerEndData = getHeaderEndData();
long fileLength = 8 + headerEndData.length + tagsBuffer.length + docPropertiesTagsBuffer.length;
writeHeaderStart();
bitStream.writeUI32(fileLength);
if (document.isCompressed()) {
bitStream.enableCompression();
}
bitStream.writeBytes(headerEndData);
// header written, now write document property tags (background,
// file attrs, metadata)
bitStream.writeBytes(docPropertiesTagsBuffer);
// write all remaining tags
bitStream.writeBytes(tagsBuffer);
} finally {
try {
bitStream.close();
} catch (Exception e) {
// empty on purpose - don't need to propagate errors which occur
// while closing
}
}
}
protected byte[] getDocPropertiesTagsBuffer() throws IOException {
OutputBitStream tagStream = new OutputBitStream();
if (document.getVersion() >= 8) {
FileAttributes fileAttributes = new FileAttributes();
fileAttributes.setAllowNetworkAccess(document.getAccessMode() == SWFDocument.ACCESS_MODE_NETWORK);
TagWriter.writeTag(tagStream, fileAttributes, document.getVersion());
String metadata = document.getMetadata();
if (metadata != null) {
fileAttributes.setHasMetadata(true);
TagWriter.writeTag(tagStream, new Metadata(metadata), document.getVersion());
}
}
TagWriter.writeTag(tagStream, new SetBackgroundColor(document.getBackgroundColor()), document.getVersion());
return tagStream.getData();
}
private int getFrameCount() {
int count = 0;
for (Iterator i = document.getTags().iterator(); i.hasNext();) {
if (((Tag) i.next()).getCode() == TagConstants.SHOW_FRAME) {
count++;
}
}
return count;
}
private byte[] getHeaderEndData() throws IOException {
OutputBitStream headerStream = new OutputBitStream();
// frame size
document.getFrameSize().write(headerStream);
// frame rate
headerStream.writeUI8((short) 0); // this byte is ignored
headerStream.writeUI8(document.getFrameRate());
// frame count
headerStream.writeUI16(getFrameCount());
byte[] headerData = headerStream.getData();
return headerData;
}
private void writeHeaderStart() throws IOException {
// writes CWS/FWS and version - that's 4 bytes
// C (0x43) for compressed or F (0x46) for uncompressed files
bitStream.writeUI8((short) (document.isCompressed() ? 0x43 : 0x46));
// WS (0x57 0x53)
bitStream.writeBytes(new byte[] { 0x57, 0x53 });
// version
bitStream.writeUI8(document.getVersion());
}
}