├── .gitmodules ├── DexMac ├── Resources │ ├── dexmac.icns │ └── Credits.rtf ├── Main.cs ├── MainWindow.cs ├── AppDelegate.designer.cs ├── Info.plist ├── AppDelegate.cs ├── MainWindow.designer.cs ├── DexMac.csproj ├── MainWindowController.cs ├── ClassModel.cs ├── MainWindow.xib └── MainMenu.xib ├── .gitignore ├── README.md ├── DexMac.sln └── LICENSE /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "dex.net"] 2 | path = dex.net 3 | url = git://github.com/mariokmk/dex.net.git 4 | -------------------------------------------------------------------------------- /DexMac/Resources/dexmac.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mariokmk/DexMac/HEAD/DexMac/Resources/dexmac.icns -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | bin 3 | obj 4 | classes 5 | 6 | # mstest test results 7 | TestResults 8 | test-results 9 | UnitTests/test-results 10 | 11 | *.dex 12 | *.userprefs 13 | *.pidb 14 | *~ 15 | .sources 16 | *.test-cache 17 | .DS_Store 18 | *.userprefs 19 | 20 | -------------------------------------------------------------------------------- /DexMac/Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using MonoMac.Foundation; 4 | using MonoMac.AppKit; 5 | using MonoMac.ObjCRuntime; 6 | 7 | namespace DexMac 8 | { 9 | class MainClass 10 | { 11 | static void Main (string[] args) 12 | { 13 | NSApplication.Init (); 14 | NSApplication.Main (args); 15 | } 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /DexMac/Resources/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \margl1440\margr1440\vieww10800\viewh8400\viewkind0 5 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural 6 | 7 | \f0\fs24 \cf0 Developed by Mario Kosmiskas} -------------------------------------------------------------------------------- /DexMac/MainWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using MonoMac.Foundation; 5 | using MonoMac.AppKit; 6 | 7 | namespace DexMac 8 | { 9 | public partial class MainWindow : MonoMac.AppKit.NSWindow 10 | { 11 | #region Constructors 12 | // Called when created from unmanaged code 13 | public MainWindow (IntPtr handle) : base (handle) 14 | { 15 | Initialize (); 16 | } 17 | // Called when created directly from a XIB file 18 | [Export ("initWithCoder:")] 19 | public MainWindow (NSCoder coder) : base (coder) 20 | { 21 | Initialize (); 22 | } 23 | // Shared initialization code 24 | void Initialize () 25 | { 26 | } 27 | #endregion 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /DexMac/AppDelegate.designer.cs: -------------------------------------------------------------------------------- 1 | // WARNING 2 | // 3 | // This file has been generated automatically by Xamarin Studio to store outlets and 4 | // actions made in the UI designer. If it is removed, they will be lost. 5 | // Manual changes to this file may not be handled correctly. 6 | // 7 | using MonoMac.Foundation; 8 | using System.CodeDom.Compiler; 9 | 10 | namespace DexMac 11 | { 12 | [Register ("AppDelegate")] 13 | partial class AppDelegate 14 | { 15 | [Action ("_MenuCloseClick:")] 16 | partial void _MenuCloseClick (MonoMac.Foundation.NSObject sender); 17 | 18 | [Action ("_MenuOpenClick:")] 19 | partial void _MenuOpenClick (MonoMac.Foundation.NSObject sender); 20 | 21 | void ReleaseDesignerOutlets () 22 | { 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /DexMac/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | DexMac 7 | CFBundleVersion 8 | 1 9 | LSMinimumSystemVersion 10 | 10.6 11 | NSMainNibFile 12 | MainMenu 13 | NSPrincipalClass 14 | NSApplication 15 | CFBundleIconFile 16 | dexmac 17 | LSApplicationCategoryType 18 | public.app-category.developer-tools 19 | NSHumanReadableCopyright 20 | https://github.com/mariokmk/dex.net 21 | CFBundleShortVersionString 22 | 0.5 23 | 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DexMac 2 | ====== 3 | 4 | Is a native OSX application for disassembling Android DEX files. 5 | 6 | Usage 7 | ----- 8 | 9 | Launch the app and open a DEX or APK file using the File->Open menu. The list of packages in the DEX/APK will display. Selecting a class or method will render the details of the selected item using the language shown in the 'Language' dropdown. 10 | 11 | See the dex.net project for a description of the output languages. 12 | 13 | The search field allows to filter the packages, classes or methods. If a method matches the criterium its class and package will be displayed as well to allow for navigation. 14 | 15 | Development 16 | ----------- 17 | 18 | DexMac uses the dex.net library which is configured as a git submodule. You must initialize the submodules before compiling DexMac. 19 | 20 | License 21 | ------- 22 | 23 | Dex.NET is provided under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0) 24 | 25 | -------------------------------------------------------------------------------- /DexMac/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using MonoMac.Foundation; 4 | using MonoMac.AppKit; 5 | using MonoMac.ObjCRuntime; 6 | 7 | namespace DexMac 8 | { 9 | public partial class AppDelegate : NSApplicationDelegate 10 | { 11 | public AppDelegate () 12 | { 13 | } 14 | 15 | public override void FinishedLaunching (NSObject notification) 16 | { 17 | } 18 | 19 | partial void _MenuOpenClick (MonoMac.Foundation.NSObject sender) 20 | { 21 | var openPanel = new NSOpenPanel(); 22 | openPanel.ReleasedWhenClosed = true; 23 | openPanel.Prompt = "Select DEX file"; 24 | openPanel.CanChooseDirectories = false; 25 | openPanel.AllowedFileTypes = new string[] { "apk", "dex" }; 26 | 27 | var result = openPanel.RunModal(); 28 | if (result == 1) 29 | { 30 | MainWindowController windowController = null; 31 | try { 32 | windowController = new MainWindowController (); 33 | windowController.OpenDex (openPanel.Url.Path); 34 | windowController.Window.MakeKeyAndOrderFront (this); 35 | } catch (Exception e) { 36 | Console.WriteLine(e); 37 | 38 | // Show error message to the user 39 | var alert = new NSAlert { 40 | MessageText = e.Message, 41 | AlertStyle = NSAlertStyle.Critical 42 | }; 43 | alert.AddButton("OK"); 44 | alert.RunModal(); 45 | 46 | if (windowController != null) { 47 | windowController.Close (); 48 | windowController.Dispose (); 49 | } 50 | } 51 | } 52 | } 53 | 54 | partial void _MenuCloseClick (MonoMac.Foundation.NSObject sender) 55 | { 56 | NSApplication.SharedApplication.KeyWindow.Close(); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /DexMac/MainWindow.designer.cs: -------------------------------------------------------------------------------- 1 | // WARNING 2 | // 3 | // This file has been generated automatically by Xamarin Studio to store outlets and 4 | // actions made in the UI designer. If it is removed, they will be lost. 5 | // Manual changes to this file may not be handled correctly. 6 | // 7 | using MonoMac.Foundation; 8 | using System.CodeDom.Compiler; 9 | 10 | namespace DexMac 11 | { 12 | [Register ("MainWindow")] 13 | partial class MainWindow 14 | { 15 | [Outlet] 16 | MonoMac.AppKit.NSOutlineView _DexOutlineView { get; set; } 17 | 18 | void ReleaseDesignerOutlets () 19 | { 20 | if (_DexOutlineView != null) { 21 | _DexOutlineView.Dispose (); 22 | _DexOutlineView = null; 23 | } 24 | } 25 | } 26 | 27 | [Register ("MainWindowController")] 28 | partial class MainWindowController 29 | { 30 | [Outlet] 31 | MonoMac.AppKit.NSTextView codeTextView { get; set; } 32 | 33 | [Outlet] 34 | MonoMac.AppKit.NSOutlineView dexOutlineView { get; set; } 35 | 36 | [Outlet] 37 | MonoMac.AppKit.NSPopUpButton languagePopUpButton { get; set; } 38 | 39 | [Outlet] 40 | MonoMac.AppKit.NSSearchField searchField { get; set; } 41 | 42 | [Action ("languagePopUpButtonClicked:")] 43 | partial void languagePopUpButtonClicked (MonoMac.Foundation.NSObject sender); 44 | 45 | void ReleaseDesignerOutlets () 46 | { 47 | if (codeTextView != null) { 48 | codeTextView.Dispose (); 49 | codeTextView = null; 50 | } 51 | 52 | if (dexOutlineView != null) { 53 | dexOutlineView.Dispose (); 54 | dexOutlineView = null; 55 | } 56 | 57 | if (languagePopUpButton != null) { 58 | languagePopUpButton.Dispose (); 59 | languagePopUpButton = null; 60 | } 61 | 62 | if (searchField != null) { 63 | searchField.Dispose (); 64 | searchField = null; 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /DexMac.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dex.net", "dex.net\dex.net\dex.net.csproj", "{2B7D42B6-F491-4294-A052-8A30B16EFB9A}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DexMac", "DexMac\DexMac.csproj", "{E23D7BA3-B491-4D8C-B6FD-6E552FB3B3D0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | Default|Any CPU = Default|Any CPU 13 | AppStore|Any CPU = AppStore|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {2B7D42B6-F491-4294-A052-8A30B16EFB9A}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU 17 | {2B7D42B6-F491-4294-A052-8A30B16EFB9A}.AppStore|Any CPU.Build.0 = Debug|Any CPU 18 | {2B7D42B6-F491-4294-A052-8A30B16EFB9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {2B7D42B6-F491-4294-A052-8A30B16EFB9A}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {2B7D42B6-F491-4294-A052-8A30B16EFB9A}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {2B7D42B6-F491-4294-A052-8A30B16EFB9A}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {CDDF6181-818E-4875-8FBF-5F488C5FBEF6}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU 23 | {CDDF6181-818E-4875-8FBF-5F488C5FBEF6}.AppStore|Any CPU.Build.0 = Debug|Any CPU 24 | {CDDF6181-818E-4875-8FBF-5F488C5FBEF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {CDDF6181-818E-4875-8FBF-5F488C5FBEF6}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {CDDF6181-818E-4875-8FBF-5F488C5FBEF6}.Default|Any CPU.ActiveCfg = Debug|Any CPU 27 | {CDDF6181-818E-4875-8FBF-5F488C5FBEF6}.Default|Any CPU.Build.0 = Debug|Any CPU 28 | {CDDF6181-818E-4875-8FBF-5F488C5FBEF6}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {CDDF6181-818E-4875-8FBF-5F488C5FBEF6}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {DE901DF2-B16A-45A2-9323-1C0E13E35D35}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU 31 | {DE901DF2-B16A-45A2-9323-1C0E13E35D35}.AppStore|Any CPU.Build.0 = Debug|Any CPU 32 | {DE901DF2-B16A-45A2-9323-1C0E13E35D35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {DE901DF2-B16A-45A2-9323-1C0E13E35D35}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {DE901DF2-B16A-45A2-9323-1C0E13E35D35}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {DE901DF2-B16A-45A2-9323-1C0E13E35D35}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {E23D7BA3-B491-4D8C-B6FD-6E552FB3B3D0}.AppStore|Any CPU.ActiveCfg = AppStore|Any CPU 37 | {E23D7BA3-B491-4D8C-B6FD-6E552FB3B3D0}.AppStore|Any CPU.Build.0 = AppStore|Any CPU 38 | {E23D7BA3-B491-4D8C-B6FD-6E552FB3B3D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {E23D7BA3-B491-4D8C-B6FD-6E552FB3B3D0}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {E23D7BA3-B491-4D8C-B6FD-6E552FB3B3D0}.Default|Any CPU.ActiveCfg = Debug|Any CPU 41 | {E23D7BA3-B491-4D8C-B6FD-6E552FB3B3D0}.Default|Any CPU.Build.0 = Debug|Any CPU 42 | {E23D7BA3-B491-4D8C-B6FD-6E552FB3B3D0}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {E23D7BA3-B491-4D8C-B6FD-6E552FB3B3D0}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {ECBCE759-E50E-4956-9FEA-8F2C67A07E73}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU 45 | {ECBCE759-E50E-4956-9FEA-8F2C67A07E73}.AppStore|Any CPU.Build.0 = Debug|Any CPU 46 | {ECBCE759-E50E-4956-9FEA-8F2C67A07E73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {ECBCE759-E50E-4956-9FEA-8F2C67A07E73}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {ECBCE759-E50E-4956-9FEA-8F2C67A07E73}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {ECBCE759-E50E-4956-9FEA-8F2C67A07E73}.Release|Any CPU.Build.0 = Release|Any CPU 50 | EndGlobalSection 51 | GlobalSection(MonoDevelopProperties) = preSolution 52 | StartupItem = DexMac\DexMac.csproj 53 | Policies = $0 54 | $0.DotNetNamingPolicy = $1 55 | $1.DirectoryNamespaceAssociation = None 56 | $1.ResourceNamePolicy = FileFormatDefault 57 | $0.StandardHeader = $2 58 | $2.Text = 59 | $2.IncludeInNewFiles = True 60 | EndGlobalSection 61 | EndGlobal 62 | -------------------------------------------------------------------------------- /DexMac/DexMac.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {E23D7BA3-B491-4D8C-B6FD-6E552FB3B3D0} 9 | {948B3504-5B70-4649-8FE4-BDE1FB46EC69};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10 | Exe 11 | DexMac 12 | Resources 13 | DexMac 14 | True 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug 21 | DEBUG; 22 | prompt 23 | 4 24 | false 25 | false 26 | false 27 | false 28 | false 29 | false 30 | false 31 | 5 32 | 33 | 34 | full 35 | true 36 | bin\Release 37 | prompt 38 | 4 39 | false 40 | Full 41 | false 42 | true 43 | false 44 | Developer ID Application 45 | true 46 | true 47 | false 48 | 5 49 | 50 | 51 | full 52 | true 53 | bin\AppStore 54 | prompt 55 | 4 56 | false 57 | Full 58 | false 59 | true 60 | 3rd Party Mac Developer Installer 61 | true 62 | 3rd Party Mac Developer Application 63 | true 64 | true 65 | false 66 | 5 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | MainWindow.cs 84 | 85 | 86 | 87 | 88 | AppDelegate.cs 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | {2B7D42B6-F491-4294-A052-8A30B16EFB9A} 105 | dex.net 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /DexMac/MainWindowController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using MonoMac.Foundation; 5 | using MonoMac.AppKit; 6 | using System.IO; 7 | using ICSharpCode.SharpZipLib.Zip; 8 | using dex.net; 9 | using MonoMac.CoreText; 10 | using System.Text.RegularExpressions; 11 | using MonoMac.CoreGraphics; 12 | 13 | namespace DexMac 14 | { 15 | public partial class MainWindowController : MonoMac.AppKit.NSWindowController 16 | { 17 | private string _tempFile = null; 18 | private Dex _dex; 19 | private WritersFactory _factory = new WritersFactory (); 20 | private IDexWriter _writer; 21 | private CTStringAttributes _codeFont; 22 | private List _codeHighlight = new List (); 23 | private ClassDisplayOptions _classDisplayOptions = ClassDisplayOptions.ClassAnnotations | 24 | ClassDisplayOptions.ClassName | ClassDisplayOptions.ClassDetails | ClassDisplayOptions.Fields; 25 | 26 | #region Constructors 27 | // Called when created from unmanaged code 28 | public MainWindowController (IntPtr handle) : base (handle) 29 | { 30 | Initialize (); 31 | } 32 | // Called when created directly from a XIB file 33 | [Export ("initWithCoder:")] 34 | public MainWindowController (NSCoder coder) : base (coder) 35 | { 36 | Initialize (); 37 | } 38 | // Call to load from the XIB/NIB file 39 | public MainWindowController () : base ("MainWindow") 40 | { 41 | Initialize (); 42 | } 43 | // Shared initialization code 44 | void Initialize () 45 | { 46 | } 47 | #endregion 48 | //strongly typed window accessor 49 | public new MainWindow Window { 50 | get { 51 | return (MainWindow)base.Window; 52 | } 53 | } 54 | 55 | internal void OpenDex(string filename) 56 | { 57 | string dexFile = filename; 58 | _tempFile = null; 59 | 60 | if (System.IO.Path.GetExtension(dexFile).EndsWith("apk")) { 61 | var apkFile = new FileInfo (dexFile); 62 | if (apkFile.Exists) { 63 | var zip = new ZipFile (dexFile); 64 | var entry = zip.GetEntry ("classes.dex"); 65 | 66 | if (entry != null) { 67 | var zipStream = zip.GetInputStream (entry); 68 | var tempFileName = System.IO.Path.GetTempFileName (); 69 | 70 | var buffer = new byte[4096]; 71 | using (var writer = File.Create(tempFileName)) { 72 | int bytesRead; 73 | while ((bytesRead = zipStream.Read(buffer, 0, 4096)) > 0) { 74 | writer.Write (buffer, 0, bytesRead); 75 | } 76 | } 77 | dexFile = tempFileName; 78 | _tempFile = dexFile; 79 | } 80 | } 81 | } 82 | 83 | _dex = new Dex(new FileStream (dexFile, FileMode.Open)); 84 | 85 | this.Window.Title = "DexMac - " + System.IO.Path.GetFileName (filename); 86 | this.Window.Delegate = new DexWindowDelegate (this); 87 | 88 | _codeFont = new CTStringAttributes () { 89 | Font = new CTFont("Menlo-Regular", 12f) 90 | }; 91 | 92 | codeTextView.TextContainer.WidthTracksTextView = false; 93 | codeTextView.TextContainer.ContainerSize = new System.Drawing.SizeF (float.MaxValue, float.MaxValue); 94 | 95 | searchField.Changed += ApplySearchFilter; 96 | 97 | var dexDataSource = new DexDataSource(); 98 | dexDataSource.SetData (_dex); 99 | 100 | dexOutlineView.DataSource = dexDataSource; 101 | //dexOutlineView.SelectionDidChange += OnSelectionChanged; 102 | dexOutlineView.Delegate = new OutlineViewWorkaroundDelegate (this); 103 | 104 | // Supported Languages 105 | languagePopUpButton.RemoveAllItems (); 106 | languagePopUpButton.AddItems (_factory.GetWriters()); 107 | 108 | UpdateSelectedLanguage (); 109 | _writer.dex = _dex; 110 | } 111 | 112 | partial void languagePopUpButtonClicked (MonoMac.Foundation.NSObject sender) 113 | { 114 | UpdateSelectedLanguage(); 115 | UpdateCodeWindow(); 116 | } 117 | 118 | private void UpdateSelectedLanguage() 119 | { 120 | var lang = languagePopUpButton.ItemTitle (languagePopUpButton.IndexOfSelectedItem); 121 | 122 | _writer = _factory.GetWriter (lang); 123 | _writer.dex = _dex; 124 | 125 | _codeHighlight.Clear (); 126 | foreach (var highlight in _writer.GetCodeHightlight()) { 127 | _codeHighlight.Add (new CodeHighlight (highlight)); 128 | } 129 | } 130 | 131 | private void PopulateClasses() 132 | { 133 | var datasource = (DexDataSource)dexOutlineView.DataSource; 134 | datasource.SetData (_dex); 135 | 136 | dexOutlineView.ReloadData (); 137 | } 138 | 139 | private void UpdateCodeWindow() 140 | { 141 | var value = dexOutlineView.ItemAtRow (dexOutlineView.SelectedRow); 142 | var writer = new StringWriter (); 143 | 144 | if (value is ClassModel) { 145 | var dexClass = value as ClassModel; 146 | _writer.WriteOutClass (dexClass._class, _classDisplayOptions, writer); 147 | } else if (value is MethodModel) { 148 | var dexMethod = (MethodModel)value; 149 | _writer.WriteOutMethod (dexMethod._class, dexMethod._method, writer, new Indentation(), true); 150 | } 151 | 152 | codeTextView.TextStorage.SetString(HighlightCode(writer.ToString ())); 153 | } 154 | 155 | private NSAttributedString HighlightCode(String code) 156 | { 157 | var highlightedCode = new NSMutableAttributedString (new NSAttributedString ((NSString)code, _codeFont)); 158 | 159 | foreach (var highlight in _codeHighlight) { 160 | foreach (Match match in highlight.Expression.Matches(code)) { 161 | highlightedCode.AddAttribute(NSAttributedString.ForegroundColorAttributeName, highlight.Color, new NSRange(match.Groups[1].Index, match.Groups[1].Length)); 162 | } 163 | } 164 | 165 | return (NSAttributedString)highlightedCode.Copy(); 166 | } 167 | 168 | void ApplySearchFilter (object sender, EventArgs e) 169 | { 170 | var datasource = (DexDataSource)dexOutlineView.DataSource; 171 | if (string.IsNullOrEmpty (searchField.StringValue)) { 172 | datasource.ResetFilter (); 173 | } else { 174 | datasource.SetFilter (searchField.StringValue); 175 | } 176 | 177 | dexOutlineView.ReloadData (); 178 | } 179 | 180 | class OutlineViewWorkaroundDelegate : NSOutlineViewDelegate 181 | { 182 | MainWindowController _controller; 183 | 184 | public OutlineViewWorkaroundDelegate (MainWindowController controller) 185 | { 186 | _controller = controller; 187 | } 188 | 189 | public override void SelectionDidChange (NSNotification notification) 190 | { 191 | _controller.UpdateCodeWindow (); 192 | } 193 | 194 | } 195 | 196 | class DexWindowDelegate : NSWindowDelegate 197 | { 198 | MainWindowController _controller; 199 | 200 | public DexWindowDelegate(MainWindowController controller) 201 | { 202 | _controller = controller; 203 | } 204 | 205 | public override void WillClose (NSNotification notification) 206 | { 207 | _controller._dex.Dispose (); 208 | 209 | if (_controller._tempFile != null) { 210 | try { 211 | new FileInfo (_controller._tempFile).Delete(); 212 | } catch { 213 | } 214 | } 215 | } 216 | } 217 | 218 | class CodeHighlight 219 | { 220 | internal Regex Expression; 221 | internal NSColor Color; 222 | 223 | internal CodeHighlight(HightlightInfo info) 224 | { 225 | Expression = info.Expression; 226 | Color = NSColor.FromDeviceRgba(info.Color.Red/255f, info.Color.Green/255f, info.Color.Blue/255f, 1); 227 | } 228 | } 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /DexMac/ClassModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MonoMac.Foundation; 3 | using dex.net; 4 | using System.Collections.Generic; 5 | using MonoMac.AppKit; 6 | using System.Collections; 7 | 8 | namespace DexMac 9 | { 10 | internal interface IDataSource 11 | { 12 | int GetChildrenCount (); 13 | NSObject GetObjectValue (); 14 | NSObject GetChild (int index); 15 | bool ItemExpandable (); 16 | } 17 | 18 | public class PackageModel : NSObject, IDataSource, IComparable 19 | { 20 | internal string _package; 21 | internal List _classes; 22 | internal BitArray _filter; 23 | 24 | public PackageModel (string packageName) 25 | { 26 | _package = packageName; 27 | _classes = new List (); 28 | } 29 | 30 | public bool IsClassInPackage(Class dexClass) 31 | { 32 | var package = dexClass.Name.Substring(0, dexClass.Name.LastIndexOf('.')); 33 | 34 | return _package.Equals (package); 35 | } 36 | 37 | public void InitFilter () 38 | { 39 | _filter = new BitArray (_classes.Count, true); 40 | } 41 | 42 | #region IDataSource 43 | 44 | public int GetChildrenCount () 45 | { 46 | return _filter.TrueCount(); 47 | } 48 | 49 | public NSObject GetObjectValue () 50 | { 51 | return (NSString)_package; 52 | } 53 | 54 | public NSObject GetChild (int index) 55 | { 56 | return _classes [_filter.MapIndex(index)]; 57 | } 58 | 59 | public bool ItemExpandable () 60 | { 61 | return _filter.TrueCount() > 0; 62 | } 63 | 64 | #endregion 65 | 66 | #region IComparable Members 67 | 68 | public int CompareTo(PackageModel p) 69 | { 70 | return _package.CompareTo(p._package); 71 | } 72 | 73 | #endregion 74 | } 75 | 76 | public class ClassModel : NSObject, IDataSource 77 | { 78 | internal Class _class; 79 | internal List _methods; 80 | internal BitArray _filter; 81 | 82 | public ClassModel (Class dexClass) 83 | { 84 | _class = dexClass; 85 | 86 | _methods = new List (); 87 | foreach (var method in _class.GetMethods ()) { 88 | _methods.Add(new MethodModel(dexClass, method)); 89 | } 90 | 91 | _filter = new BitArray (_methods.Count, true); 92 | } 93 | 94 | #region IDataSource 95 | 96 | public int GetChildrenCount () 97 | { 98 | return _filter.TrueCount(); 99 | } 100 | 101 | public NSObject GetObjectValue () 102 | { 103 | return (NSString)_class.Name.Substring(_class.Name.LastIndexOf('.')+1); 104 | } 105 | 106 | public NSObject GetChild (int index) 107 | { 108 | return _methods [_filter.MapIndex(index)]; 109 | } 110 | 111 | public bool ItemExpandable () 112 | { 113 | return _filter.TrueCount() > 0; 114 | } 115 | 116 | #endregion 117 | } 118 | 119 | public class MethodModel : NSObject, IDataSource 120 | { 121 | internal Class _class; 122 | internal Method _method; 123 | 124 | public MethodModel (Class dexClass, Method method) 125 | { 126 | _class = dexClass; 127 | _method = method; 128 | } 129 | 130 | #region IDataSource 131 | 132 | public int GetChildrenCount () 133 | { 134 | return 0; 135 | } 136 | 137 | public NSObject GetObjectValue () 138 | { 139 | return (NSString)_method.Name; 140 | } 141 | 142 | public NSObject GetChild (int index) 143 | { 144 | return null; 145 | } 146 | 147 | public bool ItemExpandable () 148 | { 149 | return false; 150 | } 151 | 152 | #endregion 153 | } 154 | 155 | public class DexDataSource : NSOutlineViewDataSource 156 | { 157 | public List Packages { get; set; } 158 | private BitArray _filter = new BitArray(0); 159 | 160 | public DexDataSource() { 161 | Packages = new List (); 162 | } 163 | 164 | public void SetData(Dex dex) 165 | { 166 | Packages.Clear (); 167 | 168 | var packages = new Dictionary(); 169 | foreach (var dexClass in dex.GetClasses()) { 170 | var lastDotPosition = dexClass.Name.LastIndexOf ('.'); 171 | string packageName; 172 | if (lastDotPosition >= 0) { 173 | packageName = dexClass.Name.Substring (0, dexClass.Name.LastIndexOf ('.')); 174 | } else { 175 | packageName = "default"; 176 | } 177 | 178 | PackageModel package; 179 | if (!packages.TryGetValue (packageName, out package)) { 180 | package = new PackageModel(packageName); 181 | packages.Add (packageName, package); 182 | } 183 | 184 | package._classes.Add (new ClassModel (dexClass)); 185 | } 186 | 187 | Packages.AddRange (packages.Values); 188 | Packages.Sort (); 189 | 190 | _filter.Length = Packages.Count; 191 | _filter.SetAll (true); 192 | 193 | foreach (var packageModel in Packages) { 194 | packageModel.InitFilter (); 195 | } 196 | } 197 | 198 | public void SetFilter(string filter) 199 | { 200 | filter = filter.ToLower (); 201 | 202 | _filter.SetAll (false); 203 | var currentPackage = 0; 204 | 205 | foreach (var package in Packages) { 206 | if (package._package.ToLower().IndexOf(filter) >= 0) { 207 | _filter.Set (currentPackage, true); 208 | } 209 | 210 | package._filter.SetAll (false); 211 | var currentClass = 0; 212 | foreach (var clazz in package._classes) { 213 | if (clazz._class.Name.ToLower().IndexOf(filter) >= 0) { 214 | package._filter.Set (currentClass, true); 215 | _filter.Set (currentPackage, true); 216 | } 217 | 218 | clazz._filter.SetAll (false); 219 | var currentMethod = 0; 220 | foreach (var method in clazz._methods) { 221 | if (method._method.Name.ToLower().IndexOf(filter) >= 0) { 222 | clazz._filter.Set (currentMethod, true); 223 | package._filter.Set (currentClass, true); 224 | _filter.Set (currentPackage, true); 225 | } 226 | 227 | currentMethod++; 228 | } 229 | 230 | currentClass++; 231 | } 232 | 233 | currentPackage++; 234 | } 235 | } 236 | 237 | public void ResetFilter() 238 | { 239 | _filter.SetAll (true); 240 | 241 | foreach (var package in Packages) { 242 | package._filter.SetAll (true); 243 | 244 | foreach (var clazz in package._classes) { 245 | clazz._filter.SetAll (true); 246 | } 247 | } 248 | } 249 | 250 | public override int GetChildrenCount (NSOutlineView outlineView, NSObject item) 251 | { 252 | if (item == null) { 253 | return _filter.TrueCount(); 254 | } 255 | 256 | return (item as IDataSource).GetChildrenCount (); 257 | } 258 | 259 | public override NSObject GetObjectValue (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) 260 | { 261 | if (item != null) { 262 | return (item as IDataSource).GetObjectValue (); 263 | } 264 | 265 | return (NSString)"Error!"; 266 | } 267 | 268 | public override NSObject GetChild (NSOutlineView outlineView, int index, NSObject item) 269 | { 270 | if (item == null) { 271 | return Packages [_filter.MapIndex(index)]; 272 | } else { 273 | return (item as IDataSource).GetChild (index); 274 | } 275 | } 276 | 277 | public override bool ItemExpandable (NSOutlineView outlineView, NSObject item) 278 | { 279 | if (item == null || item is MethodModel) 280 | return false; 281 | 282 | return (item as IDataSource).ItemExpandable (); 283 | } 284 | } 285 | 286 | public static class BitArrayExtensions 287 | { 288 | public static int TrueCount(this BitArray bitArray) 289 | { 290 | var count = 0; 291 | for (int i=0; i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 108 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 137 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /DexMac/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | --------------------------------------------------------------------------------