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