/*
* Copyright (C) 2026 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package com.jpexs.decompiler.flash.gui;
import com.jpexs.debugger.flash.DebugMessageListener;
import com.jpexs.debugger.flash.DebuggerCommands;
import com.jpexs.debugger.flash.DebuggerConnection;
import com.jpexs.debugger.flash.Variable;
import com.jpexs.debugger.flash.VariableFlags;
import com.jpexs.debugger.flash.VariableType;
import com.jpexs.debugger.flash.messages.in.InBreakAt;
import com.jpexs.debugger.flash.messages.in.InBreakAtExt;
import com.jpexs.debugger.flash.messages.in.InBreakReason;
import com.jpexs.debugger.flash.messages.in.InCallFunction;
import com.jpexs.debugger.flash.messages.in.InConstantPool;
import com.jpexs.debugger.flash.messages.in.InContinue;
import com.jpexs.debugger.flash.messages.in.InErrorException;
import com.jpexs.debugger.flash.messages.in.InExit;
import com.jpexs.debugger.flash.messages.in.InFrame;
import com.jpexs.debugger.flash.messages.in.InGetSwf;
import com.jpexs.debugger.flash.messages.in.InGetVariable;
import com.jpexs.debugger.flash.messages.in.InNumScript;
import com.jpexs.debugger.flash.messages.in.InPlaceObject;
import com.jpexs.debugger.flash.messages.in.InProcessTag;
import com.jpexs.debugger.flash.messages.in.InScript;
import com.jpexs.debugger.flash.messages.in.InSetBreakpoint;
import com.jpexs.debugger.flash.messages.in.InSwfInfo;
import com.jpexs.debugger.flash.messages.in.InTrace;
import com.jpexs.debugger.flash.messages.in.InVersion;
import com.jpexs.debugger.flash.messages.out.OutAddWatch2;
import com.jpexs.debugger.flash.messages.out.OutGetBreakReason;
import com.jpexs.debugger.flash.messages.out.OutGetSwf;
import com.jpexs.debugger.flash.messages.out.OutPlay;
import com.jpexs.debugger.flash.messages.out.OutProcessedTag;
import com.jpexs.debugger.flash.messages.out.OutRewind;
import com.jpexs.debugger.flash.messages.out.OutSwfInfo;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.helpers.Helper;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeSet;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
* @author JPEXS
*/
public class DebuggerSession {
private boolean connected = false;
private DebuggerCommands commands = null;
//private List swfs = new ArrayList<>();
private boolean paused = true;
private Map modulePaths = new HashMap<>();
private Map moduleToSwfIndex = new HashMap<>();
//Marks swfIndices that are fully loaded - at least one break was on it (including onloaded break)
private Set swfIndicesCommitted = new HashSet<>();
private Map swfIndicesNewToSwfHash = new HashMap<>();
private Map scriptToModule = new HashMap<>();
private Map moduleToTraitIndex = new HashMap<>();
private Map moduleToClassIndex = new HashMap<>();
private Map moduleToMethodIndex = new HashMap<>();
private Map>> toAddBPointMap = new WeakHashMap<>();
private Map>> toRemoveBPointMap = new WeakHashMap<>();
private Map>> confirmedPointMap = new WeakHashMap<>();
private Map>> invalidBreakPointMap = new WeakHashMap<>();
private int breakIp = -1;
private String breakScriptName = null;
private List stackScriptNames = new ArrayList<>();
private List stackLines = new ArrayList<>();
private Map debuggedSwfs = new LinkedHashMap<>();
private Map placedObjects = new LinkedHashMap<>();
private InFrame frame;
private int depth;
private InConstantPool pool;
private InBreakAtExt breakInfo;
private InBreakReason breakReason;
private DebuggerHandler handler;
private InSetBreakpoint inSetBreakpoint;
private int id;
private static int lastId = 0;
private List getSwfThreadList = Collections.synchronizedList(new ArrayList<>());
public DebuggerSession(DebuggerHandler handler, DebuggerConnection con, Map>> breakpoints) {
lastId++;
id = lastId;
toAddBPointMap = breakpoints;
this.handler = handler;
Main.startWork(AppStrings.translate("work.debugging"), null);
synchronized (this) {
paused = false;
}
Main.getMainFrame().getPanel().updateMenu();
//enlog(DebuggerConnection.class);
//enlog(DebuggerCommands.class);
//enlog(DebuggerHandler.class);
try {
con.getMessage(InVersion.class);
} catch (IOException ex) {
Logger.getLogger(DebuggerSession.class.getName()).log(Level.SEVERE, null, ex);
}
//Respond to InProcessTag with OutProcessedTag
con.addMessageListener(new DebugMessageListener() {
@Override
public void message(InProcessTag message) {
try {
con.writeMessage(new OutProcessedTag(con));
} catch (IOException ex) {
//disconnect();
//ignore
}
}
});
swfIndicesCommitted.clear();
swfIndicesNewToSwfHash.clear();
Map moduleNames = new HashMap<>();
final Pattern patAS3 = Pattern.compile("^(.*);(.*);(.*)\\.as$");
final Pattern patAS3PCode = Pattern.compile("^(?[0-9a-z_]+):#PCODE abc:(?[0-9]+),script:(?