blob: 226dd72cecc26ca257d8fc1c34e047a519ca1080 [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 flash.tools.debugger.concrete;
import java.util.Map;
import flash.swf.debug.DebugModule;
import flash.swf.debug.LineRecord;
import flash.tools.ActionLocation;
import flash.tools.debugger.InProgressException;
import flash.tools.debugger.Isolate;
import flash.tools.debugger.NoResponseException;
import flash.tools.debugger.Session;
import flash.tools.debugger.SourceFile;
import flash.tools.debugger.SwfInfo;
import flash.tools.debugger.events.FunctionMetaDataAvailableEvent;
import flash.util.IntMap;
public class DSwfInfo implements SwfInfo
{
private int m_index;
private long m_id;
private IntMap m_source;
private String m_path;
private String m_url;
private String m_host;
private int m_port;
private boolean m_swdLoading;
private int m_swfSize;
private int m_swdSize;
private int m_bpCount;
private int m_offsetCount;
private int m_scriptsExpected;
private int m_minId; // first script id in the swf
private int m_maxId; // last script id in this swf
private byte[] m_swf; // actual swf contents
private byte[] m_swd; // actual swd contents
private boolean m_unloaded; // set if the player has unloaded this swf
private Map<Long,Integer> m_local2Global; // local script id to global script id mapping table
private int m_numRefreshes; // number of refreshes we have taken
private int m_vmVersion; // version of the vm
private boolean m_populated; // set if we have already tried to load swf/swd for this info
private LineFunctionContainer m_container; // used for pulling out detailed info about the swf
private final static String UNKNOWN = PlayerSessionManager.getLocalizationManager().getLocalizedTextString("unknown"); //$NON-NLS-1$
public DSwfInfo(int index, int isolateId)
{
// defaults values of zero
m_id = 0;
m_index = index;
m_source = new IntMap();
m_path = UNKNOWN;
m_url = UNKNOWN;
m_host = UNKNOWN;
m_port = 0;
m_swdLoading = true;
m_scriptsExpected = -1; // means not yet set by anyone!
m_isolateId = isolateId;
// rest default to null, 0 or false
}
/** SwfInfo interface */
public String getPath() { return m_path; }
public String getUrl() { return m_url; }
public int getSwfSize() { return m_swfSize; }
public int getSwdSize(Session s) throws InProgressException { swdLoaded(s); return m_swdSize; }
public boolean isUnloaded() { return m_unloaded; }
public boolean isProcessingComplete() { return isPopulated(); }
public boolean containsSource(SourceFile f) { return m_source.contains(f.getId()); }
/* getters */
public long getId() { return m_id; }
public String getHost() { return m_host; }
public int getPort() { return m_port; }
public int getSwdSize() { return m_swdSize; }
public int getRefreshCount() { return m_numRefreshes; }
public boolean isSwdLoading() { return m_swdLoading; }
public boolean isPopulated() { return m_populated; }
public byte[] getSwf() { return m_swf; }
public byte[] getSwd() { return m_swd; }
public int getSourceExpectedCount() { return m_scriptsExpected; }
public int getVmVersion() { return m_vmVersion; }
// public int getBreakpointCount() throws InProgressException { swdLoading(); return m_bpCount; }
// public int getOffsetCount() { swdLoading(); return m_offsetCount; }
public int getSourceCount() { return m_source.size(); }
public int getFirstSourceId() { return m_minId; }
public int getLastSourceId() { return m_maxId; }
public void setVmVersion(int vmVersion) { m_vmVersion = vmVersion; }
public void setUnloaded() { m_unloaded = true; }
public void setSwf(byte[] swf) { m_swf = swf; }
public void setSwd(byte[] swd) { m_swd = swd; }
public void setPopulated() { m_swdLoading = false; m_populated = true; } // no more waiting for swd, we're done
public void setSourceExpectedCount(int c) { m_scriptsExpected = c; }
public void addSource(int i, DModule m) { m_source.put(i, m); }
/**
* Return the number of sources that we have
*/
public int getSourceCount(Session s) throws InProgressException
{
// only if we don't have it all yet
// then try to force a load
if (!hasAllSource())
swdLoaded(s);
return getSourceCount();
}
/**
* Return a list of our sources
*/
public SourceFile[] getSourceList(Session s) throws InProgressException
{
// only if we don't have it all yet
// then try to force a load
if (!hasAllSource())
swdLoaded(s);
return (SourceFile[])m_source.valuesToArray( new SourceFile[m_source.size()] );
}
/**
* Make sure that the player has loaded our swd. If not
* we continue InProgressException to query the player for when its complete.
* At some point we give up and finally admit that
* we don't have a swd associated with this swf.
*/
void swdLoaded(Session s) throws InProgressException
{
if (isSwdLoading() && !isUnloaded())
{
// make the request
// System.out.println("Swdloaded " + m_isolateId);
try { ((PlayerSession)s).requestSwfInfo(m_index, m_isolateId); } catch(NoResponseException nre) {}
// I should now be complete
if (!m_swdLoading)
; // done!
else if (getSourceExpectedCount() > -1 && m_numRefreshes > 10)
setPopulated(); // tried too many times, so bail big time, no swd available (only if we already have our expected count)
else
throw new InProgressException(); // still loading!!!
}
}
/**
* This method returns true once we have all the scripts
* that we expect to ever have. We can get the information about
* how many scripts we should get from two sources, 1) we may
* get an InSwfInfo message from the player which contains
* this value and 2) we may get a InNumScript message which
* contains a script count. A small caveat of course, is that
* in case 1. we may also not get the a value if the swd has
* not been fully processed by the player yet.
*/
public boolean hasAllSource()
{
boolean yes = false;
int expect = getSourceExpectedCount();
int have = getSourceCount();
// if they are equal we are done, unless
// our expectation has not been set and have not yet loaded our swd
if (expect == -1 && isSwdLoading())
yes = false;
else if (expect == have)
yes = true;
else
yes = false;
return yes;
}
public void freshen(long id, String path, String url, String host, long port, boolean swdLoading, long swfSize, long swdSize, long bpCount, long offsetCount, long scriptCount, Map<Long,Integer> map, int minId, int maxId)
{
m_id = (int)id;
m_path = path;
m_url = url;
m_host = host;
m_port = (int)port;
m_swfSize = (int)swfSize;
m_swdSize = (int)swdSize;
m_bpCount = (int)bpCount;
m_offsetCount = (int)offsetCount;
m_local2Global = map;
m_minId = (swdSize > 0) ? minId : 0;
m_maxId = (swdSize > 0) ? maxId : 0;
m_swdLoading = swdLoading;
m_numRefreshes++;
// only touch expected count if swd already loaded
if (!swdLoading)
m_scriptsExpected = (int)scriptCount;
}
/**
* Locate the given offset within the swf
*/
public ActionLocation locate(int offset)
{
return m_container.locationLessOrEqualTo(offset);
}
/**
* Ask the container to locate the next line
* record following the location specified in the
* location, without spilling over into the next
* action list
*/
public ActionLocation locateSourceLineEnd(ActionLocation l)
{
return locateSourceLineEnd(l, -1);
}
public ActionLocation locateSourceLineEnd(ActionLocation l, int stopAt)
{
ActionLocation end = m_container.endOfSourceLine(l);
if (stopAt > -1 && end.at > stopAt)
end.at = stopAt;
return end;
}
/**
* Use the local2global script id map that was provided by the
* Player, so that we can take the local id contained in the swd
* and convert it to a global one that the player has annointed
* to this script.
*/
int local2Global(long id)
{
Integer g = m_local2Global.get(id);
if (g != null)
id = g.intValue();
return (int) id;
}
/**
* Freshen the contents of this object with the given swf info
* The items that we touch are all swd related, as everything else
* has arrriave
*/
// temporary while we parse
DManager m_manager;
private int m_isolateId = Isolate.DEFAULT_ID;
/**
* Extracts information out of the SWF/SWD in order to populate
* function line number tables in SourceFile variabels.
*/
public void parseSwfSwd(DManager manager)
{
m_manager = manager;
// suck in the swf/swd into action lists and then walk the lists
// looking for LineRecords
m_container = new LineFunctionContainer(m_swf, m_swd);
m_container.combForLineRecords(this);
// we are done, sucess or no
setPopulated();
// log event that we have complete done
manager.addEvent(new FunctionMetaDataAvailableEvent());
m_manager = null;
}
/**
* This is a callback function from LineFunctionContainer.combForLineRecords()
* We extract what we want and then update the associated module
*/
public void processLineRecord(ActionLocation where, LineRecord r)
{
int line = r.lineno;
String func = (where.function == null) ? null : where.function.name;
DebugModule dm = r.module;
// locate the source file
int id = -1;
DModule module;
if (dm == null || where.at == -1)
;
else if ( (id = local2Global(dm.id)) < 0 )
;
else if ( (module = m_manager.getSource(id, Isolate.DEFAULT_ID)) == null )
;
else
module.addLineFunctionInfo(where.actions.getOffset(where.at), line, func);
}
/* for debugging */
@Override
public String toString() {
return m_path;
}
@Override
public int getIsolateId() {
return m_isolateId;
}
}