/* * Copyright 2019 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.ComponentModel; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Media; namespace SourceGen.WpfGui { /// /// Allows repositioning of a local variable table. /// /// /// This would be better implemented as cut/copy/paste, allowing parts of tables to be /// freely duplicated and copied around, but that's a bunch of work for something that /// I'm not yet convinced is important. (It might not be that much more work in and of /// itself, but once the action is possible people will expect it to work for comments /// and notes, and maybe want to paste operand formatting.) /// public partial class EditLvTableLocation : Window, INotifyPropertyChanged { /// /// After a successful move, this will hold the new offset. /// public int NewOffset { get; private set; } /// /// Project reference. /// private DisasmProject mProject; /// /// File offset at which we are initially positioned. /// private int mCurrentOffset; // Dialog label text color. private Brush mDefaultLabelColor = SystemColors.WindowTextBrush; private Brush mErrorLabelColor = Brushes.Red; public string OffsetStr { get { return mOffsetStr; } set { mOffsetStr = value; OnPropertyChanged(); ValidateOffset(); } } private string mOffsetStr; public bool IsValid { get { return mIsValid; } set { mIsValid = value; OnPropertyChanged(); } } private bool mIsValid; public Brush InvalidOffsetBrush { get { return mInvalidOffsetBrush; } set { mInvalidOffsetBrush = value; OnPropertyChanged(); } } private Brush mInvalidOffsetBrush; public Brush NotInstructionBrush { get { return mNotInstructionBrush; } set { mNotInstructionBrush = value; OnPropertyChanged(); } } private Brush mNotInstructionBrush; public Brush TableAlreadyPresentBrush { get { return mTableAlreadyPresentBrush; } set { mTableAlreadyPresentBrush = value; OnPropertyChanged(); } } private Brush mTableAlreadyPresentBrush; // INotifyPropertyChanged implementation public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public EditLvTableLocation(Window owner, DisasmProject project, int curOffset, int initialOffset) { InitializeComponent(); Owner = owner; DataContext = this; mProject = project; mCurrentOffset = curOffset; // curOffset is where the table actually is. initialOffset reflects changes // made on a previous invocation of this dialog. OffsetStr = initialOffset.ToString("x6"); } private void Window_ContentRendered(object sender, EventArgs e) { offsetTextBox.SelectAll(); offsetTextBox.Focus(); } private void OkButton_Click(object sender, RoutedEventArgs e) { NewOffset = Convert.ToInt32(OffsetStr, 16); DialogResult = true; } private void OffsetUp_Click(object sender, RoutedEventArgs e) { AdjustOffset(-1); } private void OffsetDown_Click(object sender, RoutedEventArgs e) { AdjustOffset(1); } /// /// Adjusts the offset up or down enough to get it to the next instruction start that /// doesn't already have a local variable table. /// /// Adjustment, should be +1 or -1. private void AdjustOffset(int adj) { int offset; try { offset = Convert.ToInt32(OffsetStr, 16); } catch (Exception) { // string is garbage, just put the initial offset back in OffsetStr = mCurrentOffset.ToString("x6"); return; } offset += adj; while (offset >= 0 && offset < mProject.FileDataLength) { if (mProject.GetAnattrib(offset).IsInstructionStart && !HasTableNotSelf(offset)) { // found a winner OffsetStr = offset.ToString("x6"); return; } offset += adj; } } private void ValidateOffset() { InvalidOffsetBrush = NotInstructionBrush = TableAlreadyPresentBrush = mDefaultLabelColor; if (string.IsNullOrEmpty(OffsetStr)) { InvalidOffsetBrush = mErrorLabelColor; IsValid = false; return; } int offset; try { offset = Convert.ToInt32(OffsetStr, 16); } catch (Exception) { InvalidOffsetBrush = mErrorLabelColor; IsValid = false; return; } if (offset < 0 || offset >= mProject.FileDataLength) { InvalidOffsetBrush = mErrorLabelColor; IsValid = false; return; } Anattrib attr = mProject.GetAnattrib(offset); if (!attr.IsInstructionStart) { NotInstructionBrush = mErrorLabelColor; IsValid = false; return; } if (HasTableNotSelf(offset)) { TableAlreadyPresentBrush = mErrorLabelColor; IsValid = false; return; } IsValid = true; } /// /// Returns true if the specified offset is the start of an instruction, and doesn't /// have a local variable table unless the table is us. /// private bool HasTableNotSelf(int offset) { return offset != mCurrentOffset && mProject.LvTables.TryGetValue(offset, out LocalVariableTable unused); } } }