/* * 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.InputBitStream; import com.jswiff.listeners.SWFListener; import com.jswiff.swfrecords.SWFHeader; import com.jswiff.swfrecords.tags.MalformedTag; import com.jswiff.swfrecords.tags.Tag; import com.jswiff.swfrecords.tags.TagConstants; import com.jswiff.swfrecords.tags.TagHeader; import com.jswiff.swfrecords.tags.TagReaderImpl; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * This class reads an SWF file from a stream, invoking registered listeners to * process the SWF. Use the following code to parse a SWF into a * <code>SWFDocument</code> instance: * <pre> * <code> * SWFReader reader = new SWFReader(inputStream); * SWFDocumentReader docReader = new SWFDocumentReader(); * reader.addListener(docReader); * reader.read(); * SWFDocument doc = docReader.getDocument(); * </code> * </pre> */ public class SWFReader { protected InputBitStream bitStream; protected List listeners = new ArrayList(); protected boolean japanese; /** * Creates a new SWF reader which reads from the specified stream. * * @param stream the input stream the SWF file is read from */ public SWFReader(InputStream stream) { this.bitStream = new InputBitStream(stream); } /** * Specifies whether strings should be decoded 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; } /** * Registers a listener in order to process the SWF content. * * @param listener a <code>SWFListener</code> instance */ public void addListener(SWFListener listener) { listeners.add(listener); } /** * Reads the SWF content from the stream passed to the constructor, and * invokes the methods of the registered listeners. Finally, the stream is * closed. * * @see SWFListener */ public void read() { preProcess(); SWFHeader header; try { header = new SWFHeader(bitStream); } catch (Exception e) { // invoke error processing processHeaderReadError(e); return; // without header we cannot do anything... } processHeader(header); do { // we check this because of an OpenOffice export bug // (END tag written as a UI8 (00)instead of an UI16 (00 00)) if ((header.getFileLength() - bitStream.getOffset()) < 2) { break; } TagHeader tagHeader = null; try { tagHeader = TagReaderImpl.getInstance().readTagHeader(bitStream); } catch (Exception e) { processTagHeaderReadError(e); break; // cannot continue without tag header } processTagHeader(tagHeader); Tag tag = null; byte[] tagData = null; try { tagData = TagReaderImpl.getInstance().readTagData(bitStream, tagHeader); tag = TagReaderImpl.getInstance().readTag( tagHeader, tagData, header.getVersion(), japanese); if (tag.getCode() == TagConstants.END) { break; } } catch (Exception e) { // invoke error processing if (processTagReadError(tagHeader, tagData, e)) { break; } tag = new MalformedTag(tagHeader, tagData, e); } processTag(tag, bitStream.getOffset()); } while (true); postProcess(); try { bitStream.close(); } catch (Exception e) { // empty on purpose - don't need to propagate errors which occur while closing } } protected void postProcess() { for (Iterator iterator = listeners.iterator(); iterator.hasNext();) { ((SWFListener) iterator.next()).postProcess(); } } protected void preProcess() { for (Iterator iterator = listeners.iterator(); iterator.hasNext();) { ((SWFListener) iterator.next()).preProcess(); } } protected void processHeader(SWFHeader header) { for (Iterator iterator = listeners.iterator(); iterator.hasNext();) { ((SWFListener) iterator.next()).processHeader(header); } } protected void processHeaderReadError(Exception e) { for (Iterator iterator = listeners.iterator(); iterator.hasNext();) { ((SWFListener) iterator.next()).processHeaderReadError(e); } } protected void processTag(Tag tag, long streamOffset) { for (Iterator iterator = listeners.iterator(); iterator.hasNext();) { ((SWFListener) iterator.next()).processTag(tag, streamOffset); } } protected void processTagHeader(TagHeader tagHeader) { for (Iterator iterator = listeners.iterator(); iterator.hasNext();) { ((SWFListener) iterator.next()).processTagHeader(tagHeader); } } protected void processTagHeaderReadError(Exception e) { for (Iterator iterator = listeners.iterator(); iterator.hasNext();) { ((SWFListener) iterator.next()).processTagHeaderReadError(e); } } protected boolean processTagReadError( TagHeader tagHeader, byte[] tagData, Exception e) { boolean result = false; for (Iterator iterator = listeners.iterator(); iterator.hasNext();) { result = ((SWFListener) iterator.next()).processTagReadError( tagHeader, tagData, e) || result; } return result; } }