Package flex.tools.debugger.cli

Source Code of flex.tools.debugger.cli.FileInfoCache

/*
*
*  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 flex.tools.debugger.cli;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;

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.util.IntMap;

/**
* FileInfoCache manages a list of files that are unique
* across multiple swfs.
*/
public class FileInfoCache implements Comparator<SourceFile>
{
  Session m_session;

  /**
   * We can get at files by module id or path
   */
  IntMap        m_byInt = new IntMap();
  HashMap<Integer, IntMap> m_isolateState = new HashMap<Integer, IntMap> ();

  private IntMap getIsolateState(int isolateId) {
    IntMap isolateState = null;
    if (!m_isolateState.containsKey(isolateId)) {
      isolateState = new IntMap();
      m_isolateState.put(isolateId, isolateState);
    }
    else
      isolateState = m_isolateState.get(isolateId);
    return isolateState;
  }

  SourceFile[]    m_files = null;
  SourceFile[]    m_isolateFiles = null;
  SwfInfo        m_swfFilter = null;
  int          m_swfsLoaded = 0;
    boolean             m_dirty = false;
    int lastActiveIsolate = Isolate.DEFAULT_ID;

  public FileInfoCache() {

  }

  public void      bind(Session s)                  { setSession(s); }
  public void      unbind()                    { m_session = null; }

  public SourceFile getFile(int i) {
    return getFile(i, Isolate.DEFAULT_ID);
  }

  public SourceFile getFile(int i, int isolateId) {
    populate();
    if (isolateId == Isolate.DEFAULT_ID)
      return (SourceFile) m_byInt.get(i);
    else
      return (SourceFile)getIsolateState(isolateId).get(i);
  }

  public SourceFile[] getFileList() {
    populate();
    return m_files;
  }

  public SourceFile[] getFileList(int isolateId) {
    populate();
    if (isolateId == Isolate.DEFAULT_ID) {
            final Object[] valuesToArray = m_byInt.valuesToArray(new Object[m_byInt.size()]);
            return Arrays.copyOf(valuesToArray, valuesToArray.length, SourceFile[].class);
        }
    else if (isolateId != lastActiveIsolate) {
      buildIsolateFiles(isolateId);
    }
    return m_isolateFiles;
  }

  private void buildIsolateFiles(int isolateId) {
    SwfInfo[] swfs = getSwfs(isolateId);
    boolean worked = true; // check that all worked correctly
    ArrayList<SourceFile> files = new ArrayList<SourceFile>();

    for(int i=0; i<swfs.length; i++)
    {
      if (swfs[i] != null)
        worked = loadSwfFiles(files, swfs[i]) ? worked : false;
    }

    // trim the file list
    ArrayList<SourceFile> fa = trimFileList(files);
    m_isolateFiles = fa.toArray( new SourceFile[fa.size()] );

    // sort this array in place so calls to getFileList will be ordered
    Arrays.sort(m_isolateFiles, this);
  }

  public Iterator getAllFiles(int isolateId) {
    populate();
    if (isolateId == Isolate.DEFAULT_ID)
      return m_byInt.iterator();
    else
      return getIsolateState(isolateId).iterator();
  }

    public SwfInfo      getSwfFilter()                                  { return m_swfFilter; }
    public boolean      isSwfFilterOn()                                 { return (m_swfFilter != null); }
    public void         setDirty()                                      { m_dirty = true; }

  void setSession(Session s)
  {
    m_session = s;
    m_swfFilter = null;
    clear();
  }

  SwfInfo[] getAllSwfs() {
    ArrayList<SwfInfo> result = new ArrayList<SwfInfo>();

    for ( Isolate isolate : m_session.getWorkers()) {
      SwfInfo[] swfs = new SwfInfo[0];
      try {
        swfs = m_session.getWorkerSession(isolate.getId()).getSwfs();
      } catch (NoResponseException e) {
        swfs = new SwfInfo[0];
      }

      for (SwfInfo swf : swfs)
        result.add(swf);
    }

    return result.toArray(new SwfInfo[0]);
  }

  void populate()
  {
    // do we have a new swf to load?
    if (m_session != null && (m_dirty || getAllSwfs().length > m_swfsLoaded))
      reloadCache();
  }

  void reloadCache()
  {
    clear();
    loadCache();
        m_dirty = false;
  }

  void clear()
  {
    m_byInt.clear();
    m_isolateState.clear();
    m_files = null;
  }

  /**
   * Determine if the given SourceFile is in the current fileList
   */
  public boolean inFileList(SourceFile f)
  {
    boolean isIt = false;

    SourceFile[] files = getFileList();
    for(int i=0; i<files.length && !isIt; i++)
    {
      if (files[i] == f)
        isIt = true;
    }
    return isIt;
  }

  /**
   * Go out to the session and request a list of files
   * But we dump ones that have a name collision.
   * Also if selectedSwf is set then we only add files
   * that are contained within the given swf.
   */
  void loadCache()
  {
    boolean worked = true; // check that all worked correctly
    ArrayList<SourceFile> files = new ArrayList<SourceFile>();
    SwfInfo[] swfs = getAllSwfs();
    for(int i=0; i<swfs.length; i++)
    {
      if (swfs[i] != null)
        worked = loadSwfFiles(files, swfs[i]) ? worked : false;
    }

    // trim the file list
    ArrayList<SourceFile> fa = trimFileList(files);
    m_files = fa.toArray( new SourceFile[fa.size()] );

    // sort this array in place so calls to getFileList will be ordered
    Arrays.sort(m_files, this);

    // mark our cache complete if all was good.
    if (worked)
      m_swfsLoaded = swfs.length;
  }

  boolean loadSwfFiles(ArrayList<SourceFile> ar, SwfInfo swf)
  {
    boolean worked = true;
    try
    {
      // @todo should we include unloaded swfs?
      SourceFile[] files = swf.getSourceList(m_session);
      ar.ensureCapacity(ar.size()+files.length);

      // add each file to our global source file IntMap and our list
      for(int i=0; i<files.length; i++)
      {
        putFile(files[i], swf.getIsolateId());
        ar.add(files[i]);
      }
    }
    catch(InProgressException ipe)
    {
      // can't load this one, its not ready yet
      worked = false;
    }
    return worked;
  }

  /**
   * Walk the file list looking for name collisions.
   * If we find one, then we remove it
   */
  ArrayList<SourceFile> trimFileList(ArrayList<SourceFile> files)
  {
    HashMap<String, String> names = new HashMap<String, String>();
    ArrayList<SourceFile> list = new ArrayList<SourceFile>();

    int size = files.size();
    for(int i=0; i<size; i++)
    {
      boolean addIt = false;

      SourceFile fi = files.get(i);
      // no filter currently in place so we add the file as long
      // as no duplicates exist.  We use the original Swd full
      // name for matching.
      String fName = fi.getRawName();
      if (m_swfFilter == null)
      {
        // If it exists, then we don't add it!
        if (names.get(fName) == null)
          addIt = true;
      }
      else
      {
        // we have a filter in place so, see
        // if the source file is in our currently
        // selected swf.
        addIt = m_swfFilter.containsSource(fi);
      }

      // did we mark this one to add?
      if (addIt)
      {
        names.put(fName, fName);
        list.add(fi);
      }
    }
    return list;
  }

  /**
   * All files from all swfs are placed into our byInt map
   * since we know that ids are unique across the entire
   * Player session.
   *
   * This is also important in the case that the player
   * halts in one of these files, that the debugger
   * be able to locate the SourceFile so that we can
   * display the correct context for the user.
   */
  void putFile(SourceFile s, int isolateId)
  {
    int i = s.getId();
    if (isolateId == Isolate.DEFAULT_ID)
        m_byInt.put(i, s);
    else
      getIsolateState(isolateId).put(i, s);
  }

  /**
   * Attempt to set a swf as a filter
   * for the file list that we create
   */
  public boolean setSwfFilter(String swfName)
  {
    // look for a match in our list
    boolean worked = false;
    if (swfName == null)
    {
      m_swfFilter = null;
      worked = true;
    }
    else
    {
      SwfInfo[] swfs = getAllSwfs();
      for(int i=0; i<swfs.length; i++)
      {
        SwfInfo e = swfs[i];
        if (e != null && nameOfSwf(e).equalsIgnoreCase(swfName))
        {
          worked = true;
          m_swfFilter = e;
          break;
        }
      }
    }

    // reload if it worked
    if (worked)
      reloadCache();

    return worked;
  }

  // list all swfs we know about
  public SwfInfo[] getSwfs(int isolateId)
  {
    return getSwfsIsolate(isolateId);
  }

  public SwfInfo[] getSwfsIsolate(int isolateId)
  {
    SwfInfo[] swfs = null;
    try
    {
      swfs = m_session.getWorkerSession(isolateId).getSwfs();
    }
    catch(NoResponseException nre)
    {
      swfs = new SwfInfo[] {}// oh bery bad
    }
    return swfs;
  }

  /**
   * Given a SourceFile locate the swf which it came from
   */
  public SwfInfo swfForFile(SourceFile f, int isolateId)
  {
    // We use the id to determine which swf this source files resides in
    int id = f.getId();
    SwfInfo info = null;
    SwfInfo[] swfs = getSwfs(isolateId);//getAllSwfs();
    for(int i=0; ( i<swfs.length && (info == null) ); i++)
    {
      if (swfs[i] != null && swfs[i].containsSource(f))
        info = swfs[i];
    }
    return info;
  }

  // locate the name of the swf
  public static String nameOfSwf(SwfInfo e)
  {
    int at = -1;
    String name = e.getUrl();
    if ( (at = e.getUrl().lastIndexOf('/')) > -1)
      name = e.getUrl().substring(at+1);
    if ( (at = e.getUrl().lastIndexOf('\\')) > -1)
      name = e.getUrl().substring(at+1);
    else if ( (at = e.getPath().lastIndexOf('\\')) > -1)
      name = e.getPath().substring(at+1);
    else if ( (at = e.getPath().lastIndexOf('/')) > -1)
      name = e.getPath().substring(at+1);

    // now rip off any trailing ? options
    at = name.lastIndexOf('?');
    name = (at > -1) ? name.substring(0, at) : name;

    return name;
  }

  // locate the name of the swf
  public static String shortNameOfSwf(SwfInfo e)
  {
    String name = nameOfSwf(e);

    // now strip off any leading path
    int at = -1;
    if ( (at = name.lastIndexOf('/')) > -1)
      name = name.substring(at+1);
    else if ( (at = name.lastIndexOf('\\')) > -1)
      name = name.substring(at+1);
    return name;
  }

    /**
     * Given the URL of a specfic swf determine
     * if there is a file within it that appears
     * to be the same as the given source file
     * @param f
     * @return
     */
    public SourceFile similarFileInSwf(SwfInfo info, SourceFile f) throws InProgressException
    {
        SourceFile hit = null;
    SourceFile[] files = info.getSourceList(m_session);
    if (!info.isProcessingComplete())
      throw new InProgressException();

    for(int i=0; i<files.length; i++)
    {
      if (filesMatch(f, files[i]))
        hit = files[i];
    }
        return hit;
    }

  /**
   * Comparator interface for sorting SourceFiles
   */
  public int compare(SourceFile o1, SourceFile o2)
  {
    String n1 = o1.getName();
    String n2 = o2.getName();

    return n1.compareTo(n2);
  }

    /**
     * Compare two files and determine if they are the same.
     * Our criteria included only line count package names
     * and the name of the class itself.  If there are
     * any other differences then we won't be able to detect
     * them.  We should probably do something like an MD5
     * computation on the characters in ScriptText. Then
     * we'd really be sure of a match.
     * @param a first file to compare
     * @param b second file to compare
     * @return  true if files appear to be the same
     */
    public boolean filesMatch(SourceFile a, SourceFile b)
    {
        boolean yes = true;

    if (a == null || b == null)
      yes = false;
        else if (a.getPackageName().compareTo(b.getPackageName()) != 0)
            yes = false;
        else if (a.getName().compareTo(b.getName()) != 0)
            yes = false;
        else if (a.getLineCount() != b.getLineCount()) // warning, this is sometimes expensive, so do it last
            yes = false;

        return yes;
    }

    /**
     * Return a array of SourceFiles whose names match
     * the specified string. The array is sorted by name.
     * The input can be mx.controls.xxx which will
     */
    public SourceFile[] getFiles(String matchString)
    {
        return getFiles(matchString, -1);
    }

    public SourceFile[] getFiles(String matchString, int isolateId)
    {
        boolean doStartsWith = false;
        boolean doIndexOf = false;
        boolean doEndsWith = false;

        boolean leadingAsterisk = matchString.startsWith("*") && matchString.length() > 1; //$NON-NLS-1$
        boolean trailingAsterisk = matchString.endsWith("*"); //$NON-NLS-1$
        boolean usePath = matchString.indexOf('.') > -1;

        if (leadingAsterisk && trailingAsterisk)
        {
            matchString = matchString.substring(1, matchString.length() - 1);
            doIndexOf = true;
        }
        else if (leadingAsterisk)
        {
            matchString = matchString.substring(1);
            doEndsWith = true;
        }
        else if (trailingAsterisk)
        {
            matchString = matchString.substring(0, matchString.length() - 1);
            doStartsWith = true;
        }
    else if (usePath)
    {
      doIndexOf = true;
    }
    else
        {
            doStartsWith = true;
        }

    SourceFile[] files = isolateId > -1 ? getFileList(isolateId) : getFileList();
        ArrayList<SourceFile> fileList = new ArrayList<SourceFile>();
        int n = files.length;
    int exactHitAt = -1;
    // If the matchString already starts with "." (e.g. ".as" or ".mxml"), then dotMatchString
    // will be equal to matchString; otherwise, dotMatchString will be "." + matchString
    String dotMatchString = (matchString.startsWith(".")) ? matchString : ("." + matchString); //$NON-NLS-1$ //$NON-NLS-2$
        for (int i = 0; i < n; i++)
        {
            SourceFile sourceFile = files[i];
      boolean pathExists = (usePath && sourceFile.getFullPath().matches(".*[/\\\\].*")); //$NON-NLS-1$
            String name = pathExists ? sourceFile.getFullPath() : sourceFile.getName();

      // if we are using the full path string, then prefix a '.' to our matching string so that abc.as and Gabc.as don't both hit
      String match = (usePath && pathExists) ? dotMatchString : matchString;

            match = match.replace('/', '.')// get rid of path identifiers and use dots
            match = match.replace('\\', '.');

      name = name.replace('/', '.')// get rid of path identifiers and use dots
      name = name.replace('\\', '.'); // would be better to modify the input string, but we don't know which path char will be used.

      // exact match? We are done
      if (name.equals(match))
      {
        exactHitAt = i;
        break;
      }
            else if (doStartsWith && name.startsWith(match) && !isDuplicated(fileList, sourceFile))
                fileList.add(sourceFile);
      else if (doEndsWith && name.endsWith(match) && !isDuplicated(fileList, sourceFile))
                fileList.add(sourceFile);
      else if (doIndexOf && name.contains(match) && !isDuplicated(fileList, sourceFile))
        fileList.add(sourceFile);
        }

    // trim all others if we have an exact file match
    if (exactHitAt > -1)
    {
      fileList.clear();
      fileList.add(files[exactHitAt]);
    }

    SourceFile[] fileArray = fileList.toArray( new SourceFile[fileList.size()] );
    Arrays.sort(fileArray, this);
        return fileArray;
    }

    private boolean isDuplicated(ArrayList<SourceFile> fileList, SourceFile sourceFile) {
        boolean found = false;
        for (SourceFile next : fileList) {
            if (next.getFullPath().equals(sourceFile.getFullPath())) {
                found = true;
                break;
            }
        }
        return found;
    }
}
TOP

Related Classes of flex.tools.debugger.cli.FileInfoCache

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.