All Downloads are FREE. Search and download functionalities are using the official Maven repository.

flash.swf.DebugDecoder Maven / Gradle / Ivy

/*
 *
 *  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;

import flash.swf.debug.DebugModule;
import flash.swf.debug.LineRecord;
import flash.swf.debug.RegisterRecord;
import flash.swf.types.FlashUUID;
import flash.util.FileUtils;
import flash.util.IntMap;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.File;
import java.util.ArrayList;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * The swd file format is as follows
 *
 * swd(header) (tag)*
 */
public class DebugDecoder
{
	public static final int
		kDebugScript=0,
		kDebugOffset=1,
		kDebugBreakpoint=2,
		kDebugID=3,
		kDebugRegisters=5
	;

    /**
     * table of line numbers, indexed by offset in the SWF file
     */
    private SwfDecoder in;
    private IntMap modules = new IntMap();

    public DebugDecoder(byte[] b)
    {
        this(new ByteArrayInputStream(b));
    }

    public DebugDecoder(InputStream in)
    {
        this.in = new SwfDecoder(in, 0);
    }

    public void readSwd(DebugHandler h) throws IOException
    {
        readHeader(h);
        readTags(h);
    }

    void readHeader(DebugHandler handler) throws IOException
    {
        byte[] sig = new byte[4];

        in.readFully(sig);

        if (sig[0] != 'F' || sig[1] != 'W' || sig[2] != 'D' || sig[3] < 6)
        {
            throw new SwfFormatException("not a Flash 6 or later SWD file");
        }

		in.swfVersion = sig[3];

        handler.header(in.swfVersion);
    }

	public void setTagData(byte[] b) throws IOException
	{
		in = new SwfDecoder(b, 0);
	}

    public void readTags(DebugHandler handler) throws IOException
    {
    	//  because it holds groups of {Integer, LineRecord, Integer}
		ArrayList lineRecords = new ArrayList();

		do
		{
			int tag = (int) in.readUI32();
			switch (tag)
			{
			case kDebugScript:
				DebugModule m = new DebugModule();
				int id = (int) in.readUI32();
				m.id = id;
				m.bitmap = (int) in.readUI32();
				m.name = in.readString();
				m.setText(in.readString());

				adjustModuleName(m);

				if (modules.contains(id))
				{
					DebugModule m2 = (DebugModule) modules.get(id);
					if (!m.equals(m2))
					{
						handler.error("Module '" + m2.name + "' has the same ID as Module '" + m.name + "'");
						handler.error("Let's check for kDebugOffset that came before Module '" + m2.name + "'");
						handler.error("Before: Number of accumulated line records: " + lineRecords.size());
						lineRecords = purgeLineRecords(lineRecords, id, handler);
						handler.error("After: Number of accumulated line records: " + lineRecords.size());
					}
				}
				modules.put(id, m);
				handler.module(m);
				break;
			case kDebugOffset:
				id = (int) in.readUI32();
				int lineno = (int) in.readUI32();
				DebugModule module = (DebugModule) modules.get(id);
				LineRecord lr = new LineRecord(lineno, module);
				int offset = (int) in.readUI32();

				if (module != null)
				{
					// not corrupted before we add the offset and offset add fails
					boolean wasCorrupt = module.corrupt;
					if (!module.addOffset(lr, offset) && !wasCorrupt)
						handler.error(module.name+":"+lineno+" does not exist for offset "+offset+", module marked for exclusion from debugging");
					handler.offset(offset, lr);
				}
				else
				{
					lineRecords.add(new Integer(id));
					lineRecords.add(lr);
					lineRecords.add(new Integer(offset));
				}
				break;
			case kDebugBreakpoint:
				handler.breakpoint((int) in.readUI32());
				break;
			case kDebugRegisters:
			{
				offset = (int)in.readUI32();
				int size = in.readUI8();
				RegisterRecord r = new RegisterRecord(offset, size);
				for(int i=0; i"))
		{
			return name;
		}

		String token1, token2;

		// if the url is not malformed, return it
		try
		{
			@SuppressWarnings("unused")
			URL u = new URL(name);
			// good URL, return...
			return name;
		}
		catch (MalformedURLException ex)
		{
			// not an URL, continue...
		}

		File f;

		try
		{
			f = new File(name);
		}
		catch (java.lang.Error nf)
		{
			// the CLR will throw this when a java.io.File object is init'd in a location
			// that causes a .NET System.SecurityException - can't create File objects on
			// .NET as a way of testing whether they are valid files without catching the error
			f = null;
		}

		if (f == null || !f.isFile())
		{
			int colon = name.indexOf(':');
			if (colon != -1)
			{
				token1 = name.substring(0, colon).trim();
				token2 = name.substring(colon + 1).trim();
			}
			else
			{
				token1 = "";
				token2 = name;
			}
		}
		else
		{
			token1 = "";
			token2 = name;
		}

		try
		{
			f = new File(token2);
		}
		catch (java.lang.Error nf)
		{
			// the CLR will throw this when a java.io.File object is init'd in a location
			// that causes a .NET System.SecurityException - can't create File objects on
			// .NET as a way of testing whether they are valid files without catching the error
			f = null;
		}

		if (f != null && f.isFile())
		{
			try
			{
				if (token2.indexOf("..") != -1 || token2.indexOf(".") != -1)
				{
					f = FileUtils.getCanonicalFile(f);
				}
				token2 = FileUtils.toURL(f).toString();
			}
			catch (IOException ex)
			{
			}
		}

		if (token1.length() == 0)
		{
			name = token2;
		}
		else
		{
			name = token1.trim() + ": " + token2.trim();
		}

		return name;
	}
}