blob: 4c35786475b777be463f511c6000176ad2b47779 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.royale.swf.io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.royale.abc.ABCParser;
import org.apache.royale.abc.PoolingABCVisitor;
import org.apache.royale.abc.print.ABCDumpVisitor;
import org.apache.royale.compiler.clients.problems.CompilerProblemCategorizer;
import org.apache.royale.compiler.clients.problems.ProblemFormatter;
import org.apache.royale.compiler.clients.problems.ProblemPrinter;
import org.apache.royale.compiler.clients.problems.ProblemQuery;
import org.apache.royale.compiler.clients.problems.WorkspaceProblemFormatter;
import org.apache.royale.compiler.common.VersionInfo;
import org.apache.royale.compiler.internal.workspaces.Workspace;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.swf.Header;
import org.apache.royale.swf.SWF;
import org.apache.royale.swf.SWFFrame;
import org.apache.royale.swf.TagType;
import org.apache.royale.swf.tags.*;
import org.apache.royale.swf.types.ButtonRecord;
import org.apache.royale.swf.types.CurvedEdgeRecord;
import org.apache.royale.swf.types.EdgeRecord;
import org.apache.royale.swf.types.FillStyle;
import org.apache.royale.swf.types.FillStyleArray;
import org.apache.royale.swf.types.Filter;
import org.apache.royale.swf.types.FocalGradient;
import org.apache.royale.swf.types.GlyphEntry;
import org.apache.royale.swf.types.GradRecord;
import org.apache.royale.swf.types.IFillStyle;
import org.apache.royale.swf.types.ILineStyle;
import org.apache.royale.swf.types.KerningRecord;
import org.apache.royale.swf.types.LineStyle;
import org.apache.royale.swf.types.LineStyle2;
import org.apache.royale.swf.types.LineStyleArray;
import org.apache.royale.swf.types.MorphFillStyle;
import org.apache.royale.swf.types.MorphGradRecord;
import org.apache.royale.swf.types.MorphLineStyle;
import org.apache.royale.swf.types.RGB;
import org.apache.royale.swf.types.RGBA;
import org.apache.royale.swf.types.Shape;
import org.apache.royale.swf.types.ShapeRecord;
import org.apache.royale.swf.types.ShapeWithStyle;
import org.apache.royale.swf.types.SoundEnvelope;
import org.apache.royale.swf.types.SoundInfo;
import org.apache.royale.swf.types.StraightEdgeRecord;
import org.apache.royale.swf.types.StyleChangeRecord;
import org.apache.royale.swf.types.Styles;
import org.apache.royale.swf.types.TextRecord;
import org.apache.royale.swf.types.ZoneRecord;
import org.apache.royale.utils.Base64;
import org.apache.royale.utils.Trace;
import com.google.common.collect.ImmutableList;
/**
* Dump a SWF model to XML. Usage: swfdump [-abc] file1.swf
*/
public final class SWFDump
{
/**
* Dump a SWF at a given URL.
*
* @param url URL of the SWF to dump.
* @throws IOException Any IO error ;-)
*/
public void dump(URL url) throws IOException
{
final SWFReader swfReader = new SWFReader();
final String path = url.getPath();
try
{
swf = (SWF)swfReader.readFrom(
new BufferedInputStream(url.openStream()),
path);
ProblemQuery problemQuery = new ProblemQuery();
problemQuery.addAll(swfReader.getProblems());
if (!problemQuery.hasErrors())
{
dumpHeader(swf.getHeader());
final ImmutableList<ITag> tags = ImmutableList.copyOf(swfReader.iterator());
currentFrameIndex = 0;
if (swf.getFrameCount() > 0)
currentFrame = swf.getFrameAt(0);
HashMap<String, ITag> abcTags = new HashMap<String, ITag>();
for (ITag tag : tags)
{
if (sortOption)
{
if (tag.getTagType() == TagType.DoABC)
{
DoABCTag abcTag = (DoABCTag)tag;
abcTags.put(abcTag.getName(), tag);
}
else if (tag.getTagType() == TagType.ShowFrame)
{
if (abcTags.size() > 0)
{
ArrayList<String> nameList = new ArrayList<String>();
nameList.addAll(abcTags.keySet());
Collections.sort(nameList);
for (String name : nameList)
{
ITag abcTag = abcTags.get(name);
dumpTag(abcTag);
}
}
dumpTag(tag);
abcTags = new HashMap<String, ITag>();
}
else
dumpTag(tag);
}
else
{
dumpTag(tag);
}
if (tag.getTagType() == TagType.ShowFrame)
{
currentFrameIndex++;
if (currentFrameIndex < swf.getFrameCount())
currentFrame = swf.getFrameAt(currentFrameIndex);
}
}
finish();
}
printProblems(swfReader.getProblems());
}
finally
{
IOUtils.closeQuietly(swfReader);
}
}
/**
* Print out problems to standard output.
*
* @param problems
*/
private void printProblems(Collection<ICompilerProblem> problems)
{
CompilerProblemCategorizer categorizer = new CompilerProblemCategorizer();
ProblemFormatter formatter = new WorkspaceProblemFormatter(new Workspace(),
categorizer);
ProblemPrinter printer = new ProblemPrinter(formatter, System.err);
printer.printProblems(problems);
}
/**
* Dump a tag.
*
* @param tag the tag to dump.
*/
private void dumpTag(ITag tag)
{
TagType type = tag.getTagType();
switch (type)
{
case CSMTextSettings:
dumpCSMTextSettings((CSMTextSettingsTag)tag);
break;
case DoABC:
dumpDoABC((DoABCTag)tag);
break;
case DefineBinaryData:
dumpDefineBinaryData((DefineBinaryDataTag)tag);
break;
case DefineBits:
dumpDefineBits((DefineBitsTag)tag);
break;
case DefineBitsJPEG2:
dumpDefineBitsJPEG2((DefineBitsTag)tag);
break;
case DefineBitsJPEG3:
dumpDefineBitsJPEG3((DefineBitsJPEG3Tag)tag);
break;
case DefineBitsLossless:
dumpDefineBitsLossless((DefineBitsLosslessTag)tag);
break;
case DefineBitsLossless2:
dumpDefineBitsLossless2((DefineBitsLossless2Tag)tag);
break;
case DefineScalingGrid:
dumpDefineScalingGrid((DefineScalingGridTag)tag);
break;
case DefineShape:
dumpDefineShape((DefineShapeTag)tag);
break;
case DefineShape2:
dumpDefineShape2((DefineShapeTag)tag);
break;
case DefineShape3:
dumpDefineShape3((DefineShape3Tag)tag);
break;
case DefineShape4:
dumpDefineShape4((DefineShape4Tag)tag);
break;
case DefineSprite:
dumpDefineSprite((DefineSpriteTag)tag);
break;
case DefineSound:
dumpDefineSound((DefineSoundTag)tag);
break;
case StartSound:
dumpStartSound((StartSoundTag)tag);
break;
case StartSound2:
// TODO StartSound2
// dumpStartSound2();
break;
case SoundStreamHead:
dumpSoundStreamHead((SoundStreamHeadTag)tag);
break;
case SoundStreamHead2:
dumpSoundStreamHead2((SoundStreamHeadTag)tag);
break;
case SoundStreamBlock:
dumpSoundStreamBlock((SoundStreamBlockTag)tag);
break;
case DefineMorphShape:
dumpDefineMorphShape((DefineMorphShapeTag)tag);
break;
case DefineMorphShape2:
dumpDefineMorphShape2((DefineMorphShapeTag)tag);
break;
case DefineSceneAndFrameLabelData:
// TODO: no dump routine for this tag.
//dumpDefineSceneAndFrameLabelData();
break;
case DefineFont:
dumpDefineFont((DefineFontTag)tag);
break;
case DefineFontInfo:
dumpDefineFontInfo((DefineFontInfoTag)tag);
break;
case DefineFont2:
dumpDefineFont2((DefineFont2Tag)tag);
break;
case DefineFont3:
dumpDefineFont3((DefineFont3Tag)tag);
break;
case DefineFont4:
dumpDefineFont4((DefineFont4Tag)tag);
break;
case DefineFontAlignZones:
dumpDefineFontAlignZones((DefineFontAlignZonesTag)tag);
break;
case DefineFontName:
dumpDefineFontName((DefineFontNameTag)tag);
break;
case DefineText:
dumpDefineText((DefineTextTag)tag);
break;
case DefineText2:
dumpDefineText((DefineTextTag)tag);
break;
case DefineEditText:
dumpDefineEditText((DefineEditTextTag)tag);
break;
case DefineButton:
dumpDefineButton((DefineButtonTag)tag);
break;
case DefineButton2:
dumpDefineButton2((DefineButton2Tag)tag);
break;
case DefineButtonSound:
dumpDefineButtonSound((DefineButtonSoundTag)tag);
break;
case DefineVideoStream:
dumpDefineVideoStream((DefineVideoStreamTag)tag);
break;
case VideoFrame:
dumpVideoFrame((VideoFrameTag)tag);
break;
case End:
break;
case EnableDebugger2:
dumpEnableDebugger2((EnableDebugger2Tag)tag);
break;
case ExportAssets:
dumpExportAssets((ExportAssetsTag)tag);
break;
case FileAttributes:
dumpFileAttributes((FileAttributesTag)tag);
break;
case FrameLabel:
dumpFrameLabel((FrameLabelTag)tag);
break;
case JPEGTables:
// TODO: handle this tag.
//dumpJPEGTables();
break;
case Metadata:
dumpMetadata((MetadataTag)tag);
break;
case ProductInfo:
dumpProductInfo((ProductInfoTag)tag);
break;
case PlaceObject:
dumpPlaceObject((PlaceObjectTag)tag);
break;
case PlaceObject2:
dumpPlaceObject2((PlaceObjectTag)tag);
break;
case PlaceObject3:
dumpPlaceObject3((PlaceObjectTag)tag);
break;
case RemoveObject:
dumpRemoveObject((RemoveObjectTag)tag);
break;
case RemoveObject2:
dumpRemoveObject2((RemoveObject2Tag)tag);
break;
case ScriptLimits:
dumpScriptLimits((ScriptLimitsTag)tag);
break;
case SetBackgroundColor:
dumpSetBackgroundColor((SetBackgroundColorTag)tag);
break;
case SetTabIndex:
dumpSetTabIndex((SetTabIndexTag)tag);
break;
case ShowFrame:
dumpShowFrame((ShowFrameTag)tag);
break;
case SymbolClass:
dumpSymbolClass((SymbolClassTag)tag);
break;
case EnableTelemetry:
dumpEnableTelemetry((EnableTelemetryTag) tag);
break;
default:
assert (tag instanceof RawTag);
if (tag instanceof RawTag) {
dumpRawTag((RawTag) tag);
}
break;
}
}
/**
* this value should get set after the header is parsed
*/
@SuppressWarnings("unused")
private Integer swfVersion = null;
private boolean abc = false;
private boolean verbose = false;
private boolean showActions = true;
private boolean showOffset = false;
@SuppressWarnings("unused")
private boolean showByteCode = false;
@SuppressWarnings("unused")
private boolean showDebugSource = false;
private boolean glyphs = true;
private boolean external = false;
private String externalPrefix = null;
private String externalDirectory = null;
@SuppressWarnings("unused")
private boolean decompile;
@SuppressWarnings("unused")
private boolean defunc;
private int indent = 0;
private boolean tabbedGlyphs = true;
private SWF swf;
/**
* Constructor.
*
* @param out The output stream.
*/
public SWFDump(PrintWriter out)
{
this.out = out;
}
// TODO: We currently don't decode actions.
// private void printActions(ActionList list)
// {
// if (decompile)
// {
// /*
// AsNode node;
// try
// {
// node = new Decompiler(defunc).decompile(list);
// new PrettyPrinter(out, indent).list(node);
// return;
// }
// catch (Exception e)
// {
// indent();
// out.println("// error while decompiling. falling back to disassembler");
// }
// */
// }
//
// Disassembler disassembler = new Disassembler(out, showOffset, indent);
// if (showDebugSource)
// {
// disassembler.setShowDebugSource(showDebugSource);
// disassembler.setComment("// ");
// }
// list.visitAll(disassembler);
// }
@SuppressWarnings("unused")
private void setExternal(boolean b, String path)
{
external = b;
if (external)
{
if (path != null)
{
externalPrefix = baseName(path);
externalDirectory = dirName(path);
}
if (externalPrefix == null)
externalPrefix = "";
else
externalPrefix += "-";
if (externalDirectory == null)
externalDirectory = "";
}
}
private void indent()
{
for (int i = 0; i < indent; i++)
{
out.print(" ");
}
}
public void dumpHeader(Header h)
{
swfVersion = h.getVersion();
out.println("<swf xmlns=\"http://macromedia/2003/swfx\"" +
" version=\"" + h.getVersion() + "\"" +
" framerate=\"" + h.getFrameRate() + "\"" +
" size=\"" + h.getFrameSize().getWidth() + "x" +
h.getFrameSize().getHeight() + "\"" +
" compressed=\"" + (h.getCompression() != Header.Compression.NONE) +
"\"" + " >");
indent++;
indent();
if (sortOption)
out.println("<!-- framecount=" + h.getFrameCount() + " length might be different because of debugfile paths -->");
else
out.println("<!-- framecount=" + h.getFrameCount() + " length=" + h.getLength() + " -->");
}
public void dumpProductInfo(ProductInfoTag productInfo)
{
open(productInfo);
out.print(" product=\"" + productInfo.getProduct() + "\"");
out.print(" edition=\"" + productInfo.getEdition() + "\"");
out.print(" version=\"" + productInfo.getMajorVersion() + "." +
productInfo.getMinorVersion() + "\"");
out.print(" build=\"" + productInfo.getBuild() + "\"");
out.print(" compileDate=\"" + DateFormat.getInstance().format(new Date(productInfo.getCompileDate())) + "\"");
close();
}
public void dumpMetadata(MetadataTag tag)
{
open(tag);
end();
indent();
openCDATA();
String metaData = tag.getMetadata();
if (sortOption)
{
metaData = metaData.replaceAll("build=\".*\"", "");
}
out.println(metaData);
closeCDATA();
close(tag);
}
public void dumpFileAttributes(FileAttributesTag tag)
{
open(tag);
out.print(" useDirectBlit=\"" + tag.isUseDirectBlit() + "\"");
out.print(" useGPU=\"" + tag.isUseGPU() + "\"");
out.print(" hasMetadata=\"" + tag.isHasMetadata() + "\"");
out.print(" actionScript3=\"" + tag.isAS3() + "\"");
out.print(" suppressCrossDomainCaching=\"" + tag.isSuppressCrossDomainCaching() + "\"");
out.print(" swfRelativeUrls=\"" + tag.isSWFRelativeURLs() + "\"");
out.print(" useNetwork=\"" + tag.isUseNetwork() + "\"");
close();
}
private final PrintWriter out;
private SWFFrame currentFrame;
private int currentFrameIndex;
/**
* Get the symbol name of a class.
*
* @param tag tag to look up.
* @return Name of tag in the symbol class table, null if not found.
*/
public String id(ICharacterTag tag)
{
return String.valueOf(tag.getCharacterID());
}
public void setOffsetAndSize(int offset, int size)
{
// Note: 'size' includes the size of the tag's header
// so it is either length + 2 or length + 6.
if (showOffset)
{
indent();
out.println("<!--" +
" offset=" + offset +
" size=" + size +
" -->");
}
}
/**
* Output the start of XML output for a SWF tag.
*
* @param tag the tag to output.
*/
private void open(ITag tag)
{
indent();
out.print("<" + tag.getTagType().toString());
}
/**
* Output the end of XML output for a SWF tag.
*
* @param tag the tag to output.
*/
private void end()
{
out.println(">");
indent++;
}
private void openCDATA()
{
indent();
out.print("<![CDATA[");
}
private void closeCDATA()
{
out.println("]]>");
}
private void close()
{
out.println("/>");
}
private void close(Tag tag)
{
indent--;
indent();
out.println("</" + tag.getTagType().toString() + ">");
}
public void error(String s)
{
indent();
out.println("<!-- error: " + s + " -->");
}
public void dumpRawTag(RawTag tag)
{
indent();
out.println("<!-- unknown tag=" + tag.getTagType().getValue() + " length=" +
(tag.getTagBody() != null ? tag.getTagBody().length : 0) + " -->");
}
public void dumpShowFrame(ShowFrameTag tag)
{
open(tag);
close();
}
public void dumpDefineShape(DefineShapeTag tag)
{
printDefineShape(tag);
}
private void printDefineShape(DefineShapeTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
out.print(" bounds=\"" + tag.getShapeBounds() + "\"");
if (tag.getTagType() == TagType.DefineShape4)
{
DefineShape4Tag shape4Tag = (DefineShape4Tag)tag;
out.print(" edgebounds=\"" + shape4Tag.getEdgeBounds() + "\"");
out.print(" usesNonScalingStrokes=\"" + shape4Tag.isUsesNonScalingStrokes() + "\"");
out.print(" usesScalingStrokes=\"" + shape4Tag.isUsesScalingStrokes() + "\"");
}
end();
printShapeWithStyles(tag.getShapes());
close(tag);
}
static final char[] digits = new char[] {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
/**
* @param color to print.
* @return string formatted as #RRGGBB
*/
public String printColor(RGB color)
{
StringBuilder b = new StringBuilder();
b.append('#');
int red = color.getRed();
b.append(digits[(red >> 4) & 15]);
b.append(digits[red & 15]);
int green = color.getGreen();
b.append(digits[(green >> 4) & 15]);
b.append(digits[green & 15]);
int blue = color.getBlue();
b.append(digits[(blue >> 4) & 15]);
b.append(digits[blue & 15]);
if (color instanceof RGBA)
{
int alpha = ((RGBA)color).getAlpha();
b.append(digits[(alpha >> 4) & 15]);
b.append(digits[alpha & 15]);
}
return b.toString();
}
public void dumpPlaceObject(PlaceObjectTag tag)
{
open(tag);
out.print(" idref=\"" + idRef(tag.getCharacter()) + "\"");
out.print(" depth=\"" + tag.getDepth() + "\"");
out.print(" matrix=\"" + tag.getMatrix() + "\"");
if (tag.getColorTransform() != null)
out.print(" colorXform=\"" + tag.getColorTransform() + "\"");
close();
}
public void dumpRemoveObject(RemoveObjectTag tag)
{
open(tag);
out.print(" idref=\"" + idRef(tag.getCharacter()) + "\"");
close();
}
public void outputBase64(byte[] data)
{
Base64.Encoder e = new Base64.Encoder(1024);
indent();
int remain = data.length;
while (remain > 0)
{
int block = 1024;
if (block > remain)
block = remain;
e.encode(data, data.length - remain, block);
out.print(e.drain());
remain -= block;
}
out.println(e.flush());
}
public void dumpDefineBits(DefineBitsTag tag)
{
if (tag.getData() == null)
{
out.println("<!-- warning: no JPEG table tag found. -->");
}
open(tag);
out.print(" id=\"" + id(tag) + "\"");
// if (external)
// {
// String path = externalDirectory
// + externalPrefix
// + "image"
// + dictionary.getId(tag)
// + ".jpg";
//
// out.println(" src=\"" + path + "\" />");
// try
// {
// FileOutputStream image = new FileOutputStream(path, false);
// SwfImageUtils.JPEG jpeg = new SwfImageUtils.JPEG(tag.jpegTables.data, tag.data);
// jpeg.write(image);
// image.close();
// }
// catch (IOException e)
// {
// out.println("<!-- error: unable to write external asset file " + path + "-->");
// }
// }
// else
{
out.print(" encoding=\"base64\"");
end();
outputBase64(tag.getData());
close(tag);
}
}
public void dumpDefineButton(DefineButtonTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
end();
if (showActions)
{
openCDATA();
// todo print button records
outputBase64(tag.getActions());
closeCDATA();
}
else
{
// TODO: dump out raw action bytes
// out.println("<!-- " + tag.condActions[0].actionList.size() + " action(s) elided -->");
}
close(tag);
}
public void dumpSetBackgroundColor(SetBackgroundColorTag tag)
{
open(tag);
out.print(" color=\"" + printColor(tag.getColor()) + "\"");
close();
}
public void dumpDefineFont(DefineFontTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
end();
if (glyphs)
{
for (int i = 0; i < tag.getGlyphShapeTable().length; i++)
{
indent();
out.println("<glyph>");
Shape shape = tag.getGlyphShapeTable()[i];
indent++;
printShapeWithTabs(shape);
indent--;
indent();
out.println("</glyph>");
}
}
close(tag);
}
public void dumpDefineText(DefineTextTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
out.print(" bounds=\"" + tag.getTextBounds() + "\"");
out.print(" matrix=\"" + tag.getTextMatrix() + "\"");
end();
for (TextRecord tr : tag.getTextRecords())
{
printTextRecord(tr, tag.getTagType().getValue());
}
close(tag);
}
// TODO: decode actions
// public void doAction(DoAction tag)
// {
// open(tag);
// end();
//
// if (showActions)
// {
// openCDATA();
// printActions(tag.actionList);
// closeCDATA();
// }
// else
// {
// out.println("<!-- " + tag.actionList.size() + " action(s) elided -->");
// }
// close(tag);
// }
public void dumpDefineFontInfo(DefineFontInfoTag tag)
{
open(tag);
out.print(" idref=\"" + idRef(tag.getFontTag()) + "\"");
out.print(" ansi=\"" + tag.isFontFlagsANSI() + "\"");
out.print(" italic=\"" + tag.isFontFlagsItalic() + "\"");
out.print(" bold=\"" + tag.isFontFlagsBold() + "\"");
out.print(" wideCodes=\"" + tag.isFontFlagsWideCodes() + "\"");
out.print(" smallText=\"" + tag.isFontFlagsSmallText() + "\"");
out.print(" name=\"" + escape(tag.getFontName()) + "\"");
out.print(" shiftJIS=\"" + tag.isFontFlagsShiftJIS() + "\"");
end();
indent();
int[] codeTable = tag.getCodeTable();
for (int i = 0; i < codeTable.length; i++)
{
out.print((int)codeTable[i]);
if ((i + 1) % 16 == 0)
{
out.println();
indent();
}
else
{
out.print(' ');
}
}
if (codeTable.length % 16 != 0)
{
out.println();
indent();
}
close(tag);
}
public void dumpDefineSound(DefineSoundTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
out.print(" format=\"" + tag.getSoundFormat() + "\"");
out.print(" rate=\"" + tag.getSoundRate() + "\"");
out.print(" size=\"" + tag.getSoundSize() + "\"");
out.print(" type=\"" + tag.getSoundType() + "\"");
out.print(" sampleCount=\"" + tag.getSoundSampleCount() + "\"");
out.print(" soundDataSize=\"" + tag.getSoundData().length + "\"");
end();
openCDATA();
outputBase64(tag.getSoundData());
closeCDATA();
close(tag);
}
public void dumpStartSound(StartSoundTag tag)
{
open(tag);
out.print(" soundid=\"" + idRef(tag.getSoundTag()) + "\"");
printSoundInfo(tag.getSoundInfo());
close(tag);
}
private void printSoundInfo(SoundInfo info)
{
out.print(" syncStop=\"" + info.isSyncStop() + "\"");
out.print(" syncNoMultiple=\"" + info.isSyncNoMultiple() + "\"");
if (info.getInPoint() != 0)
{
out.print(" inPoint=\"" + info.getInPoint() + "\"");
}
if (info.getOutPoint() != 0)
{
out.print(" outPoint=\"" + info.getOutPoint() + "\"");
}
if (info.getLoopCount() != 0)
{
out.print(" loopCount=\"" + info.getLoopCount() + "\"");
}
end();
SoundEnvelope[] envelopes = info.getEnvelopeRecords();
if (envelopes != null && envelopes.length > 0)
{
openCDATA();
for (int i = 0; i < envelopes.length; i++)
{
out.println("pos44 =\"" + envelopes[i].getPos44() + "\"");
out.println("left level =\"" + envelopes[i].getLeftLevel() + "\"");
out.println("right level=\"" + envelopes[i].getRightLevel() + "\"");
}
closeCDATA();
}
}
public void dumpDefineButtonSound(DefineButtonSoundTag tag)
{
open(tag);
out.print(" buttonId=\"" + idRef(tag.getButtonTag()) + "\"");
close();
}
public void dumpSoundStreamHead(SoundStreamHeadTag tag)
{
open(tag);
close();
}
public void dumpSoundStreamBlock(SoundStreamBlockTag tag)
{
open(tag);
close();
}
public void dumpDefineBinaryData(DefineBinaryDataTag tag)
{
open(tag);
out.println(" id=\"" + id(tag) + "\" length=\"" + tag.getData().length + "\" />");
}
public void dumpDefineBitsLossless(DefineBitsLosslessTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\" width=\"" + tag.getBitmapWidth() +
"\" height=\"" + tag.getBitmapHeight() + "\"");
if (external)
{
String path = externalDirectory
+ externalPrefix
+ "image"
+ id(tag)
+ ".bitmap";
out.println(" src=\"" + path + "\" />");
try
{
FileOutputStream image = new FileOutputStream(path, false);
image.write(tag.getData());
image.close();
}
catch (IOException e)
{
out.println("<!-- error: unable to write external asset file " + path + "-->");
}
}
else
{
out.print(" encoding=\"base64\"");
end();
outputBase64(tag.getData());
close(tag);
}
}
public void dumpDefineBitsJPEG2(DefineBitsTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
if (external)
{
String path = externalDirectory
+ externalPrefix
+ "image"
+ id(tag)
+ ".jpg";
out.println(" src=\"" + path + "\" />");
try
{
FileOutputStream image = new FileOutputStream(path, false);
image.write(tag.getData());
image.close();
}
catch (IOException e)
{
out.println("<!-- error: unable to write external asset file " + path + "-->");
}
}
else
{
out.print(" encoding=\"base64\"");
end();
outputBase64(tag.getData());
close(tag);
}
}
public void dumpDefineShape2(DefineShapeTag tag)
{
printDefineShape(tag);
}
public void dumpDefineButtonCxform(DefineButtonCxformTag tag)
{
open(tag);
out.print(" buttonId=\"" + idRef(tag.getButtonTag()) + "\"");
close();
}
// TODO: Handle the Protect Tag
// public void protect(GenericTag tag)
// {
// open(tag);
// if (tag.data != null)
// out.print(" password=\"" + hexify(tag.data) + "\"");
// close();
// }
public void dumpPlaceObject2(PlaceObjectTag tag)
{
dumpPlaceObject23(tag);
}
public void dumpPlaceObject3(PlaceObjectTag tag)
{
dumpPlaceObject23(tag);
}
public void dumpPlaceObject23(PlaceObjectTag tag)
{
PlaceObject2Tag tag2 = tag instanceof PlaceObject2Tag ? (PlaceObject2Tag)tag : null;
PlaceObject3Tag tag3 = tag instanceof PlaceObject3Tag ? (PlaceObject3Tag)tag : null;
if (tag != null || (tag2 != null && tag2.isHasCharacter()))
{
if (tag.getCharacter() != null && currentFrame != null &&
currentFrame.getSymbolName(tag.getCharacter()) != null)
{
indent();
out.println("<!-- instance of " + idRef(tag.getCharacter()) + " -->");
}
}
open(tag);
if (tag3 != null && tag3.isHasClassName())
out.print(" className=\"" + tag3.getClassName() + "\"");
if (tag3 != null && tag3.isHasImage())
out.print(" hasImage=\"true\" ");
if (tag != null || (tag2 != null && tag2.isHasCharacter()))
out.print(" idref=\"" + idRef(tag.getCharacter()) + "\"");
if (tag2 != null && tag2.isHasName())
out.print(" name=\"" + tag2.getName() + "\"");
out.print(" depth=\"" + tag.getDepth() + "\"");
if (tag2 != null && tag2.isHasClipDepth())
out.print(" clipDepth=\"" + tag2.getClipDepth() + "\"");
if (tag3 != null && tag3.isHasCacheAsBitmap())
out.print(" cacheAsBitmap=\"true\"");
if (tag2 != null && tag2.isHasRatio())
out.print(" ratio=\"" + tag2.getRatio() + "\"");
if (tag2 != null && tag2.isHasColorTransform())
out.print(" cxform=\"" + tag2.getColorTransform() + "\"");
else if (tag.getColorTransform() != null)
out.print(" cxform=\"" + tag.getColorTransform() + "\"");
if (tag.getMatrix() != null || (tag2 != null && tag2.isHasMatrix()))
out.print(" matrix=\"" + tag.getMatrix() + "\"");
if (tag3 != null && tag3.isHasBlendMode())
out.print(" blendmode=\"" + tag3.getBlendMode() + "\"");
if (tag3 != null && tag3.isHasFilterList())
{
// todo - pretty print this once we actually care
out.print(" filters=\"");
for (Filter filter : tag3.getSurfaceFilterList())
{
out.print(filter.getFilterID() + " ");
}
out.print("\"");
}
// TODO: decode clip actions
// if (tag3 != null && tag3.isHasClipActions())
// {
// end();
// Iterator it = tag.clipActions.clipActionRecords.iterator();
//
// openCDATA();
// for (ClipActions )
// {
// ClipActionRecord record = (ClipActionRecord)it.next();
// indent();
// out.println("onClipEvent(" + printClipEventFlags(record.eventFlags) +
// (record.hasKeyPress() ? "<" + record.keyCode + ">" : "") +
// ") {");
// indent++;
// if (showActions)
// {
// printActions(record.actionList);
// }
// else
// {
// indent();
// out.println("// " + record.actionList.size() + " action(s) elided");
// }
// indent--;
// indent();
// out.println("}");
// }
// closeCDATA();
// close(tag);
// }
// else
{
close();
}
}
public void dumpRemoveObject2(RemoveObject2Tag tag)
{
open(tag);
out.print(" depth=\"" + tag.getDepth() + "\"");
close();
}
public void dumpDefineShape3(DefineShape3Tag tag)
{
printDefineShape(tag);
}
public void dumpDefineShape4(DefineShape4Tag tag)
{
printDefineShape(tag);
}
private void printShapeWithStyles(ShapeWithStyle shapes)
{
printFillStyles(shapes.getFillStyles());
printLineStyles(shapes.getLineStyles());
printShape(shapes);
}
@SuppressWarnings("unused")
private void printMorphLineStyles(MorphLineStyle[] lineStyles)
{
for (int i = 0; i < lineStyles.length; i++)
{
MorphLineStyle lineStyle = lineStyles[i];
indent();
out.print("<linestyle ");
out.print("startColor=\"" + printColor(lineStyle.getStartColor()) + "\" ");
out.print("endColor=\"" + printColor(lineStyle.getStartColor()) + "\" ");
out.print("startWidth=\"" + lineStyle.getStartWidth() + "\" ");
out.print("endWidth=\"" + lineStyle.getEndWidth() + "\" ");
out.println("/>");
}
}
private void printLineStyles(LineStyleArray linestyles)
{
for (ILineStyle lineStyle : linestyles)
{
indent();
out.print("<linestyle ");
if (lineStyle instanceof LineStyle)
{
LineStyle ls = (LineStyle)lineStyle;
String color = printColor(ls.getColor());
out.print("color=\"" + color + "\" ");
out.print("width=\"" + ls.getWidth() + "\" ");
}
if (lineStyle instanceof LineStyle2)
{
LineStyle2 lineStyle2 = (LineStyle2)lineStyle;
if (lineStyle2.getJoinStyle() == LineStyle2.JS_MITER_JOIN)
{
out.print("miterLimit=\"" + lineStyle2.getMiterLimitFactor() + "\" ");
}
if (lineStyle2.isHasFillFlag())
{
out.println(">");
indent();
FillStyleArray fillStyles = new FillStyleArray(1);
fillStyles.add(lineStyle2.getFillType());
printFillStyles(fillStyles);
indent();
out.println("</linestyle>");
}
else
{
out.println("/>");
}
}
else
{
out.println("/>");
}
}
}
private void printFillStyles(FillStyleArray fillstyles)
{
for (IFillStyle iFillStyle : fillstyles)
{
indent();
out.print("<fillstyle");
int fillStyleType;
FillStyle fillStyle = (FillStyle)iFillStyle;
fillStyleType = fillStyle.getFillStyleType();
out.print(" type=\"" + fillStyleType + "\"");
if (fillStyleType == FillStyle.SOLID_FILL)
{
out.print(" color=\"" + printColor(fillStyle.getColor()) + "\"");
}
if ((fillStyleType & FillStyle.LINEAR_GRADIENT_FILL) != 0)
{
if (fillStyleType == FillStyle.RADIAL_GRADIENT_FILL)
out.print(" typeName=\"radial\"");
else if (fillStyleType == FillStyle.FOCAL_RADIAL_GRADIENT_FILL)
out.print(" typeName=\"focal\" focalPoint=\"" +
((FocalGradient)fillStyle.getGradient()).getFocalPoint() + "\"");
// todo print linear or radial or focal
out.print(" gradient=\"" + formatGradient(fillStyle.getGradient().getGradientRecords()) + "\"");
out.print(" matrix=\"" + fillStyle.getGradientMatrix() + "\"");
}
if ((fillStyleType & FillStyle.REPEATING_BITMAP_FILL) != 0)
{
// todo print tiled or clipped
out.print(" idref=\"" + idRef(fillStyle.getBitmapCharacter()) + "\"");
out.print(" matrix=\"" + fillStyle.getBitmapMatrix() + "\"");
}
out.println(" />");
}
}
@SuppressWarnings("unused")
private void printMorphFillStyles(MorphFillStyle[] fillStyles)
{
for (int i = 0; i < fillStyles.length; i++)
{
MorphFillStyle fillStyle = fillStyles[i];
indent();
out.print("<fillstyle");
out.print(" type=\"" + fillStyle.getFillStyleType() + "\"");
if (fillStyle.getFillStyleType() == FillStyle.SOLID_FILL)
{
out.print(" startColor=\"" + printColor(fillStyle.getStartColor()) + "\"");
out.print(" endColor=\"" + printColor(fillStyle.getEndColor()) + "\"");
}
if ((fillStyle.getFillStyleType() & FillStyle.LINEAR_GRADIENT_FILL) != 0)
{
// todo print linear or radial
out.print(" gradient=\"" + formatMorphGradient(
fillStyle.getGradient().toArray(new MorphGradRecord[0])) + "\"");
out.print(" startMatrix=\"" + fillStyle.getStartGradientMatrix() + "\"");
out.print(" endMatrix=\"" + fillStyle.getEndGradientMatrix() + "\"");
if (fillStyle.getFillStyleType() == FillStyle.FOCAL_RADIAL_GRADIENT_FILL)
{
out.print(" ratio1 =\"" + fillStyle.getRatio1());
out.print(" ratio2 =\"" + fillStyle.getRatio2());
}
}
if ((fillStyle.getFillStyleType() & FillStyle.REPEATING_BITMAP_FILL) != 0)
{
// todo print tiled or clipped
out.print(" idref=\"" + idRef(fillStyle.getBitmap()) + "\"");
out.print(" startMatrix=\"" + fillStyle.getStartBitmapMatrix() + "\"");
out.print(" endMatrix=\"" + fillStyle.getEndBitmapMatrix() + "\"");
}
out.println(" />");
}
}
private String formatGradient(List<GradRecord> records)
{
StringBuilder b = new StringBuilder();
int i = 0;
for (GradRecord record : records)
{
b.append(record.getRatio());
b.append(' ');
b.append(printColor(record.getColor()));
if (i + 1 < records.size())
b.append(' ');
i++;
}
return b.toString();
}
private String formatMorphGradient(MorphGradRecord[] records)
{
StringBuilder b = new StringBuilder();
for (int i = 0; i < records.length; i++)
{
b.append(records[i].getStartRatio());
b.append(',');
b.append(records[i].getEndRatio());
b.append(' ');
b.append(printColor(records[i].getStartColor()));
b.append(',');
b.append(printColor(records[i].getEndColor()));
if (i + 1 < records.length)
b.append(' ');
}
return b.toString();
}
private void printShape(Shape shapes)
{
if (shapes == null)
return;
Styles styles = null;
if (shapes instanceof ShapeWithStyle)
{
styles = new Styles(((ShapeWithStyle)shapes).getFillStyles(),
((ShapeWithStyle)shapes).getLineStyles());
}
for (ShapeRecord shape : shapes.getShapeRecords())
{
indent();
if (shape instanceof StyleChangeRecord)
{
StyleChangeRecord styleChange = (StyleChangeRecord)shape;
out.print("<styleChange ");
if (styleChange.isStateMoveTo())
{
out.print("dx=\"" + styleChange.getMoveDeltaX() + "\" dy=\"" +
styleChange.getMoveDeltaY() + "\" ");
}
if (styleChange.isStateFillStyle0())
{
out.print("fillStyle0=\"" +
(styles.getFillStyles().indexOf(styleChange.getFillstyle0()) + 1) + "\" ");
}
if (styleChange.isStateFillStyle1())
{
out.print("fillStyle1=\"" +
(styles.getFillStyles().indexOf(styleChange.getFillstyle1()) + 1) + "\" ");
}
if (styleChange.isStateLineStyle())
{
out.print("lineStyle=\"" +
(styles.getFillStyles().indexOf(styleChange.getLinestyle()) + 1) + "\" ");
}
if (styleChange.isStateNewStyles())
{
out.println(">");
indent++;
printFillStyles(styleChange.getStyles().getFillStyles());
printLineStyles(styleChange.getStyles().getLineStyles());
indent--;
indent();
out.println("</styleChange>");
styles = styleChange.getStyles();
}
else
{
out.println("/>");
}
}
else
{
EdgeRecord edge = (EdgeRecord)shape;
if (edge instanceof StraightEdgeRecord)
{
StraightEdgeRecord straightEdge = (StraightEdgeRecord)edge;
out.println("<line dx=\"" + straightEdge.getDeltaX() + "\" dy=\"" +
straightEdge.getDeltaY() + "\" />");
}
else
{
CurvedEdgeRecord curvedEdge = (CurvedEdgeRecord)edge;
out.print("<curve ");
out.print("cdx=\"" + curvedEdge.getControlDeltaX() + "\" cdy=\"" +
curvedEdge.getControlDeltaY() + "\" ");
out.print("dx=\"" + curvedEdge.getAnchorDeltaX() + "\" dy=\"" +
curvedEdge.getAnchorDeltaY() + "\" ");
out.println("/>");
}
}
}
}
private void printShapeWithTabs(Shape shapes)
{
if (shapes == null)
return;
int startX = 0;
int startY = 0;
int x = 0;
int y = 0;
for (ShapeRecord shape : shapes.getShapeRecords())
{
indent();
if (shape instanceof StyleChangeRecord)
{
StyleChangeRecord styleChange = (StyleChangeRecord)shape;
// No longer print out number of bits in MoveDeltaX and
// MoveDeltaY. The StyleChangeRecord record does not preserve
// this information.
out.print("SCR\t");
if (styleChange.isStateMoveTo())
{
out.print(styleChange.getMoveDeltaX() + "\t" + styleChange.getMoveDeltaY());
if (startX == 0 && startY == 0)
{
startX = styleChange.getMoveDeltaX();
startY = styleChange.getMoveDeltaY();
}
x = styleChange.getMoveDeltaX();
y = styleChange.getMoveDeltaY();
out.print("\t\t");
}
}
else
{
EdgeRecord edge = (EdgeRecord)shape;
if (edge instanceof StraightEdgeRecord)
{
StraightEdgeRecord straightEdge = (StraightEdgeRecord)edge;
out.print("SER" + "\t");
out.print(straightEdge.getDeltaX() + "\t" + straightEdge.getDeltaY());
x += straightEdge.getDeltaX();
y += straightEdge.getDeltaY();
out.print("\t\t");
}
else
{
CurvedEdgeRecord curvedEdge = (CurvedEdgeRecord)edge;
out.print("CER" + "\t");
out.print(curvedEdge.getControlDeltaX() + "\t" + curvedEdge.getControlDeltaY() + "\t");
out.print(curvedEdge.getAnchorDeltaX() + "\t" + curvedEdge.getAnchorDeltaY());
x += (curvedEdge.getControlDeltaX() + curvedEdge.getAnchorDeltaX());
y += (curvedEdge.getControlDeltaY() + curvedEdge.getAnchorDeltaY());
}
}
out.println("\t\t" + x + "\t" + y);
}
}
// TODO: decode ClipActionRecords
// private String printClipEventFlags(int flags)
// {
// StringBuilder b = new StringBuilder();
//
// if ((flags & ClipActionRecord.unused31) != 0) b.append("res31,");
// if ((flags & ClipActionRecord.unused30) != 0) b.append("res30,");
// if ((flags & ClipActionRecord.unused29) != 0) b.append("res29,");
// if ((flags & ClipActionRecord.unused28) != 0) b.append("res28,");
// if ((flags & ClipActionRecord.unused27) != 0) b.append("res27,");
// if ((flags & ClipActionRecord.unused26) != 0) b.append("res26,");
// if ((flags & ClipActionRecord.unused25) != 0) b.append("res25,");
// if ((flags & ClipActionRecord.unused24) != 0) b.append("res24,");
//
// if ((flags & ClipActionRecord.unused23) != 0) b.append("res23,");
// if ((flags & ClipActionRecord.unused22) != 0) b.append("res22,");
// if ((flags & ClipActionRecord.unused21) != 0) b.append("res21,");
// if ((flags & ClipActionRecord.unused20) != 0) b.append("res20,");
// if ((flags & ClipActionRecord.unused19) != 0) b.append("res19,");
// if ((flags & ClipActionRecord.construct) != 0) b.append("construct,");
// if ((flags & ClipActionRecord.keyPress) != 0) b.append("keyPress,");
// if ((flags & ClipActionRecord.dragOut) != 0) b.append("dragOut,");
//
// if ((flags & ClipActionRecord.dragOver) != 0) b.append("dragOver,");
// if ((flags & ClipActionRecord.rollOut) != 0) b.append("rollOut,");
// if ((flags & ClipActionRecord.rollOver) != 0) b.append("rollOver,");
// if ((flags & ClipActionRecord.releaseOutside) != 0) b.append("releaseOutside,");
// if ((flags & ClipActionRecord.release) != 0) b.append("release,");
// if ((flags & ClipActionRecord.press) != 0) b.append("press,");
// if ((flags & ClipActionRecord.initialize) != 0) b.append("initialize,");
// if ((flags & ClipActionRecord.data) != 0) b.append("data,");
//
// if ((flags & ClipActionRecord.keyUp) != 0) b.append("keyUp,");
// if ((flags & ClipActionRecord.keyDown) != 0) b.append("keyDown,");
// if ((flags & ClipActionRecord.mouseUp) != 0) b.append("mouseUp,");
// if ((flags & ClipActionRecord.mouseDown) != 0) b.append("mouseDown,");
// if ((flags & ClipActionRecord.mouseMove) != 0) b.append("moseMove,");
// if ((flags & ClipActionRecord.unload) != 0) b.append("unload,");
// if ((flags & ClipActionRecord.enterFrame) != 0) b.append("enterFrame,");
// if ((flags & ClipActionRecord.load) != 0) b.append("load,");
// if (b.length() > 1)
// {
// b.setLength(b.length() - 1);
// }
// return b.toString();
// }
public void defineText2(DefineTextTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
end();
for (TextRecord tr : tag.getTextRecords())
{
printTextRecord(tr, tag.getTagType().getValue());
}
close(tag);
}
public void printTextRecord(TextRecord tr, int tagCode)
{
indent();
out.print("<textRecord ");
if (tr.isStyleFlagsHasFont())
{
out.print(" font=\"" + id(tr.getFontTag()) + "\"");
out.print(" height=\"" + tr.getTextHeight() + "\"");
}
if (tr.isStyleFlagsHasXOffset())
out.print(" xOffset=\"" + tr.getxOffset() + "\"");
if (tr.isStyleFlagsHasYOffset())
out.print(" yOffset=\"" + tr.getyOffset() + "\"");
if (tr.isStyleFlagsHasColor())
out.print(" color=\"" + printColor(tr.getTextColor()) + "\"");
out.println(">");
indent++;
printGlyphEntries(tr);
indent--;
indent();
out.println("</textRecord>");
}
private void printGlyphEntries(TextRecord tr)
{
indent();
GlyphEntry[] entries = tr.getGlyphEntries();
for (int i = 0; i < entries.length; i++)
{
GlyphEntry ge = entries[i];
out.print(ge.getGlyphIndex());
if (ge.getGlyphAdvance() >= 0)
out.print('+');
out.print(ge.getGlyphAdvance());
out.print(' ');
if ((i + 1) % 10 == 0)
{
out.println();
indent();
}
}
if (entries.length % 10 != 0)
out.println();
}
public void dumpDefineButton2(DefineButton2Tag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
out.print(" trackAsMenu=\"" + tag.isTrackAsMenu() + "\"");
end();
for (int i = 0; i < tag.getCharacters().length; i++)
{
ButtonRecord record = tag.getCharacters()[i];
indent();
out.println("<buttonRecord " +
"idref=\"" + record.getCharacterID() + "\" " + //TODO: print symbol name
"depth=\"" + record.getPlaceDepth() + "\" " +
"matrix=\"" + record.getPlaceMatrix() + "\" " +
"stateHitTest=\"" + record.isStateHitTest() + "\" " +
"stateDown=\"" + record.isStateDown() + "\" " +
"stateOver=\"" + record.isStateOver() + "\" " +
"stateUp=\"" + record.isStateUp() + "\" " +
"/>");
// todo print optional cxforma
}
// print conditional actions
// TODO: print actions
// if (tag.condActions.length > 0 && showActions)
// {
// indent();
// out.println("<buttonCondAction>");
// openCDATA();
// for (int i = 0; i < tag.condActions.length; i++)
// {
// ButtonCondAction cond = tag.condActions[i];
// indent();
// out.println("on(" + cond + ") {");
// indent++;
// printActions(cond.actionList);
// indent--;
// indent();
// out.println("}");
// }
// closeCDATA();
// indent();
// out.println("</buttonCondAction>");
// }
close(tag);
}
public void dumpDefineBitsJPEG3(DefineBitsJPEG3Tag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
// TODO: We don't have a JEB encoder
// if (external)
// {
// String path = externalDirectory
// + externalPrefix
// + "image"
// + id(tag)
// + ".jpg";
//
// out.println(" src=\"" + path + "\" />");
//
// try
// {
// FileOutputStream image = new FileOutputStream(path, false);
// SwfImageUtils.JPEG jpeg = null;
//
// if (tag.jpegTables != null)
// {
// jpeg = new SwfImageUtils.JPEG(tag.jpegTables.data, tag.data);
// }
// else
// {
// jpeg = new SwfImageUtils.JPEG(tag.data, true);
// }
//
// jpeg.write(image);
// image.close();
// }
// catch (IOException e)
// {
// out.println("<!-- error: unable to write external asset file " + path + "-->");
// }
// }
// else
{
out.print(" encoding=\"base64\"");
end();
outputBase64(tag.getData());
close(tag);
}
}
public void dumpDefineBitsLossless2(DefineBitsLossless2Tag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
if (external)
{
String path = externalDirectory
+ externalPrefix
+ "image"
+ id(tag)
+ ".bitmap";
out.println(" src=\"" + path + "\" />");
try
{
FileOutputStream image = new FileOutputStream(path, false);
image.write(tag.getData());
image.close();
}
catch (IOException e)
{
out.println("<!-- error: unable to write external asset file " + path + "-->");
}
}
else
{
out.print(" encoding=\"base64\"");
end();
outputBase64(tag.getData());
close(tag);
}
}
String escape(String s)
{
if (s == null)
return null;
StringBuilder b = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i);
switch (c)
{
case '<':
b.append("&lt;");
break;
case '>':
b.append("&gt;");
break;
case '&':
b.append("&amp;");
break;
case '"':
b.append("&quot;");
break;
default:
{
// Non-printable low ASCII characters are invalid in XML
if ((c >= 0 && c <= 8)
|| (c >= 11 && c <= 12)
|| (c >= 14 && c <= 31))
{
b.append("?");
}
else
{
b.append(c);
}
}
}
}
return b.toString();
}
public void dumpDefineEditText(DefineEditTextTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
if (tag.isHasFont())
{
out.print(" fontId=\"" + id(tag.getFontTag()) + "\"");
out.print(" fontName=\"" + escape(idRef(tag.getFontTag())) + "\"");
out.print(" fontHeight=\"" + tag.getFontHeight() + "\"");
}
else if (tag.isHasFontClass())
{
out.print(" fontClass=\"" + tag.getFontClass() + "\"");
out.print(" fontHeight=\"" + tag.getFontHeight() + "\"");
}
out.print(" bounds=\"" + tag.getBounds() + "\"");
if (tag.isHasTextColor())
out.print(" color=\"" + printColor(tag.getTextColor()) + "\"");
out.print(" html=\"" + tag.isHtml() + "\"");
out.print(" autoSize=\"" + tag.isAutoSize() + "\"");
out.print(" border=\"" + tag.isBorder() + "\"");
if (tag.isHasMaxLength())
out.print(" maxLength=\"" + tag.getMaxLength() + "\"");
out.print(" multiline=\"" + tag.isMultiline() + "\"");
out.print(" noSelect=\"" + tag.isNoSelect() + "\"");
out.print(" password=\"" + tag.isPassword() + "\"");
out.print(" readOnly=\"" + tag.isReadOnly() + "\"");
out.print(" useOutlines=\"" + tag.isUseOutlines() + "\"");
out.print(" varName=\"" + escape(tag.getVariableName()) + "\"");
out.print(" wordWrap=\"" + tag.isWordWrap() + "\"");
if (tag.isHasLayout())
{
out.print(" align=\"" + tag.getAlign() + "\"");
out.print(" indent=\"" + tag.getIndent() + "\"");
out.print(" leading=\"" + tag.getLeading() + "\"");
out.print(" leftMargin=\"" + tag.getLeftMargin() + "\"");
out.print(" rightMargin=\"" + tag.getRightMargin() + "\"");
}
end();
if (tag.isHasText())
{
indent();
out.println("<text>");
openCDATA();
out.print(tag.getInitialText());
closeCDATA();
indent();
out.println("</text>");
}
close(tag);
}
public void dumpDefineSprite(DefineSpriteTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
end();
indent();
out.println("<!-- sprite framecount=" + tag.getFrameCount() + " -->");
// Dump list of nested tags in the sprite.
for (ITag controlTag : tag.getControlTags())
dumpTag(controlTag);
close(tag);
}
public void finish()
{
--indent;
indent();
out.println("</swf>");
}
public void dumpFrameLabel(FrameLabelTag tag)
{
open(tag);
out.print(" label=\"" + tag.getName() + "\"");
if (tag.isNamedAnchorTag())
out.print(" anchor=\"" + "true" + "\"");
close();
}
public void dumpSoundStreamHead2(SoundStreamHeadTag tag)
{
open(tag);
out.print(" playbackRate=\"" + tag.getPlaybackSoundRate() + "\"");
out.print(" playbackSize=\"" + tag.getPlaybackSoundSize() + "\"");
out.print(" playbackType=\"" + tag.getPlaybackSoundType() + "\"");
out.print(" compression=\"" + tag.getStreamSoundCompression() + "\"");
out.print(" streamRate=\"" + tag.getStreamSoundRate() + "\"");
out.print(" streamSize=\"" + tag.getStreamSoundSize() + "\"");
out.print(" streamType=\"" + tag.getStreamSoundRate() + "\"");
out.print(" streamSampleCount=\"" + tag.getStreamSoundSampleCount() + "\"");
if (tag.getStreamSoundCompression() == 2)
{
out.print(" latencySeek=\"" + tag.getLatencySeek() + "\"");
}
close();
}
public void dumpDefineScalingGrid(DefineScalingGridTag tag)
{
open(tag);
out.print(" idref=\"" + id(tag.getCharacter()) + "\"");
out.print(" grid=\"" + tag.getSplitter() + "\"");
close();
}
public void dumpDefineMorphShape(DefineMorphShapeTag tag)
{
dumpDefineMorphShape2(tag);
}
public void dumpDefineMorphShape2(DefineMorphShapeTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
out.print(" startBounds=\"" + tag.getStartBounds() + "\"");
out.print(" endBounds=\"" + tag.getEndBounds() + "\"");
if (tag.getTagType() == TagType.DefineMorphShape2)
{
DefineMorphShape2Tag tag2 = (DefineMorphShape2Tag)tag;
out.print(" startEdgeBounds=\"" + tag2.getStartEdgeBounds() + "\"");
out.print(" endEdgeBounds=\"" + tag2.getEndEdgeBounds() + "\"");
out.print(" usesNonScalingStrokes=\"" + tag2.isUsesNonScalingStrokes() + "\"");
out.print(" usesScalingStrokes=\"" + tag2.isUsesScalingStrokes() + "\"");
}
end();
// TODO: dump line styles and fill styles
// printMorphLineStyles(tag.lineStyles);
// printMorphFillStyles(tag.fillStyles);
indent();
out.println("<start>");
indent++;
printShape(tag.getStartEdges());
indent--;
indent();
out.println("</start>");
indent();
out.println("<end>");
indent++;
printShape(tag.getEndEdges());
indent--;
indent();
out.println("</end>");
close(tag);
}
public void dumpDefineFont2(DefineFont2Tag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
out.print(" font=\"" + escape(tag.getFontName()) + "\"");
out.print(" numGlyphs=\"" + tag.getNumGlyphs() + "\"");
out.print(" italic=\"" + tag.isFontFlagsItalic() + "\"");
out.print(" bold=\"" + tag.isFontFlagsBold() + "\"");
out.print(" ansi=\"" + tag.isFontFlagsANSI() + "\"");
out.print(" wideOffsets=\"" + tag.isFontFlagsWideCodes() + "\"");
out.print(" wideCodes=\"" + tag.isFontFlagsWideCodes() + "\"");
out.print(" shiftJIS=\"" + tag.isFontFlagsShiftJIS() + "\"");
out.print(" langCode=\"" + tag.getLanguageCode() + "\"");
out.print(" hasLayout=\"" + tag.isFontFlagsHasLayout() + "\"");
out.print(" ascent=\"" + tag.getFontAscent() + "\"");
out.print(" descent=\"" + tag.getFontDescent() + "\"");
out.print(" leading=\"" + tag.getFontLeading() + "\"");
out.print(" kerningCount=\"" + tag.getKerningCount() + "\"");
out.print(" codepointCount=\"" + tag.getCodeTable().length + "\"");
if (tag.isFontFlagsHasLayout())
{
out.print(" advanceCount=\"" + tag.getFontAdvanceTable().length + "\"");
out.print(" boundsCount=\"" + tag.getFontBoundsTable().length + "\"");
}
end();
if (glyphs && tag.isFontFlagsHasLayout())
{
for (int i = 0; i < tag.getFontKerningTable().length; i++)
{
KerningRecord rec = tag.getFontKerningTable()[i];
indent();
out.println("<kerningRecord adjustment=\"" + rec.getAdjustment() +
"\" code1=\"" + rec.getCode1() + "\" code2=\"" + rec.getCode2() + "\" />");
}
for (int i = 0; i < tag.getGlyphShapeTable().length; i++)
{
indent();
out.print("<glyph");
out.print(" codepoint=\"" + (tag.getCodeTable()[i]) +
(isPrintable((char)tag.getCodeTable()[i]) ? escape(("(" + (char)tag.getCodeTable()[i] + ")")) : "(?)") + "\"");
if (tag.isFontFlagsHasLayout())
{
out.print(" advance=\"" + tag.getFontAdvanceTable()[i] + "\"");
out.print(" bounds=\"" + tag.getFontBoundsTable()[i] + "\"");
}
out.println(">");
Shape shape = tag.getGlyphShapeTable()[i];
indent++;
if (tabbedGlyphs)
printShapeWithTabs(shape);
else
printShape(shape);
indent--;
indent();
out.println("</glyph>");
}
}
close(tag);
}
public void dumpDefineFont3(DefineFont3Tag tag)
{
dumpDefineFont2(tag);
}
public void dumpDefineFont4(DefineFont4Tag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
out.print(" font=\"" + escape(tag.getFontName()) + "\"");
out.print(" hasFontData=\"" + tag.isFontFlagsHasFontData() + "\"");
out.print(" italic=\"" + tag.isFontFlagsItalic() + "\"");
out.print(" bold=\"" + tag.isFontFlagsBold() + "\"");
end();
if (glyphs && tag.isFontFlagsHasFontData())
{
outputBase64(tag.getFontData());
}
close(tag);
}
public void dumpDefineFontAlignZones(DefineFontAlignZonesTag tag)
{
open(tag);
out.print(" fontID=\"" + id(tag.getFontTag()) + "\"");
out.print(" CSMTableHint=\"" + tag.getCsmTableHint() + "\"");
out.println(">");
indent++;
indent();
out.println("<ZoneTable length=\"" + tag.getZoneTable().length + "\">");
indent++;
if (glyphs)
{
for (int i = 0; i < tag.getZoneTable().length; i++)
{
ZoneRecord record = tag.getZoneTable()[i];
indent();
out.print("<ZoneRecord num=\"" + record.getNumZoneData() +
"\" maskX=\"" + record.isZoneMaskX() +
"\" maskY=\"" + record.isZoneMaskY() +
"\">");
out.print(record.getZoneData0().getData() + " " +
record.getZoneData1().getData() + " ");
out.println("</ZoneRecord>");
}
}
indent--;
indent();
out.println("</ZoneTable>");
close(tag);
}
public void dumpCSMTextSettings(CSMTextSettingsTag tag)
{
open(tag);
String textID = tag.getTextTag() == null ? "0" : id(tag.getTextTag());
out.print(" textID=\"" + textID + "\"");
out.print(" useFlashType=\"" + tag.getUseFlashType() + "\"");
out.print(" gridFitType=\"" + tag.getGridFit() + "\"");
out.print(" thickness=\"" + tag.getThickness() + "\"");
out.print(" sharpness=\"" + tag.getSharpness() + "\"");
close();
}
public void dumpDefineFontName(DefineFontNameTag tag)
{
open(tag);
out.print(" fontID=\"" + id(tag.getFontTag()) + "\"");
if (tag.getFontName() != null)
{
out.print(" name=\"" + tag.getFontName() + "\"");
}
if (tag.getFontCopyright() != null)
{
out.print(" copyright=\"" + escape(tag.getFontCopyright()) + "\"");
}
close();
}
private boolean isPrintable(char c)
{
int i = c & 0xFFFF;
if (i < ' ' || i == '<' || i == '&' || i == '\'')
return false;
else
return true;
}
public void dumpExportAssets(ExportAssetsTag tag)
{
open(tag);
end();
for (String name : tag.getCharacterNames())
{
indent();
out.println("<Export idref=\"" + tag.getCharacterTagByName(name).getCharacterID() +
"\" name=\"" + name + "\" />");
}
close(tag);
}
public void dumpSymbolClass(SymbolClassTag tag)
{
open(tag);
end();
for (String symbolName : tag.getSymbolNames())
{
indent();
out.println("<Symbol idref=\"" + tag.getSymbol(symbolName).getCharacterID() +
"\" className=\"" + symbolName + "\" />");
}
if (currentFrameIndex == 0 && swf.getTopLevelClass() != null)
{
indent();
out.println("<Symbol idref=\"0\" className=\"" + swf.getTopLevelClass() + "\" />");
}
close(tag);
}
// TODO: handle ImportAssets tag.
// public void dumpImportAssets(ImportAssets tag)
// {
// open(tag);
// out.print(" url=\"" + tag.url + "\"");
// end();
//
// Iterator it = tag.importRecords.iterator();
// while (it.hasNext())
// {
// ImportRecord record = (ImportRecord)it.next();
// indent();
// out.println("<Import name=\"" + record.name + "\" id=\"" + dictionary.getId(record) + "\" />");
// }
//
// close(tag);
// }
//
// public void dumpImportAssets2(ImportAssets tag)
// {
// // TODO: add support for tag.downloadNow and SHA1...
// importAssets(tag);
// }
public void dumpEnableDebugger(EnableDebugger2Tag tag)
{
open(tag);
out.print(" password=\"" + tag.getPassword() + "\"");
close();
}
// TODO Decode actions
// public void dumpDoInitAction(DoInitAction tag)
// {
// if (tag.sprite != null && tag.sprite.name != null)
// {
// indent();
// out.println("<!-- init " + tag.sprite.name + " " + dictionary.getId(tag.sprite) + " -->");
// }
//
// open(tag);
// if (tag.sprite != null)
// out.print(" idref=\"" + idRef(tag.sprite) + "\"");
// end();
//
// if (showActions)
// {
// openCDATA();
// printActions(tag.actionList);
// closeCDATA();
// }
// else
// {
// indent();
// out.println("<!-- " + tag.actionList.size() + " action(s) elided -->");
// }
// close(tag);
// }
public void dumpEnableTelemetry(EnableTelemetryTag tag)
{
open(tag);
out.print(" password=\"" + tag.getPassword() + "\"");
close();
}
private String idRef(ICharacterTag tag)
{
if (tag == null)
{
// if tag is null then it isn't in the dict -- the SWF is invalid.
// lets be lax and print something; Matador generates invalid SWF sometimes.
return "-1";
}
else if (currentFrame == null || currentFrame.getSymbolName(tag) == null)
{
// just print the character id since no name was exported
return String.valueOf(id(tag));
}
else
{
return currentFrame.getSymbolName(tag);
}
}
public void dumpDefineVideoStream(DefineVideoStreamTag tag)
{
open(tag);
out.print(" id=\"" + id(tag) + "\"");
close();
}
public void dumpVideoFrame(VideoFrameTag tag)
{
open(tag);
out.print(" streamId=\"" + idRef(tag.getStreamTag()) + "\"");
out.print(" frame=\"" + tag.getFrameNum() + "\"");
close();
}
public void dumpDefineFontInfo2(DefineFontInfoTag tag)
{
dumpDefineFontInfo(tag);
}
public void dumpEnableDebugger2(EnableDebugger2Tag tag)
{
open(tag);
out.print(" password=\"" + tag.getPassword() + "\"");
out.print(" reserved=\"0x" + Integer.toHexString(EnableDebugger2Tag.RESERVED_FIELD_VALUE) + "\"");
close();
}
// TODO: handle DebugID tag
// public void dumpDebugID(DebugID tag)
// {
// open(tag);
// out.print(" uuid=\"" + tag.uuid + "\"");
// close();
// }
public void dumpScriptLimits(ScriptLimitsTag tag)
{
open(tag);
out.print(" scriptRecursionLimit=\"" + tag.getMaxRecursionDepth() + "\"" +
" scriptTimeLimit=\"" + tag.getScriptTimeoutSeconds() + "\"");
close();
}
public void dumpSetTabIndex(SetTabIndexTag tag)
{
open(tag);
out.print(" depth=\"" + tag.getDepth() + "\"");
out.print(" index=\"" + tag.getTabIndex() + "\"");
close();
}
public void dumpDoABC(DoABCTag tag)
{
if (abc)
{
open(tag);
end();
ABCParser parser = new ABCParser(tag.getABCData());
parser.verbose = verbose;
parser.output = out;
PoolingABCVisitor printer = new ABCDumpVisitor(out, sortOption);
if (verbose)
out.println("doABC for " + tag.getName());
parser.parseABC(printer);
close(tag);
}
else
{
open(tag);
if (tag.getTagType() == TagType.DoABC)
out.print(" name=\"" + tag.getName() + "\"");
close();
}
}
@SuppressWarnings("unused")
private String hexify(byte[] id)
{
StringBuilder b = new StringBuilder(id.length * 2);
for (int i = 0; i < id.length; i++)
{
b.append(Character.forDigit((id[i] >> 4) & 15, 16));
b.append(Character.forDigit(id[i] & 15, 16));
}
return b.toString().toUpperCase();
}
public static String baseName(String path)
{
int start = path.lastIndexOf(File.separatorChar);
if (File.separatorChar != '/')
{
// some of us are grouchy about unix paths not being
// parsed since they are totally legit at the system
// level of win32.
int altstart = path.lastIndexOf('/');
if ((start == -1) || (altstart > start))
start = altstart;
}
if (start == -1)
start = 0;
else
++start;
int end = path.lastIndexOf('.');
if (end == -1)
end = path.length();
if (start > end)
end = path.length();
return path.substring(start, end);
}
public static String dirName(String path)
{
int end = path.lastIndexOf(File.pathSeparatorChar);
if (File.pathSeparatorChar != '/')
{
// some of us are grouchy about unix paths not being
// parsed since they are totally legit at the system
// level of win32.
int altend = path.lastIndexOf('/');
if ((end == -1) || (altend < end))
end = altend;
}
if (end == -1)
return "";
else
++end;
return path.substring(0, end);
}
// options
public static boolean abcOption = false;
public static boolean verboseOption = false;
static boolean encodeOption = false;
static boolean showActionsOption = true;
static boolean showOffsetOption = false;
static boolean showByteCodeOption = false;
static boolean showDebugSourceOption = false;
static boolean glyphsOption = true;
static boolean externalOption = false;
static boolean decompileOption = true;
static boolean defuncOption = true;
static boolean saveOption = false;
static boolean sortOption = false;
static boolean tabbedGlyphsOption = true;
static boolean uncompressOption = false;
/**
* SWFDump will dump a SWF file as XML.
*
* Usage: swfdump [-abc] file1.swf
*/
public static void main(String[] args) throws IOException
{
// This message should not be localized.
System.err.println("Apache Royale SWF Dump Utility");
System.err.println(VersionInfo.buildMessage());
System.err.println("");
if (args.length == 0)
{
// TODO: decide which options to implement.
// System.err.println("Usage: swfdump [-encode] [-asm] [-abc] [-showbytecode] [-showdebugsource] [-showoffset] [-noglyphs] [-save file.swf] [-nofunctions] [-out file.swfx] file1.swf ...");
System.err.println("Usage: swfdump [-abc] file1.swf");
System.exit(1);
}
int index = 0;
PrintWriter out = null;
String outfile = null;
while ((index < args.length) && (args[index].startsWith("-")))
{
if (args[index].equals("-encode"))
{
encodeOption = true;
++index;
}
else if (args[index].equals("-verbose"))
{
++index;
verboseOption = true;
}
else if (args[index].equals("-save"))
{
++index;
saveOption = true;
outfile = args[index++];
}
else if (args[index].equals("-sort"))
{
// Try to sort output by alpha-order of identifiers
// so compare of two dumps compare better.
// There is some randomness in the order of output
// of some scripts
++index;
sortOption = true;
}
else if (args[index].equals("-uncompress"))
{
++index;
uncompressOption = true;
outfile = args[index++];
}
else if (args[index].equals("-decompile"))
{
decompileOption = true;
++index;
}
else if (args[index].equals("-nofunctions"))
{
defuncOption = false;
++index;
}
else if (args[index].equals("-asm"))
{
decompileOption = false;
++index;
}
else if (args[index].equals("-abc"))
{
abcOption = true;
++index;
}
else if (args[index].equals("-noactions"))
{
showActionsOption = false;
++index;
}
else if (args[index].equals("-showoffset"))
{
showOffsetOption = true;
++index;
}
else if (args[index].equals("-showbytecode"))
{
showByteCodeOption = true;
++index;
}
else if (args[index].equals("-showdebugsource"))
{
showDebugSourceOption = true;
++index;
}
else if (args[index].equals("-noglyphs"))
{
glyphsOption = false;
++index;
}
else if (args[index].equals("-out"))
{
if (index + 1 == args.length)
{
System.err.println("-out requires a filename or - for stdout");
System.exit(1);
}
if (!args[index + 1].equals("-"))
{
outfile = args[index + 1];
out = new PrintWriter(outfile, "UTF-8");
}
index += 2;
}
else if (args[index].equals("-external"))
{
externalOption = true;
++index;
}
else if (args[index].equalsIgnoreCase("-tabbedGlyphs"))
{
tabbedGlyphsOption = true;
++index;
}
else
{
System.err.println("unknown argument " + args[index]);
++index;
}
}
if (out == null)
out = new PrintWriter(new OutputStreamWriter(System.out, "UTF-8"), true);
File f = new File(args[index]);
URL[] urls = new URL[0];
File currentFile = f;
try
{
if (!f.exists())
{
urls = new URL[] {new URL(args[index])};
}
else
{
if (f.isDirectory())
{
File[] list = listFiles(f);
urls = new URL[list.length];
for (int i = 0; i < list.length; i++)
{
currentFile = list[i];
urls[i] = toURL(list[i]);
}
}
else
{
urls = new URL[] {toURL(f)};
}
}
}
catch (MalformedURLException e)
{
System.err.println("Unable to open " + currentFile);
}
for (int i = 0; i < urls.length; i++)
{
try
{
URL url = urls[i];
if (saveOption)
{
InputStream in = new BufferedInputStream(url.openStream());
try
{
OutputStream fileOut = new BufferedOutputStream(new FileOutputStream(outfile));
try
{
int c;
while ((c = in.read()) != -1)
{
fileOut.write(c);
}
}
finally
{
fileOut.close();
}
}
finally
{
in.close();
}
}
if (uncompressOption)
{
final SWFReader swfReader = new SWFReader();
final String path = url.getPath();
try
{
SWF swf = (SWF)swfReader.readFrom(
new BufferedInputStream(url.openStream()),
path);
ProblemQuery problemQuery = new ProblemQuery();
problemQuery.addAll(swfReader.getProblems());
if (!problemQuery.hasErrors())
{
OutputStream fileOut = new BufferedOutputStream(new FileOutputStream(outfile));
SWFWriter swfWriter = new SWFWriter(swf, Header.Compression.NONE);
swfWriter.writeTo(fileOut);
swfWriter.close();
}
}
finally
{
IOUtils.closeQuietly(swfReader);
}
}
if (!uncompressOption)
dumpSwf(out, url, outfile);
out.flush();
}
catch (Error e)
{
if (Trace.error)
e.printStackTrace();
System.err.println("");
System.err.println("An unrecoverable error occurred. The given file " + urls[i] + " may not be");
System.err.println("a valid swf.");
}
catch (FileNotFoundException e)
{
System.err.println("Error: " + e.getMessage());
System.exit(1);
}
}
}
public static void dumpSwf(PrintWriter out, URL url, String outfile)
throws IOException
{
out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
if (!sortOption)
out.println("<!-- Parsing swf " + url + " -->");
SWFDump swfDump = new SWFDump(out);
// TODO: Disable options
// swfDump.showActions = showActionsOption;
// swfDump.showOffset = showOffsetOption;
// swfDump.showByteCode = showByteCodeOption;
// swfDump.showDebugSource = showDebugSourceOption;
// swfDump.glyphs = glyphsOption;
// swfDump.setExternal(externalOption, outfile);
// swfDump.decompile = decompileOption;
swfDump.abc = abcOption;
swfDump.verbose = verboseOption;
// swfDump.defunc = defuncOption;
// swfDump.tabbedGlyphs = tabbedGlyphsOption;
swfDump.dump(url);
}
public static URL toURL(File f) throws MalformedURLException
{
String s = f.getAbsolutePath();
if (File.separatorChar != '/')
{
s = s.replace(File.separatorChar, '/');
}
if (!s.startsWith("/"))
{
s = "/" + s;
}
if (!s.endsWith("/") && f.isDirectory())
{
s = s + "/";
}
return new URL("file", "", s);
}
public static File[] listFiles(File dir)
{
String[] fileNames = dir.list();
if (fileNames == null)
{
return null;
}
File[] fileList = new File[fileNames.length];
for (int i = 0; i < fileNames.length; i++)
{
fileList[i] = new File(dir.getPath(), fileNames[i]);
}
return fileList;
}
}