├── .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 |
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 |
--------------------------------------------------------------------------------
/DexMac/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
--------------------------------------------------------------------------------