| /* |
| * |
| * 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 flash.swf.tools; |
| |
| import macromedia.abc.AbcParser; |
| import macromedia.asc.embedding.CompilerHandler; |
| import macromedia.asc.embedding.avmplus.ActionBlockEmitter; |
| import macromedia.asc.parser.ProgramNode; |
| import macromedia.asc.semantics.ObjectValue; |
| import macromedia.asc.semantics.TypeValue; |
| import macromedia.asc.util.Context; |
| import macromedia.asc.util.ContextStatics; |
| import macromedia.asc.util.StringPrintWriter; |
| import flash.swf.ActionDecoder; |
| import flash.swf.Dictionary; |
| import flash.swf.Header; |
| import flash.swf.SwfDecoder; |
| import flash.swf.Tag; |
| import flash.swf.TagDecoder; |
| import flash.swf.TagEncoder; |
| import flash.swf.TagHandler; |
| import flash.swf.TagValues; |
| import flash.swf.tags.*; |
| import flash.swf.types.ActionList; |
| import flash.swf.types.ButtonCondAction; |
| import flash.swf.types.ButtonRecord; |
| import flash.swf.types.ClipActionRecord; |
| import flash.swf.types.CurvedEdgeRecord; |
| import flash.swf.types.EdgeRecord; |
| import flash.swf.types.FillStyle; |
| import flash.swf.types.Filter; |
| import flash.swf.types.GlyphEntry; |
| import flash.swf.types.GradRecord; |
| import flash.swf.types.ImportRecord; |
| import flash.swf.types.LineStyle; |
| import flash.swf.types.MorphFillStyle; |
| import flash.swf.types.MorphGradRecord; |
| import flash.swf.types.MorphLineStyle; |
| import flash.swf.types.Shape; |
| import flash.swf.types.ShapeRecord; |
| import flash.swf.types.ShapeWithStyle; |
| import flash.swf.types.SoundInfo; |
| import flash.swf.types.StraightEdgeRecord; |
| import flash.swf.types.StyleChangeRecord; |
| import flash.swf.types.TextRecord; |
| import flash.swf.types.FocalGradient; |
| import flash.swf.types.KerningRecord; |
| import flash.util.Base64; |
| import flash.util.FileUtils; |
| import flash.util.SwfImageUtils; |
| import flash.util.Trace; |
| |
| import java.io.BufferedInputStream; |
| import java.io.BufferedOutputStream; |
| import java.io.ByteArrayInputStream; |
| import java.io.DataInputStream; |
| 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.PrintWriter; |
| import java.io.StringWriter; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.text.DateFormat; |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipInputStream; |
| |
| /** |
| * This class supports printing out a SWF in a human readable XML |
| * format. |
| * |
| * @author Clement Wong |
| * @author Edwin Smith |
| */ |
| public final class SwfxPrinter extends TagHandler |
| { |
| /** |
| * this value should get set after the header is parsed |
| */ |
| private Integer swfVersion = null; |
| |
| private boolean abc = false; |
| private boolean showActions = true; |
| private boolean showOffset = false; |
| private boolean showByteCode = false; |
| private boolean showDebugSource = false; |
| private boolean glyphs = true; |
| private boolean external = false; |
| private String externalPrefix = null; |
| private String externalDirectory = null; |
| private boolean decompile; |
| private boolean defunc; |
| private int indent = 0; |
| private boolean tabbedGlyphs = false; |
| |
| static |
| { |
| TypeValue.init(); |
| ObjectValue.init(); |
| } |
| |
| public SwfxPrinter(PrintWriter out) |
| { |
| this.out = out; |
| } |
| |
| 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); |
| } |
| |
| 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 header(Header h) |
| { |
| swfVersion = h.version; |
| out.println("<!-- ?xml version=\"1.0\" encoding=\"UTF-8\"? -->"); |
| out.println("<swf xmlns='http://macromedia/2003/swfx'" + |
| " version='" + h.version + "'" + |
| " framerate='" + h.rate + "'" + |
| " size='" + h.size + "'" + |
| " compressed='" + h.compressed + "'" + |
| " >"); |
| indent++; |
| indent(); |
| out.println("<!-- framecount=" + h.framecount + " length=" + h.length + " -->"); |
| } |
| |
| public void productInfo(ProductInfo productInfo) |
| { |
| open(productInfo); |
| out.print(" product='" + productInfo.getProductString() + "'"); |
| out.print(" edition='" + productInfo.getEditionString() + "'"); |
| 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 metadata(Metadata tag) |
| { |
| open(tag); |
| end(); |
| indent(); |
| out.println(tag.xml); |
| close(tag); |
| } |
| |
| public void fileAttributes(FileAttributes tag) |
| { |
| open(tag); |
| out.print(" useDirectBlit='" + tag.useDirectBlit + "'"); |
| out.print(" useGPU='" + tag.useGPU + "'"); |
| out.print(" hasMetadata='" + tag.hasMetadata + "'"); |
| out.print(" actionScript3='" + tag.actionScript3 + "'"); |
| out.print(" suppressCrossDomainCaching='" + tag.suppressCrossDomainCaching + "'"); |
| out.print(" swfRelativeUrls='" + tag.swfRelativeUrls + "'"); |
| out.print(" useNetwork='" + tag.useNetwork + "'"); |
| close(); |
| } |
| |
| |
| private final PrintWriter out; |
| |
| private Dictionary dict; |
| |
| public void setDecoderDictionary(Dictionary dict) |
| { |
| this.dict = dict; |
| } |
| |
| 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 + |
| " -->"); |
| } |
| } |
| |
| private void open(Tag tag) |
| { |
| indent(); |
| out.print("<" + TagValues.names[tag.code]); |
| } |
| |
| private void end() |
| { |
| out.println(">"); |
| indent++; |
| } |
| |
| private void openCDATA() |
| { |
| indent(); |
| out.println("<![CDATA["); |
| indent++; |
| } |
| |
| private void closeCDATA() |
| { |
| indent--; |
| indent(); |
| out.println("]]>"); |
| } |
| |
| private void close() |
| { |
| out.println("/>"); |
| } |
| |
| private void close(Tag tag) |
| { |
| indent--; |
| indent(); |
| out.println("</" + TagValues.names[tag.code] + ">"); |
| } |
| |
| public void error(String s) |
| { |
| indent(); |
| out.println("<!-- error: " + s + " -->"); |
| } |
| |
| public void unknown(GenericTag tag) |
| { |
| indent(); |
| out.println("<!-- unknown tag=" + tag.code + " length=" + |
| (tag.data != null ? tag.data.length : 0) + " -->"); |
| } |
| |
| public void showFrame(ShowFrame tag) |
| { |
| open(tag); |
| close(); |
| } |
| |
| public void defineShape(DefineShape tag) |
| { |
| printDefineShape(tag, false); |
| } |
| |
| private void printDefineShape(DefineShape tag, boolean alpha) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| out.print(" bounds='" + tag.bounds + "'"); |
| if (tag.code == Tag.stagDefineShape4) |
| { |
| out.print(" edgebounds='" + tag.edgeBounds + "'"); |
| out.print(" usesNonScalingStrokes='" + tag.usesNonScalingStrokes + "'"); |
| out.print(" usesScalingStrokes='" + tag.usesScalingStrokes + "'"); |
| } |
| |
| end(); |
| |
| printShapeWithStyles(tag.shapeWithStyle, alpha); |
| |
| close(tag); |
| } |
| |
| private String id(DefineTag tag) |
| { |
| final int id = dict.getId(tag); |
| return String.valueOf(id); |
| } |
| |
| static final char[] digits = new char[]{ |
| '0', '1', '2', '3', '4', '5', '6', '7', |
| '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' |
| }; |
| |
| /** |
| * @param rgb as an integer, 0x00RRGGBB |
| * @return string formatted as #RRGGBB |
| */ |
| public String printRGB(int rgb) |
| { |
| StringBuilder b = new StringBuilder(); |
| b.append('#'); |
| int red = (rgb >> 16) & 255; |
| b.append(digits[(red >> 4) & 15]); |
| b.append(digits[red & 15]); |
| int green = (rgb >> 8) & 255; |
| b.append(digits[(green >> 4) & 15]); |
| b.append(digits[green & 15]); |
| int blue = rgb & 255; |
| b.append(digits[(blue >> 4) & 15]); |
| b.append(digits[blue & 15]); |
| return b.toString(); |
| } |
| |
| /** |
| * @param rgb as an integer, 0xAARRGGBB |
| * @return string formatted as #RRGGBBAA |
| */ |
| public String printRGBA(int rgb) |
| { |
| StringBuilder b = new StringBuilder(); |
| b.append('#'); |
| int red = (rgb >> 16) & 255; |
| b.append(digits[(red >> 4) & 15]); |
| b.append(digits[red & 15]); |
| int green = (rgb >> 8) & 255; |
| b.append(digits[(green >> 4) & 15]); |
| b.append(digits[green & 15]); |
| int blue = rgb & 255; |
| b.append(digits[(blue >> 4) & 15]); |
| b.append(digits[blue & 15]); |
| int alpha = (rgb >> 24) & 255; |
| b.append(digits[(alpha >> 4) & 15]); |
| b.append(digits[alpha & 15]); |
| return b.toString(); |
| } |
| |
| public void placeObject(PlaceObject tag) |
| { |
| open(tag); |
| out.print(" idref='" + idRef(tag.ref) + "'"); |
| out.print(" depth='" + tag.depth + "'"); |
| out.print(" matrix='" + tag.matrix + "'"); |
| if (tag.colorTransform != null) |
| out.print(" colorXform='" + tag.colorTransform + "'"); |
| close(); |
| } |
| |
| public void removeObject(RemoveObject tag) |
| { |
| open(tag); |
| out.print(" idref='" + idRef(tag.ref) + "'"); |
| 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()); |
| } |
| //private byte[] jpegTable = null; |
| |
| public void defineBits(DefineBits tag) |
| { |
| if (tag.jpegTables == null) |
| { |
| out.println("<!-- warning: no JPEG table tag found. -->"); |
| } |
| |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| |
| if (external) |
| { |
| String path = externalDirectory |
| + externalPrefix |
| + "image" |
| + dict.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.data); |
| close(tag); |
| } |
| } |
| |
| public void defineButton(DefineButton tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| end(); |
| if (showActions) |
| { |
| openCDATA(); |
| // todo print button records |
| printActions(tag.condActions[0].actionList); |
| closeCDATA(); |
| } |
| else |
| { |
| out.println("<!-- " + tag.condActions[0].actionList.size() + " action(s) elided -->"); |
| } |
| close(tag); |
| } |
| |
| public void jpegTables(GenericTag tag) |
| { |
| open(tag); |
| out.print(" encoding='base64'"); |
| end(); |
| outputBase64(tag.data); |
| close(tag); |
| } |
| |
| public void setBackgroundColor(SetBackgroundColor tag) |
| { |
| open(tag); |
| out.print(" color='" + printRGB(tag.color) + "'"); |
| close(); |
| } |
| |
| public void defineFont(DefineFont1 tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| end(); |
| |
| if (glyphs) |
| { |
| for (int i = 0; i < tag.glyphShapeTable.length; i++) |
| { |
| indent(); |
| out.println("<glyph>"); |
| |
| Shape shape = tag.glyphShapeTable[i]; |
| indent++; |
| printShapeWithTabs(shape); |
| indent--; |
| |
| indent(); |
| out.println("</glyph>"); |
| } |
| } |
| close(tag); |
| } |
| |
| public void defineText(DefineText tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| out.print(" bounds='" + tag.bounds + "'"); |
| out.print(" matrix='" + tag.matrix + "'"); |
| |
| end(); |
| |
| Iterator it = tag.records.iterator(); |
| |
| while (it.hasNext()) |
| { |
| TextRecord tr = (TextRecord)it.next(); |
| printTextRecord(tr, tag.code); |
| } |
| |
| close(tag); |
| } |
| |
| 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 defineFontInfo(DefineFontInfo tag) |
| { |
| open(tag); |
| out.print(" idref='" + idRef(tag.font) + "'"); |
| out.print(" ansi='" + tag.ansi + "'"); |
| out.print(" italic='" + tag.italic + "'"); |
| out.print(" bold='" + tag.bold + "'"); |
| out.print(" wideCodes='" + tag.wideCodes + "'"); |
| out.print(" langCold='" + tag.langCode + "'"); |
| out.print(" name='" + tag.name + "'"); |
| out.print(" shiftJIS='" + tag.shiftJIS + "'"); |
| end(); |
| indent(); |
| for (int i = 0; i < tag.codeTable.length; i++) |
| { |
| out.print((int)tag.codeTable[i]); |
| if ((i + 1) % 16 == 0) |
| { |
| out.println(); |
| indent(); |
| } |
| else |
| { |
| out.print(' '); |
| } |
| } |
| if (tag.codeTable.length % 16 != 0) |
| { |
| out.println(); |
| indent(); |
| } |
| close(tag); |
| } |
| |
| public void defineSound(DefineSound tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| out.print(" format='" + tag.format + "'"); |
| out.print(" rate='" + tag.rate + "'"); |
| out.print(" size='" + tag.size + "'"); |
| out.print(" type='" + tag.type + "'"); |
| out.print(" sampleCount='" + tag.sampleCount + "'"); |
| out.print(" soundDataSize='" + tag.data.length + "'"); |
| end(); |
| openCDATA(); |
| outputBase64(tag.data); |
| closeCDATA(); |
| close(tag); |
| } |
| |
| public void startSound(StartSound tag) |
| { |
| open(tag); |
| out.print(" soundid='" + idRef(tag.sound) + "'"); |
| printSoundInfo(tag.soundInfo); |
| close(tag); |
| } |
| |
| private void printSoundInfo(SoundInfo info) |
| { |
| out.print(" syncStop='" + info.syncStop + "'"); |
| out.print(" syncNoMultiple='" + info.syncNoMultiple + "'"); |
| if (info.inPoint != SoundInfo.UNINITIALIZED) |
| { |
| out.print(" inPoint='" + info.inPoint + "'"); |
| } |
| if (info.outPoint != SoundInfo.UNINITIALIZED) |
| { |
| out.print(" outPoint='" + info.outPoint + "'"); |
| } |
| if (info.loopCount != SoundInfo.UNINITIALIZED) |
| { |
| out.print(" loopCount='" + info.loopCount + "'"); |
| } |
| end(); |
| if (info.records != null && info.records.length > 0) |
| { |
| openCDATA(); |
| for (int i = 0; i < info.records.length; i++) |
| { |
| out.println(info.records[i]); |
| } |
| closeCDATA(); |
| } |
| } |
| |
| public void defineButtonSound(DefineButtonSound tag) |
| { |
| open(tag); |
| out.print(" buttonId='" + idRef(tag.button) + "'"); |
| close(); |
| } |
| |
| public void soundStreamHead(SoundStreamHead tag) |
| { |
| open(tag); |
| close(); |
| } |
| |
| public void soundStreamBlock(GenericTag tag) |
| { |
| open(tag); |
| close(); |
| } |
| |
| public void defineBinaryData(DefineBinaryData tag) |
| { |
| open(tag); |
| out.println(" id='" + id(tag) + "' length='" + tag.data.length + "' />" ); |
| } |
| public void defineBitsLossless(DefineBitsLossless tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "' width='" + tag.width + "' height='" + tag.height + "'"); |
| |
| if (external) |
| { |
| String path = externalDirectory |
| + externalPrefix |
| + "image" |
| + dict.getId(tag) |
| + ".bitmap"; |
| |
| out.println(" src='" + path + "' />"); |
| try |
| { |
| FileOutputStream image = new FileOutputStream(path, false); |
| image.write(tag.data); |
| image.close(); |
| } |
| catch (IOException e) |
| { |
| out.println("<!-- error: unable to write external asset file " + path + "-->"); |
| } |
| } |
| else |
| { |
| out.print(" encoding='base64'"); |
| end(); |
| outputBase64(tag.data); |
| close(tag); |
| } |
| } |
| |
| public void defineBitsJPEG2(DefineBits tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| |
| if (external) |
| { |
| String path = externalDirectory |
| + externalPrefix |
| + "image" |
| + dict.getId(tag) |
| + ".jpg"; |
| |
| out.println(" src='" + path + "' />"); |
| try |
| { |
| FileOutputStream image = new FileOutputStream(path, false); |
| image.write(tag.data); |
| image.close(); |
| } |
| catch (IOException e) |
| { |
| out.println("<!-- error: unable to write external asset file " + path + "-->"); |
| } |
| } |
| else |
| { |
| out.print(" encoding='base64'"); |
| end(); |
| outputBase64(tag.data); |
| close(tag); |
| } |
| } |
| |
| public void defineShape2(DefineShape tag) |
| { |
| printDefineShape(tag, false); |
| } |
| |
| public void defineButtonCxform(DefineButtonCxform tag) |
| { |
| open(tag); |
| out.print(" buttonId='" + idRef(tag.button) + "'"); |
| close(); |
| } |
| |
| public void protect(GenericTag tag) |
| { |
| open(tag); |
| if (tag.data != null) |
| out.print(" password='" + hexify(tag.data) + "'"); |
| close(); |
| } |
| |
| public void placeObject2(PlaceObject tag) |
| { |
| placeObject23(tag); |
| } |
| |
| public void placeObject3(PlaceObject tag) |
| { |
| placeObject23(tag); |
| } |
| |
| public void placeObject23(PlaceObject tag) |
| { |
| if (tag.hasCharID()) |
| { |
| if (tag.ref.name != null) |
| { |
| indent(); |
| out.println("<!-- instance of " + tag.ref.name + " -->"); |
| } |
| } |
| |
| open(tag); |
| if (tag.hasClassName()) |
| out.print(" className='" + tag.className + "'"); |
| if (tag.hasImage()) |
| out.print(" hasImage='true' "); |
| if (tag.hasCharID()) |
| out.print(" idref='" + idRef(tag.ref) + "'"); |
| if (tag.hasName()) |
| out.print(" name='" + tag.name + "'"); |
| out.print(" depth='" + tag.depth + "'"); |
| if (tag.hasClipDepth()) |
| out.print(" clipDepth='" + tag.clipDepth + "'"); |
| if (tag.hasCacheAsBitmap()) |
| out.print(" cacheAsBitmap='true'"); |
| if (tag.hasRatio()) |
| out.print(" ratio='" + tag.ratio + "'"); |
| if (tag.hasCxform()) |
| out.print(" cxform='" + tag.colorTransform + "'"); |
| if (tag.hasMatrix()) |
| out.print(" matrix='" + tag.matrix + "'"); |
| if (tag.hasBlendMode()) |
| out.print(" blendmode='" + tag.blendMode + "'"); |
| if (tag.hasFilterList()) |
| { |
| // todo - pretty print this once we actually care |
| out.print(" filters='"); |
| for (Iterator it = tag.filters.iterator(); it.hasNext();) |
| { |
| out.print( (((Filter) it.next()).getID() ) + " "); |
| } |
| out.print("'"); |
| } |
| |
| if (tag.hasClipAction()) |
| { |
| end(); |
| Iterator it = tag.clipActions.clipActionRecords.iterator(); |
| |
| openCDATA(); |
| while (it.hasNext()) |
| { |
| 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 removeObject2(RemoveObject tag) |
| { |
| open(tag); |
| out.print(" depth='" + tag.depth + "'"); |
| close(); |
| } |
| |
| public void defineShape3(DefineShape tag) |
| { |
| printDefineShape(tag, true); |
| } |
| |
| public void defineShape4(DefineShape tag) |
| { |
| printDefineShape(tag, true); |
| } |
| |
| private void printShapeWithStyles(ShapeWithStyle shapes, boolean alpha) |
| { |
| printFillStyles(shapes.fillstyles, alpha); |
| printLineStyles(shapes.linestyles, alpha); |
| printShape(shapes, alpha); |
| } |
| |
| private void printMorphLineStyles(MorphLineStyle[] lineStyles) |
| { |
| for (int i = 0; i < lineStyles.length; i++) |
| { |
| MorphLineStyle lineStyle = lineStyles[i]; |
| indent(); |
| out.print("<linestyle "); |
| out.print("startColor='" + printRGBA(lineStyle.startColor) + "' "); |
| out.print("endColor='" + printRGBA(lineStyle.startColor) + "' "); |
| out.print("startWidth='" + lineStyle.startWidth + "' "); |
| out.print("endWidth='" + lineStyle.endWidth + "' "); |
| out.println("/>"); |
| } |
| } |
| |
| private void printLineStyles(ArrayList linestyles, boolean alpha) |
| { |
| Iterator it = linestyles.iterator(); |
| while (it.hasNext()) |
| { |
| LineStyle lineStyle = (LineStyle)it.next(); |
| indent(); |
| out.print("<linestyle "); |
| String color = alpha ? printRGBA(lineStyle.color) : printRGB(lineStyle.color); |
| out.print("color='" + color + "' "); |
| out.print("width='" + lineStyle.width + "' "); |
| if (lineStyle.flags != 0) |
| out.print("flags='" + lineStyle.flags + "' "); |
| if (lineStyle.hasMiterJoint()) |
| { |
| out.print("miterLimit='" + lineStyle.miterLimit + "' "); |
| } |
| if (lineStyle.hasFillStyle()) |
| { |
| out.println(">"); |
| indent(); |
| ArrayList<FillStyle> fillStyles = new ArrayList<FillStyle>(1); |
| fillStyles.add(lineStyle.fillStyle); |
| printFillStyles(fillStyles, alpha); |
| indent(); |
| out.println("</linestyle>"); |
| } |
| else |
| { |
| out.println("/>"); |
| } |
| } |
| } |
| |
| private void printFillStyles(ArrayList fillstyles, boolean alpha) |
| { |
| Iterator it = fillstyles.iterator(); |
| while (it.hasNext()) |
| { |
| FillStyle fillStyle = (FillStyle)it.next(); |
| indent(); |
| out.print("<fillstyle"); |
| out.print(" type='" + fillStyle.getType() + "'"); |
| if (fillStyle.getType() == FillStyle.FILL_SOLID) |
| { |
| out.print(" color='" + (alpha ? printRGBA(fillStyle.color) : printRGB(fillStyle.color)) + "'"); |
| } |
| if ((fillStyle.getType() & FillStyle.FILL_LINEAR_GRADIENT) != 0) |
| { |
| if (fillStyle.getType() == FillStyle.FILL_RADIAL_GRADIENT) |
| out.print( " typeName='radial'"); |
| else if (fillStyle.getType() == FillStyle.FILL_FOCAL_RADIAL_GRADIENT) |
| out.print( " typeName='focal' focalPoint='" + ((FocalGradient)fillStyle.gradient).focalPoint + "'"); |
| // todo print linear or radial or focal |
| out.print(" gradient='" + formatGradient(fillStyle.gradient.records, alpha) + "'"); |
| out.print(" matrix='" + fillStyle.matrix + "'"); |
| } |
| if ((fillStyle.getType() & FillStyle.FILL_BITS) != 0) |
| { |
| // todo print tiled or clipped |
| out.print(" idref='" + idRef(fillStyle.bitmap) + "'"); |
| out.print(" matrix='" + fillStyle.matrix + "'"); |
| } |
| out.println(" />"); |
| } |
| } |
| |
| 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.type + "'"); |
| if (fillStyle.type == FillStyle.FILL_SOLID) |
| { |
| out.print(" startColor='" + printRGBA(fillStyle.startColor) + "'"); |
| out.print(" endColor='" + printRGBA(fillStyle.endColor) + "'"); |
| } |
| if ((fillStyle.type & FillStyle.FILL_LINEAR_GRADIENT) != 0) |
| { |
| // todo print linear or radial |
| out.print(" gradient='" + formatMorphGradient(fillStyle.gradRecords) + "'"); |
| out.print(" startMatrix='" + fillStyle.startGradientMatrix + "'"); |
| out.print(" endMatrix='" + fillStyle.endGradientMatrix + "'"); |
| } |
| if ((fillStyle.type & FillStyle.FILL_BITS) != 0) |
| { |
| // todo print tiled or clipped |
| out.print(" idref='" + idRef(fillStyle.bitmap) + "'"); |
| out.print(" startMatrix='" + fillStyle.startBitmapMatrix + "'"); |
| out.print(" endMatrix='" + fillStyle.endBitmapMatrix + "'"); |
| } |
| out.println(" />"); |
| } |
| } |
| |
| private String formatGradient(GradRecord[] records, boolean alpha) |
| { |
| StringBuilder b = new StringBuilder(); |
| for (int i = 0; i < records.length; i++) |
| { |
| b.append(records[i].ratio); |
| b.append(' '); |
| b.append(alpha ? printRGBA(records[i].color) : printRGB(records[i].color)); |
| if (i + 1 < records.length) |
| b.append(' '); |
| } |
| return b.toString(); |
| } |
| |
| private String formatMorphGradient(MorphGradRecord[] records) |
| { |
| StringBuilder b = new StringBuilder(); |
| for (int i = 0; i < records.length; i++) |
| { |
| b.append(records[i].startRatio); |
| b.append(','); |
| b.append(records[i].endRatio); |
| b.append(' '); |
| b.append(printRGBA(records[i].startColor)); |
| b.append(','); |
| b.append(printRGBA(records[i].endColor)); |
| if (i + 1 < records.length) |
| b.append(' '); |
| } |
| return b.toString(); |
| } |
| |
| private void printShape(Shape shapes, boolean alpha) |
| { |
| if (shapes == null) |
| return; |
| |
| Iterator it = shapes.shapeRecords.iterator(); |
| while (it.hasNext()) |
| { |
| indent(); |
| ShapeRecord shape = (ShapeRecord)it.next(); |
| if (shape instanceof StyleChangeRecord) |
| { |
| StyleChangeRecord styleChange = (StyleChangeRecord)shape; |
| out.print("<styleChange "); |
| if (styleChange.stateMoveTo) |
| { |
| out.print("dx='" + styleChange.moveDeltaX + "' dy='" + styleChange.moveDeltaY + "' "); |
| } |
| if (styleChange.stateFillStyle0) |
| { |
| out.print("fillStyle0='" + styleChange.fillstyle0 + "' "); |
| } |
| if (styleChange.stateFillStyle1) |
| { |
| out.print("fillStyle1='" + styleChange.fillstyle1 + "' "); |
| } |
| if (styleChange.stateLineStyle) |
| { |
| out.print("lineStyle='" + styleChange.linestyle + "' "); |
| } |
| if (styleChange.stateNewStyles) |
| { |
| out.println(">"); |
| indent++; |
| printFillStyles(styleChange.fillstyles, alpha); |
| printLineStyles(styleChange.linestyles, alpha); |
| indent--; |
| indent(); |
| out.println("</styleChange>"); |
| } |
| else |
| { |
| out.println("/>"); |
| } |
| } |
| else |
| { |
| EdgeRecord edge = (EdgeRecord)shape; |
| if (edge instanceof StraightEdgeRecord) |
| { |
| StraightEdgeRecord straightEdge = (StraightEdgeRecord)edge; |
| out.println("<line dx='" + straightEdge.deltaX + "' dy='" + straightEdge.deltaY + "' />"); |
| } |
| else |
| { |
| CurvedEdgeRecord curvedEdge = (CurvedEdgeRecord)edge; |
| out.print("<curve "); |
| out.print("cdx='" + curvedEdge.controlDeltaX + "' cdy='" + curvedEdge.controlDeltaY + "' "); |
| out.print("dx='" + curvedEdge.anchorDeltaX + "' dy='" + curvedEdge.anchorDeltaY + "' "); |
| out.println("/>"); |
| } |
| } |
| } |
| } |
| |
| private void printShapeWithTabs(Shape shapes) |
| { |
| if (shapes == null) |
| return; |
| |
| Iterator it = shapes.shapeRecords.iterator(); |
| int startX = 0; |
| int startY = 0; |
| |
| int x = 0; |
| int y = 0; |
| |
| while (it.hasNext()) |
| { |
| indent(); |
| ShapeRecord shape = (ShapeRecord)it.next(); |
| if (shape instanceof StyleChangeRecord) |
| { |
| StyleChangeRecord styleChange = (StyleChangeRecord)shape; |
| out.print("SSCR" + styleChange.nMoveBits() + "\t"); |
| if (styleChange.stateMoveTo) |
| { |
| out.print(styleChange.moveDeltaX + "\t" + styleChange.moveDeltaY); |
| |
| if (startX == 0 && startY == 0) |
| { |
| startX = styleChange.moveDeltaX; |
| startY = styleChange.moveDeltaY; |
| } |
| |
| x = styleChange.moveDeltaX; |
| y = styleChange.moveDeltaY; |
| |
| out.print("\t\t"); |
| } |
| } |
| else |
| { |
| EdgeRecord edge = (EdgeRecord)shape; |
| if (edge instanceof StraightEdgeRecord) |
| { |
| StraightEdgeRecord straightEdge = (StraightEdgeRecord)edge; |
| out.print("SER" + "\t"); |
| out.print(straightEdge.deltaX + "\t" + straightEdge.deltaY); |
| x += straightEdge.deltaX; |
| y += straightEdge.deltaY; |
| out.print("\t\t"); |
| } |
| else |
| { |
| CurvedEdgeRecord curvedEdge = (CurvedEdgeRecord)edge; |
| out.print("CER" + "\t"); |
| out.print(curvedEdge.controlDeltaX + "\t" + curvedEdge.controlDeltaY + "\t"); |
| out.print(curvedEdge.anchorDeltaX + "\t" + curvedEdge.anchorDeltaY); |
| x += (curvedEdge.controlDeltaX + curvedEdge.anchorDeltaX); |
| y += (curvedEdge.controlDeltaY + curvedEdge.anchorDeltaY); |
| } |
| } |
| |
| out.println("\t\t" + x + "\t" + y); |
| } |
| } |
| |
| 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(DefineText tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| end(); |
| |
| Iterator it = tag.records.iterator(); |
| |
| while (it.hasNext()) |
| { |
| TextRecord tr = (TextRecord)it.next(); |
| printTextRecord(tr, tag.code); |
| } |
| |
| close(tag); |
| } |
| |
| public void printTextRecord(TextRecord tr, int tagCode) |
| { |
| indent(); |
| out.print("<textRecord "); |
| if (tr.hasFont()) |
| out.print(" font='" + tr.font.getFontName() + "'"); |
| |
| if (tr.hasHeight()) |
| out.print(" height='" + tr.height + "'"); |
| |
| if (tr.hasX()) |
| out.print(" xOffset='" + tr.xOffset + "'"); |
| |
| if (tr.hasY()) |
| out.print(" yOffset='" + tr.yOffset + "'"); |
| |
| if (tr.hasColor()) |
| out.print(" color='" + |
| (tagCode == TagValues.stagDefineEditText ? printRGB(tr.color) : printRGBA(tr.color)) + |
| "'"); |
| out.println(">"); |
| |
| indent++; |
| printGlyphEntries(tr); |
| indent--; |
| indent(); |
| out.println("</textRecord>"); |
| |
| } |
| |
| private void printGlyphEntries(TextRecord tr) |
| { |
| indent(); |
| for (int i = 0; i < tr.entries.length; i++) |
| { |
| GlyphEntry ge = tr.entries[i]; |
| out.print(ge.getIndex()); |
| if (ge.advance >= 0) |
| out.print('+'); |
| out.print(ge.advance); |
| out.print(' '); |
| if ((i + 1) % 10 == 0) |
| { |
| out.println(); |
| indent(); |
| } |
| } |
| if (tr.entries.length % 10 != 0) |
| out.println(); |
| } |
| |
| |
| public void defineButton2(DefineButton tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| out.print(" trackAsMenu='" + tag.trackAsMenu + "'"); |
| end(); |
| |
| for (int i = 0; i < tag.buttonRecords.length; i++) |
| { |
| ButtonRecord record = tag.buttonRecords[i]; |
| indent(); |
| out.println("<buttonRecord " + |
| "idref='" + idRef(record.characterRef) + "' " + |
| "depth='" + record.placeDepth + "' " + |
| "matrix='" + record.placeMatrix + "' " + |
| "states='" + record.getFlags() + "'/>"); |
| // todo print optional cxforma |
| } |
| |
| // print conditional 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 defineBitsJPEG3(DefineBitsJPEG3 tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| |
| if (external) |
| { |
| String path = externalDirectory |
| + externalPrefix |
| + "image" |
| + dict.getId(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.data); |
| close(tag); |
| } |
| } |
| |
| public void defineBitsLossless2(DefineBitsLossless tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| |
| if (external) |
| { |
| String path = externalDirectory |
| + externalPrefix |
| + "image" |
| + dict.getId(tag) |
| + ".bitmap"; |
| |
| out.println(" src='" + path + "' />"); |
| try |
| { |
| FileOutputStream image = new FileOutputStream(path, false); |
| image.write(tag.data); |
| image.close(); |
| } |
| catch (IOException e) |
| { |
| out.println("<!-- error: unable to write external asset file " + path + "-->"); |
| } |
| } |
| else |
| { |
| out.print(" encoding='base64'"); |
| end(); |
| outputBase64(tag.data); |
| 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("<"); |
| break; |
| case '>': |
| b.append(">"); |
| break; |
| case '&': |
| b.append("&"); |
| break; |
| } |
| } |
| |
| return b.toString(); |
| } |
| |
| public void defineEditText(DefineEditText tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| |
| if (tag.hasText) |
| out.print(" text='" + escape(tag.initialText) + "'"); |
| |
| if (tag.hasFont) |
| { |
| out.print(" fontId='" + id(tag.font) + "'"); |
| out.print(" fontName='" + tag.font.getFontName() + "'"); |
| out.print(" fontHeight='" + tag.height + "'"); |
| } |
| else if (tag.hasFontClass) |
| { |
| out.print(" fontClass='" + tag.fontClass + "'"); |
| out.print(" fontHeight='" + tag.height + "'"); |
| } |
| |
| out.print(" bounds='" + tag.bounds + "'"); |
| |
| if (tag.hasTextColor) |
| out.print(" color='" + printRGBA(tag.color) + "'"); |
| |
| out.print(" html='" + tag.html + "'"); |
| out.print(" autoSize='" + tag.autoSize + "'"); |
| out.print(" border='" + tag.border + "'"); |
| |
| if (tag.hasMaxLength) |
| out.print(" maxLength='" + tag.maxLength + "'"); |
| |
| out.print(" multiline='" + tag.multiline + "'"); |
| out.print(" noSelect='" + tag.noSelect + "'"); |
| out.print(" password='" + tag.password + "'"); |
| out.print(" readOnly='" + tag.readOnly + "'"); |
| out.print(" useOutlines='" + tag.useOutlines + "'"); |
| out.print(" varName='" + tag.varName + "'"); |
| out.print(" wordWrap='" + tag.wordWrap + "'"); |
| |
| if (tag.hasLayout) |
| { |
| out.print(" align='" + tag.align + "'"); |
| out.print(" indent='" + tag.ident + "'"); |
| out.print(" leading='" + tag.leading + "'"); |
| out.print(" leftMargin='" + tag.leftMargin + "'"); |
| out.print(" rightMargin='" + tag.rightMargin + "'"); |
| } |
| close(); |
| } |
| |
| |
| public void defineSprite(DefineSprite tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| end(); |
| indent(); |
| out.println("<!-- sprite framecount=" + tag.framecount + " -->"); |
| |
| tag.tagList.visitTags(this); |
| |
| close(tag); |
| } |
| |
| public void finish() |
| { |
| --indent; |
| indent(); |
| out.println("</swf>"); |
| } |
| |
| public void frameLabel(FrameLabel tag) |
| { |
| open(tag); |
| out.print(" label='" + tag.label + "'"); |
| if (tag.anchor) |
| out.print(" anchor='" + "true" + "'"); |
| close(); |
| } |
| |
| public void soundStreamHead2(SoundStreamHead tag) |
| { |
| open(tag); |
| out.print(" playbackRate='" + tag.playbackRate + "'"); |
| out.print(" playbackSize='" + tag.playbackSize + "'"); |
| out.print(" playbackType='" + tag.playbackType + "'"); |
| out.print(" compression='" + tag.compression + "'"); |
| out.print(" streamRate='" + tag.streamRate + "'"); |
| out.print(" streamSize='" + tag.streamSize + "'"); |
| out.print(" streamType='" + tag.streamType + "'"); |
| out.print(" streamSampleCount='" + tag.streamSampleCount + "'"); |
| |
| if (tag.compression == 2) |
| { |
| out.print(" latencySeek='" + tag.latencySeek + "'"); |
| } |
| close(); |
| } |
| |
| public void defineScalingGrid(DefineScalingGrid tag) |
| { |
| open(tag); |
| out.print(" idref='" + id(tag.scalingTarget) + "'"); |
| out.print( " grid='" + tag.rect + "'" ); |
| close(); |
| } |
| |
| public void defineMorphShape(DefineMorphShape tag) |
| { |
| defineMorphShape2(tag); |
| } |
| |
| public void defineMorphShape2(DefineMorphShape tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| out.print(" startBounds='" + tag.startBounds + "'"); |
| out.print(" endBounds='" + tag.endBounds + "'"); |
| if (tag.code == TagValues.stagDefineMorphShape2) |
| { |
| out.print(" startEdgeBounds='" + tag.startEdgeBounds + "'"); |
| out.print(" endEdgeBounds='" + tag.endEdgeBounds + "'"); |
| out.print(" usesNonScalingStrokes='" + tag.usesNonScalingStrokes + "'"); |
| out.print(" usesScalingStrokes='" + tag.usesScalingStrokes + "'"); |
| } |
| end(); |
| printMorphLineStyles(tag.lineStyles); |
| printMorphFillStyles(tag.fillStyles); |
| |
| indent(); |
| out.println("<start>"); |
| indent++; |
| printShape(tag.startEdges, true); |
| indent--; |
| indent(); |
| out.println("</start>"); |
| |
| indent(); |
| out.println("<end>"); |
| indent++; |
| printShape(tag.endEdges, true); |
| indent--; |
| indent(); |
| out.println("</end>"); |
| |
| close(tag); |
| } |
| |
| public void defineFont2(DefineFont2 tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| out.print(" font='" + tag.fontName + "'"); |
| out.print(" numGlyphs='" + tag.glyphShapeTable.length + "'"); |
| out.print(" italic='" + tag.italic + "'"); |
| out.print(" bold='" + tag.bold + "'"); |
| out.print(" ansi='" + tag.ansi + "'"); |
| out.print(" wideOffsets='" + tag.wideOffsets + "'"); |
| out.print(" wideCodes='" + tag.wideCodes + "'"); |
| out.print(" shiftJIS='" + tag.shiftJIS + "'"); |
| out.print(" langCode='" + tag.langCode + "'"); |
| out.print(" hasLayout='" + tag.hasLayout + "'"); |
| out.print(" ascent='" + tag.ascent + "'"); |
| out.print(" descent='" + tag.descent + "'"); |
| out.print(" leading='" + tag.leading + "'"); |
| out.print(" kerningCount='" + tag.kerningCount + "'"); |
| |
| out.print(" codepointCount='" + tag.codeTable.length + "'"); |
| |
| if (tag.hasLayout) |
| { |
| out.print(" advanceCount='" + tag.advanceTable.length + "'"); |
| out.print(" boundsCount='" + tag.boundsTable.length + "'"); |
| } |
| end(); |
| |
| if (glyphs) |
| { |
| for (int i=0; i < tag.kerningCount; i++) |
| { |
| KerningRecord rec = tag.kerningTable[i]; |
| indent(); |
| out.println("<kerningRecord adjustment='" + rec.adjustment + "' code1='" + rec.code1 + "' code2='" + rec.code2 + "' />"); |
| } |
| |
| for (int i = 0; i < tag.glyphShapeTable.length; i++) |
| { |
| indent(); |
| out.print("<glyph"); |
| out.print(" codepoint='" + ((int)tag.codeTable[i]) + (isPrintable(tag.codeTable[i]) ? ("(" + tag.codeTable[i] + ")") : "(?)") + "'"); |
| if (tag.hasLayout) |
| { |
| out.print(" advance='" + tag.advanceTable[i] + "'"); |
| out.print(" bounds='" + tag.boundsTable[i] + "'"); |
| } |
| out.println(">"); |
| |
| Shape shape = tag.glyphShapeTable[i]; |
| indent++; |
| if (tabbedGlyphs) |
| printShapeWithTabs(shape); |
| else |
| printShape(shape, true); |
| indent--; |
| indent(); |
| out.println("</glyph>"); |
| } |
| } |
| |
| close(tag); |
| } |
| |
| public void defineFont3(DefineFont3 tag) |
| { |
| defineFont2(tag); |
| } |
| |
| public void defineFont4(DefineFont4 tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| out.print(" font='" + tag.fontName + "'"); |
| out.print(" hasFontData='" + tag.hasFontData + "'"); |
| out.print(" smallText='" + tag.smallText + "'"); |
| out.print(" italic='" + tag.italic + "'"); |
| out.print(" bold='" + tag.bold + "'"); |
| out.print(" langCode='" + tag.langCode + "'"); |
| end(); |
| |
| if (glyphs && tag.hasFontData) |
| { |
| outputBase64(tag.data); |
| } |
| |
| close(tag); |
| } |
| |
| public void defineFontAlignZones(DefineFontAlignZones tag) |
| { |
| open(tag); |
| if (tag.name != null) |
| out.print(" id='" + id(tag) + "'"); |
| out.print(" fontID='" + id(tag.font) + "'"); |
| out.print(" CSMTableHint='" + tag.csmTableHint + "'"); |
| out.println(">"); |
| indent++; |
| indent(); |
| out.println("<ZoneTable length='" + tag.zoneTable.length + "'>"); |
| indent++; |
| if (glyphs) |
| { |
| for (int i = 0; i < tag.zoneTable.length; i++) |
| { |
| ZoneRecord record = tag.zoneTable[i]; |
| indent(); |
| out.print("<ZoneRecord num='" + record.numZoneData + "' mask='" + record.zoneMask + "'>"); |
| for (int j = 0; j < record.zoneData.length; j++) |
| { |
| out.print(record.zoneData[j] + " "); |
| } |
| out.println("</ZoneRecord>"); |
| } |
| } |
| indent--; |
| indent(); |
| out.println("</ZoneTable>"); |
| close(tag); |
| } |
| |
| public void csmTextSettings(CSMTextSettings tag) |
| { |
| open(tag); |
| if (tag.name != null) |
| out.print(" id='" + id(tag) + "'"); |
| |
| String textID = tag.textReference == null ? "0" : id(tag.textReference); |
| out.print(" textID='" + textID + "'"); |
| out.print(" styleFlagsUseSaffron='" + tag.styleFlagsUseSaffron + "'"); |
| out.print(" gridFitType='" + tag.gridFitType + "'"); |
| out.print(" thickness='" + tag.thickness + "'"); |
| out.print(" sharpness='" + tag.sharpness + "'"); |
| close(); |
| } |
| |
| public void defineFontName(DefineFontName tag) |
| { |
| open(tag); |
| if (tag.name != null) |
| out.print(" id='" + id(tag) + "'"); |
| out.print(" fontID='" + id(tag.font) + "'"); |
| if (tag.fontName != null) |
| { |
| out.print(" name='" + tag.fontName + "'"); |
| } |
| if (tag.copyright != null) |
| { |
| out.print(" copyright='" + tag.copyright + "'"); |
| } |
| |
| close(); |
| } |
| |
| private boolean isPrintable(char c) |
| { |
| int i = c & 0xFFFF; |
| if (i < ' ' || i == '<' || i == '&' || i == '\'') |
| return false; |
| else |
| return true; |
| } |
| |
| |
| public void exportAssets(ExportAssets tag) |
| { |
| open(tag); |
| end(); |
| |
| Iterator it = tag.exports.iterator(); |
| while (it.hasNext()) |
| { |
| DefineTag ref = (DefineTag)it.next(); |
| indent(); |
| out.println("<Export idref='" + dict.getId(ref) + "' name='" + ref.name + "' />"); |
| } |
| |
| close(tag); |
| } |
| |
| public void symbolClass(SymbolClass tag) |
| { |
| open(tag); |
| end(); |
| |
| Iterator it = tag.class2tag.entrySet().iterator(); |
| while (it.hasNext()) |
| { |
| Map.Entry e = (Map.Entry)it.next(); |
| String className = (String)e.getKey(); |
| DefineTag ref = (DefineTag)e.getValue(); |
| indent(); |
| out.println("<Symbol idref='" + dict.getId(ref) + "' className='" + className + "' />"); |
| } |
| |
| if (tag.topLevelClass != null) |
| { |
| indent(); |
| out.println("<Symbol idref='0' className='" + tag.topLevelClass + "' />"); |
| } |
| |
| |
| close(tag); |
| } |
| |
| public void importAssets(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='" + dict.getId(record) + "' />"); |
| } |
| |
| close(tag); |
| } |
| |
| public void importAssets2(ImportAssets tag) |
| { |
| // TODO: add support for tag.downloadNow and SHA1... |
| importAssets(tag); |
| } |
| |
| public void enableDebugger(EnableDebugger tag) |
| { |
| open(tag); |
| out.print(" password='" + tag.password + "'"); |
| close(); |
| } |
| |
| public void doInitAction(DoInitAction tag) |
| { |
| if (tag.sprite != null && tag.sprite.name != null) |
| { |
| indent(); |
| out.println("<!-- init " + tag.sprite.name + " " + dict.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); |
| } |
| |
| private String idRef(DefineTag 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 (tag.name == null) |
| { |
| // just print the character id since no name was exported |
| return String.valueOf(dict.getId(tag)); |
| } |
| else |
| { |
| return tag.name; |
| } |
| } |
| |
| public void defineVideoStream(DefineVideoStream tag) |
| { |
| open(tag); |
| out.print(" id='" + id(tag) + "'"); |
| close(); |
| } |
| |
| public void videoFrame(VideoFrame tag) |
| { |
| open(tag); |
| out.print(" streamId='" + idRef(tag.stream) + "'"); |
| out.print(" frame='" + tag.frameNum + "'"); |
| close(); |
| } |
| |
| public void defineFontInfo2(DefineFontInfo tag) |
| { |
| defineFontInfo(tag); |
| } |
| |
| public void enableDebugger2(EnableDebugger tag) |
| { |
| open(tag); |
| out.print(" password='" + tag.password + "'"); |
| out.print(" reserved='0x" + Integer.toHexString(tag.reserved) + "'"); |
| close(); |
| } |
| |
| public void debugID(DebugID tag) |
| { |
| open(tag); |
| out.print(" uuid='" + tag.uuid + "'"); |
| close(); |
| } |
| |
| public void scriptLimits(ScriptLimits tag) |
| { |
| open(tag); |
| out.print(" scriptRecursionLimit='" + tag.scriptRecursionLimit + "'" + |
| " scriptTimeLimit='" + tag.scriptTimeLimit + "'"); |
| close(); |
| } |
| |
| public void setTabIndex(SetTabIndex tag) |
| { |
| open(tag); |
| out.print(" depth='" + tag.depth + "'"); |
| out.print(" index='" + tag.index + "'"); |
| close(); |
| } |
| |
| public void doABC(DoABC tag) |
| { |
| if (abc) |
| { |
| open(tag); |
| end(); |
| AbcPrinter abcPrinter = new AbcPrinter(tag.abc, out, showOffset, indent, showByteCode); |
| abcPrinter.print(); |
| close(tag); |
| } |
| else if (showActions) |
| { |
| open(tag); |
| if (tag.code == TagValues.stagDoABC2) |
| out.print( " name='" + tag.name + "'"); |
| end(); |
| |
| ContextStatics contextStatics = new ContextStatics(); |
| contextStatics.use_static_semantics = true; |
| contextStatics.dialect = 9; |
| |
| assert swfVersion != null : "header should have been parsed already, but wasn't"; |
| contextStatics.setAbcVersion(ContextStatics.getTargetAVM(swfVersion)); |
| contextStatics.use_namespaces.addAll(ContextStatics.getRequiredUseNamespaces(swfVersion)); |
| |
| Context context = new Context(contextStatics); |
| context.setHandler(new CompilerHandler()); |
| AbcParser abcParser = new AbcParser(context, tag.abc); |
| context.setEmitter(new ActionBlockEmitter(context, tag.name, new StringPrintWriter(), |
| new StringPrintWriter(), false, false, false, false)); |
| ProgramNode programNode = abcParser.parseAbc(); |
| |
| if (programNode == null) |
| { |
| out.println("<!-- Error: could not parse abc -->"); |
| } |
| else if (decompile) |
| { |
| // PrettyPrinter prettyPrinter = new PrettyPrinter(out); |
| // programNode.evaluate(context, prettyPrinter); |
| } |
| else |
| { |
| SyntaxTreeDumper syntaxTreeDumper = new SyntaxTreeDumper(out, indent); |
| programNode.evaluate(context, syntaxTreeDumper); |
| } |
| |
| close(tag); |
| } |
| else |
| { |
| open(tag); |
| close(); |
| } |
| } |
| |
| 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 |
| static boolean abcOption = 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 tabbedGlyphsOption = true; |
| |
| |
| /** |
| * swfdump usage: swfdump [-encode] [-noactions] [-showoffset] files ... |
| * -encode ? |
| * -noactions don't output ActionScript byte code |
| * -showoffset output an XML comment line in the output before each |
| * tag, displaying the tag's byte offset and size in the file |
| * <p/> |
| * Swfdump will dump a SWF file as XML. Swf tags are shown as XML tags. Swf Actions are shown |
| * commented out assembly language. If a SWD file is found that matches this SWF file, then |
| * we will show intermixed source code and assembly language. |
| * <p/> |
| * The format of the output (swfx) is according to the SWFX doctype. The optional -dtd flag will |
| * include the doctype declaration before the actual content. This format can be edited in any |
| * text or xml editor, and then converted back into SWF using the Swfxc utility. |
| */ |
| public static void main(String[] args) throws IOException |
| { |
| if (args.length == 0) |
| { |
| System.err.println("Usage: java tools.SwfxPrinter [-encode] [-asm] [-abc] [-showbytecode] [-noactions] [-showdebugsource] [-showoffset] [-noglyphs] [-external] [-save file.swf] [-nofunctions] [-out file.swfx] 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("-save")) |
| { |
| ++index; |
| saveOption = 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(new FileOutputStream(outfile, false)); |
| } |
| 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(System.out, true); |
| |
| File f = new File(args[index]); |
| URL[] urls; |
| if (!f.exists()) |
| { |
| urls = new URL[]{new URL(args[index])}; |
| } |
| else |
| { |
| if (f.isDirectory()) |
| { |
| File[] list = FileUtils.listFiles(f); |
| urls = new URL[list.length]; |
| for (int i = 0; i < list.length; i++) |
| { |
| urls[i] = FileUtils.toURL(list[i]); |
| } |
| } |
| else |
| { |
| urls = new URL[]{FileUtils.toURL(f)}; |
| } |
| } |
| |
| 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 (isSwf(url)) |
| { |
| dumpSwf(out, url, outfile); |
| } |
| else if (isZip(url) && !url.toString().endsWith(".abj")) |
| { |
| dumpZip(out, url, outfile); |
| } |
| else |
| { |
| out.println("<!-- Parsing actions from " + url + " -->"); |
| // we have no way of knowing the swf version, so assume latest |
| URLConnection connection = url.openConnection(); |
| ActionDecoder actionDecoder = new ActionDecoder(new SwfDecoder(connection.getInputStream(), 7)); |
| actionDecoder.setKeepOffsets(true); |
| ActionList actions = actionDecoder.decode(connection.getContentLength()); |
| SwfxPrinter printer = new SwfxPrinter(out); |
| printer.decompile = decompileOption; |
| printer.defunc = defuncOption; |
| printer.printActions(actions); |
| } |
| 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); |
| } |
| } |
| } |
| |
| private static void dumpZip(PrintWriter out, URL url, String outfile) throws IOException |
| { |
| InputStream in = new BufferedInputStream(url.openStream()); |
| try |
| { |
| ZipInputStream zipIn = new ZipInputStream(in); |
| ZipEntry zipEntry = zipIn.getNextEntry(); |
| while ((zipEntry != null)) |
| { |
| URL fileUrl = new URL("jar:" + url.toString() + "!/" + zipEntry.getName()); |
| if (isSwf(fileUrl)) |
| dumpSwf(out, fileUrl, outfile); |
| zipEntry = zipIn.getNextEntry(); |
| } |
| } |
| finally |
| { |
| in.close(); |
| } |
| } |
| |
| private static void dumpSwf(PrintWriter out, URL url, String outfile) |
| throws IOException |
| { |
| out.println("<!-- Parsing swf " + url + " -->"); |
| InputStream in; |
| SwfxPrinter debugPrinter = new SwfxPrinter(out); |
| |
| debugPrinter.showActions = showActionsOption; |
| debugPrinter.showOffset = showOffsetOption; |
| debugPrinter.showByteCode = showByteCodeOption; |
| debugPrinter.showDebugSource = showDebugSourceOption; |
| debugPrinter.glyphs = glyphsOption; |
| debugPrinter.setExternal(externalOption, outfile); |
| debugPrinter.decompile = decompileOption; |
| debugPrinter.abc = abcOption; |
| debugPrinter.defunc = defuncOption; |
| debugPrinter.tabbedGlyphs = tabbedGlyphsOption; |
| |
| if (encodeOption) |
| { |
| // decode -> encode -> decode -> print |
| TagEncoder encoder = new TagEncoder(); |
| in = url.openStream(); |
| new TagDecoder(in, url).parse(encoder); |
| encoder.finish(); |
| in = new ByteArrayInputStream(encoder.toByteArray()); |
| } |
| else |
| { |
| // decode -> print |
| in = url.openStream(); |
| } |
| TagDecoder t = new TagDecoder(in, url); |
| t.setKeepOffsets(debugPrinter.showOffset); |
| t.parse(debugPrinter); |
| } |
| |
| private static boolean isSwf(URL url) throws IOException |
| { |
| InputStream in = new BufferedInputStream(url.openStream()); |
| try |
| { |
| return isSwf(in); |
| } |
| finally |
| { |
| in.close(); |
| } |
| } |
| |
| public static boolean isSwf(InputStream in) |
| { |
| try |
| { |
| DataInputStream data = new DataInputStream(in); |
| byte[] b = new byte[3]; |
| data.mark(b.length); |
| data.readFully(b); |
| if (b[0] == 'C' && b[1] == 'W' && b[2] == 'S' || |
| b[0] == 'F' && b[1] == 'W' && b[2] == 'S') |
| { |
| data.reset(); |
| return true; |
| } |
| else |
| { |
| data.reset(); |
| return false; |
| } |
| } |
| catch (IOException e) |
| { |
| return false; |
| } |
| } |
| |
| private static boolean isZip(URL url) throws IOException |
| { |
| InputStream in = new BufferedInputStream(url.openStream()); |
| try |
| { |
| return isZip(in); |
| } |
| finally |
| { |
| in.close(); |
| } |
| } |
| |
| public static boolean isZip(InputStream in) |
| { |
| try |
| { |
| ZipInputStream swcZipInputStream = new ZipInputStream(in); |
| swcZipInputStream.getNextEntry(); |
| return true; |
| } |
| catch (IOException e) |
| { |
| return false; |
| } |
| } |
| |
| // Handy dandy for dumping an action list during debugging |
| public static String actionListToString(ActionList al, String[] args) |
| { |
| // cut and paste arg code from main() could be better but it works |
| boolean showActions = true; |
| boolean showOffset = false; |
| boolean showDebugSource = false; |
| boolean decompile = false; |
| boolean defunc = true; |
| boolean tabbedGlyphs = true; |
| int index = 0; |
| |
| while (args != null && (index < args.length) && (args[index].startsWith("-"))) |
| { |
| if (args[index].equals("-decompile")) |
| { |
| decompile = true; |
| ++index; |
| } |
| else if (args[index].equals("-nofunctions")) |
| { |
| defunc = false; |
| ++index; |
| } |
| else if (args[index].equals("-asm")) |
| { |
| decompile = false; |
| ++index; |
| } |
| else if (args[index].equals("-noactions")) |
| { |
| showActions = false; |
| ++index; |
| } |
| else if (args[index].equals("-showoffset")) |
| { |
| showOffset = true; |
| ++index; |
| } |
| else if (args[index].equals("-showdebugsource")) |
| { |
| showDebugSource = true; |
| ++index; |
| } |
| else if (args[index].equalsIgnoreCase("-tabbedGlyphs")) |
| { |
| tabbedGlyphs = true; |
| ++index; |
| } |
| } |
| |
| StringWriter sw = new StringWriter(); |
| PrintWriter out = new PrintWriter(sw); |
| SwfxPrinter printer = new SwfxPrinter(out); |
| printer.showActions = showActions; |
| printer.showOffset = showOffset; |
| printer.showDebugSource = showDebugSource; |
| printer.decompile = decompile; |
| printer.defunc = defunc; |
| printer.tabbedGlyphs = tabbedGlyphs; |
| |
| printer.printActions(al); |
| out.flush(); |
| return sw.toString(); |
| } |
| } |