/* * Copyright 2018 faddenSoft * * Licensed 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. */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; namespace PluginCommon { /// /// Extension script "plugins" must implement this interface. /// public interface IPlugin { /// /// Identification string. Contents are arbitrary, but should briefly identify the /// purpose of the plugin, e.g. "Apple II ProDOS 8 MLI call handler". It may /// contain version information, but should not be expected to be machine-readable. /// string Identifier { get; } /// /// Prepares the plugin for action. Called at the start of every code analysis pass /// and when generating visualization images. /// /// In the current implementation, the file data will be the same every time, /// because it doesn't change after the project is opened. However, this could /// change if we add a descramble feature. The IApplication and AddressTranslate /// references will likely change between invocations. /// /// This may be called even when the plugin won't be asked to do anything. Avoid /// performing expensive operations here. /// /// Reference to application interface. /// 65xx code and data. /// Mapping between offsets and addresses. void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans); /// /// Tells the plugin that we're done talking to it for now. /// void Unprepare(); } /// /// Extension scripts that want to receive the list of symbols must implement this interface. /// public interface IPlugin_SymbolList { /// /// Receives a list of the currently defined platform, project, and user symbols. /// The list does not include auto-generated labels or local variables. /// /// This is called immediately after Prepare(), before any other interfaces are /// invoked, at the start of every code analysis pass. /// /// Symbols available to plugins, in no particular order. void UpdateSymbolList(List plSyms); /// /// Handles a notification that a user symbol has been added, edited, or removed. If the /// label is of interest to the plugin, e.g. it changes how the plugin formats code or /// data, the app needs to know. /// /// /// The application does a full re-analysis when project properties change, but not /// when labels are edited. The CheckJsr/Jsl/Brk methods are only called during code /// analysis, so if their behavior changes based on the presence or absence of a user /// label then we need to tell the application that a full re-analysis is needed. /// /// Plugins that don't care about user symbols, e.g. that just use tagged platform /// symbols, can simply return false. (Changes to user labels that overlap with /// project/platform symbols are detected by the app.) /// /// The label before the change, or empty if this is a /// newly-added label. /// The label after the change, or empty if the label was /// removed. /// True if the label change could affect the plugin's actions. bool IsLabelSignificant(string beforeLabel, string afterLabel); } /// /// Extension scripts that want to handle inline JSRs must implement this interface. /// public interface IPlugin_InlineJsr { /// /// Checks to see if code/data near a JSR instruction should be formatted. /// /// The file data is guaranteed to hold all bytes of the JSR (offset + 2). /// /// Offset of the JSR instruction. /// 16-bit JSR operand. /// Set to true if the JSR doesn't actually return. void CheckJsr(int offset, int operand, out bool noContinue); } /// /// Extension scripts that want to handle inline JSLs must implement this interface. /// public interface IPlugin_InlineJsl { /// /// Checks to see if code/data near a JSL instruction should be formatted. /// /// The file data is guaranteed to hold all bytes of the JSL (offset + 3). /// /// Offset of the JSL instruction. /// 24-bit JSL operand. /// Set to true if the JSL doesn't actually return. void CheckJsl(int offset, int operand, out bool noContinue); } /// /// Extension scripts that want to handle inline BRKs must implement this interface. /// public interface IPlugin_InlineBrk { /// /// Checks to see if code/data near a BRK instruction should be formatted. /// /// The file data is only guaranteed to hold the BRK opcode byte. /// /// Offset of the BRK instruction. /// True if the CPU is configured for two-byte BRKs. /// Set to true if the BRK doesn't actually return. void CheckBrk(int offset, bool isTwoBytes, out bool noContinue); } /// /// Extension scripts that want to generate visualizations must implement this interface. /// public interface IPlugin_Visualizer { /// /// Retrieves a list of descriptors for visualization generators implemented by this /// plugin. The items in the set may have values based on the file data. /// /// The caller must not modify the contents. /// VisDescr[] GetVisGenDescrs(); /// /// Executes the specified visualization generator with the supplied parameters. /// /// Visualization generator descriptor. /// Parameter set. /// 2D visualization object reference, or null if something went /// wrong (unknown ident, bad parameters, etc). By convention, an error /// message is reported through the IApplication ReportError interface. IVisualization2d Generate2d(VisDescr descr, ReadOnlyDictionary parms); } /// /// Version 2 of the visualizer interface. Adds wireframe objects. /// public interface IPlugin_Visualizer_v2 : IPlugin_Visualizer { /// /// Executes the specified visualization generator with the supplied parameters. /// /// Visualization generator descriptor. /// Parameter set. /// Wireframe visualization object reference, or null if something went /// wrong (unknown ident, bad parameters, etc). By convention, an error /// message is reported through the IApplication ReportError interface. IVisualizationWireframe GenerateWireframe(VisDescr descr, ReadOnlyDictionary parms); } /// /// Visualization generator descriptor. IPlugin_Visualizer instances publish a list of /// these to tell the application about the generators it supports. /// [Serializable] public class VisDescr { /// /// Unique identifier. This is stored in the project file. Names beginning with /// underscores ('_') are reserved and must not be defined by plugins. /// public string Ident { get; private set; } /// /// Human-readable string describing the visualizer. Used for combo boxes and /// other UI elements. /// public string UiName { get; private set; } /// /// Visualization type, used to distinguish between bitmaps and wireframes. /// public enum VisType { Unknown = 0, Bitmap, // 2D bitmap Wireframe, // wireframe mesh } /// /// Visualization type. /// public VisType VisualizationType { get; private set; } /// /// Visualization parameter descriptors. /// public VisParamDescr[] VisParamDescrs { get; private set; } /// /// Constructor. /// public VisDescr(string ident, string uiName, VisType type, VisParamDescr[] descrs) { Ident = ident; UiName = uiName; VisualizationType = type; VisParamDescrs = descrs; } } /// /// Visualization parameter descriptor. /// /// /// We provide min/max for individual numeric fields, but there's no way to check other /// fields to see if e.g. Stride >= Width. We'd need a "verify" function and a way to /// report errors that the GUI could use to point out what was wrong. /// [Serializable] public class VisParamDescr { /// /// Special feature enumeration. /// public enum SpecialMode { None = 0, Offset } /// /// Label to show in the UI. /// public string UiLabel { get; private set; } /// /// Name to use internally. Do not use names that start with an underscore ('_'), as /// these are reserved for future internal use. /// public string Name { get; private set; } /// /// Parameter data type. /// public Type CsType { get; private set; } /// /// Minimum allowable value for int/float (and perhaps string length). /// public object Min { get; private set; } /// /// Maximum allowable value for int/float (and perhaps string length). /// public object Max { get; private set; } /// /// Set to a value if the field requires special treatment. /// public SpecialMode Special { get; private set; } /// /// Default value for this field. /// public object DefaultValue { get; private set; } /// /// Constructor. /// public VisParamDescr(string uiLabel, string name, Type csType, object min, object max, SpecialMode special, object defVal) { if (defVal.GetType() != csType) { throw new ArgumentException("Mismatch between type and default value in \"" + name + "\""); } UiLabel = uiLabel; Name = name; CsType = csType; Min = min; Max = max; Special = special; DefaultValue = defVal; } } /// /// Rendered 2D visualization. The object represents the "raw" form of the data, /// without scaling or filtering. /// public interface IVisualization2d { /// /// Bitmap width, in pixels. /// int Width { get; } /// /// Bitmap height, in pixels. /// int Height { get; } /// /// Returns a densely-packed array of color indices or ARGB values. Color index /// values may be remapped from what was originally set to improve compression. /// /// Do not modify. /// byte[] GetPixels(); /// /// Returns the color palette as a series of 32-bit ARGB values. Duplicate entries /// may have been merged to improve compression. /// /// Will be null for direct-color images. Do not modify. /// /// /// It's possible, but weird, for the array to have a length of zero. For best results /// with GIF images, only one palette entry should be transparent. /// int[] GetPalette(); // TODO(maybe): report pixel aspect ratio? } /// /// Holds raw vertex/edge/normal data collected from a 2D or 3D wireframe mesh. We use /// a left-handed coordinate system (+Z goes into the screen). If the project being /// disassembled uses different definitions for the axes, it's probably best to convert /// them in the visualizer. 2D data should use X/Y with Z=0. /// /// All objects will have vertices. Most will have edges, some will have points. Face /// normals are optional. /// /// /// The face-normal stuff is designed specifically for Elite. Besides being one of the /// very few 6502-based games to use backface culling, it extended the concept to allow /// convex shapes to have protrusions. /// /// Points are included primarily for the benefit of AVG games like Battlezone. /// /// We favor multiple arrays over compound objects for this interface to avoid making /// such objects part of the plugin interface. /// /// TODO(maybe): specify colors for points and edges. Not widely used? Could be handy for /// color AVG games like Tempest. /// public interface IVisualizationWireframe { // Each function returns the specified data. Do not modify the returned arrays. bool Is2d { get; } float[] GetVerticesX(); float[] GetVerticesY(); float[] GetVerticesZ(); int[] GetPoints(); IntPair[] GetEdges(); float[] GetNormalsX(); float[] GetNormalsY(); float[] GetNormalsZ(); IntPair[] GetVertexFaces(); IntPair[] GetEdgeFaces(); int[] GetExcludedVertices(); int[] GetExcludedEdges(); bool Validate(out string msg); } /// /// Represents a pair of integers. Immutable. /// [Serializable] public struct IntPair { public int Val0 { get; private set; } public int Val1 { get; private set; } public IntPair(int val0, int val1) { Val0 = val0; Val1 = val1; } } /// /// Interfaces provided by the application for use by plugins. An IApplication instance /// is passed to the plugin as an argument to Prepare(). /// public interface IApplication { /// /// Reports an error message to the application. Used by visualizers. /// /// void ReportError(string msg); /// /// Sends a debug message to the application. This can be useful when debugging scripts. /// (For example, DEBUG > Show Analyzer Output shows output generated while performing /// code analysis.) /// /// Message to send. void DebugLog(string msg); /// /// Specifies operand formatting. /// /// File offset of opcode. /// Sub-type. Must be appropriate for NumericLE. /// Optional symbolic label. /// True if the change was made, false if it was rejected. bool SetOperandFormat(int offset, DataSubType subType, string label); /// /// Formats file data as inline data. /// /// File offset. /// Length of item. /// Type of item. Must be NumericLE, NumericBE, or Dense. /// Sub-type. Must be appropriate for type. /// Optional symbolic label. /// True if the change was made, false if it was rejected (e.g. because /// the area is already formatted, or contains code). /// If something is really wrong, e.g. data runs /// off end of file. bool SetInlineDataFormat(int offset, int length, DataType type, DataSubType subType, string label); } /// /// Data format type. /// /// /// Essentially a clone of FormatDescriptor.Type. /// public enum DataType { Unknown = 0, NumericLE, NumericBE, StringGeneric, StringReverse, StringNullTerm, StringL8, StringL16, StringDci, Dense, Fill, Uninit, Junk, BinaryInclude } /// /// Data format sub-type. /// /// /// Essentially a clone of FormatDescriptor.SubType. /// public enum DataSubType { // No sub-type specified. None = 0, // For NumericLE/BE Hex, Decimal, Binary, Address, Symbol, // Strings and NumericLE/BE (single character) Ascii, HighAscii, C64Petscii, C64Screen // skipping alignment sub-types for now } }