Merge branch 'master' into feat/build-lists

# Conflicts:
#	package-lock.json
This commit is contained in:
Sam Carlton 2021-03-02 19:32:16 -06:00
commit a7551e1dd8
46 changed files with 3164 additions and 7153 deletions

124
README.md
View file

@ -5,7 +5,7 @@ Lists of reported app support for macOS on ARM so far.
Any comments, suggestions? [Let us know!](https://github.com/ThatGuySam/doesitarm/issues). PRs welcome :)
[Search List](https://doesitarm.com/) | [Benchmarks and Performance](https://doesitarm.com/benchmarks/) | [Twitter Updates](https://twitter.com/DoesItARM) | [More Lists](https://github.com/ThatGuySam/doesitarm/blob/master/README.md#more-apple-silicon-lists) | [Youtube Playlists](https://github.com/ThatGuySam/doesitarm/blob/master/README.md#youtube-apple-silicon-playlists)
[Search List](https://doesitarm.com/) | [🧪 Apple Silicon App Test](https://doesitarm.com/apple-silicon-app-test/) | [Benchmarks and Performance](https://doesitarm.com/benchmarks/) | [Twitter Updates](https://twitter.com/DoesItARM) | [More Lists](https://github.com/ThatGuySam/doesitarm/blob/master/README.md#more-apple-silicon-lists) | [Youtube Playlists](https://github.com/ThatGuySam/doesitarm/blob/master/README.md#youtube-apple-silicon-playlists)
@ -13,7 +13,7 @@ Any comments, suggestions? [Let us know!](https://github.com/ThatGuySam/doesitar
## Legend
* ✅ Yes, Full Native Apple Silicon Support
* ✳️ Yes, works via Rosetta 2
* ✳️ Yes, works via Translation or Virtualization
* ⏹ No, not working at all but support is in development
* 🚫 No, not yet supported only works on Intel-based Macs
* 🔶 Unknown, more info needed
@ -47,12 +47,13 @@ Any comments, suggestions? [Let us know!](https://github.com/ThatGuySam/doesitar
* [Attributed String Creator](https://apps.apple.com/us/app/attributed-string-creator-pro/id730928349) - ✅ Yes, full native support as of v1.9.6 - [Release Notes](https://www.bridgetech.io)
* [BBEdit](https://www.barebones.com/products/bbedit/download.html) - ✅ Yes, full native support as of v13.5 - [Release Notes](https://www.barebones.com/support/bbedit/notes-13.5.html)
* [Beyond Compare](https://www.scootersoftware.com/) - ✳️ Yes, works via Rosetta 2 - [Facebook Post](https://www.facebook.com/ScooterSoftware/posts/5178865142127412)
* [Caddy](https://caddyserver.com/download) - ✅ Yes, Full Native Apple Silicon Support - [Verification](https://github.com/ThatGuySam/doesitarm/issues/577#issuecomment-783684858)
* [Charles Web Debugging Proxy](https://www.charlesproxy.com/download/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/122#issuecomment-751907737)
* [CLion](https://www.jetbrains.com/clion/download/#section=mac) - ✅ Yes, full native support as of v2020.3.1
* [CocoaPods](https://cocoapods.org/) - ✳️ Yes, it works via Rosetta 2 - [Issue](https://github.com/CocoaPods/CocoaPods/issues/9907)
* [CotEditor](https://coteditor.com) - ✅ Yes, full native support as of 4.0.0 - [App Store](https://itunes.apple.com/app/coteditor/id1024640650)
* [Cyberduck](https://cyberduck.io/download/) - ✳️ Yes, works via Rosetta 2 with native build in development - [Source](https://github.com/ThatGuySam/doesitarm/issues/333)
* [Dash for macOS](https://kapeli.com/dash) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/225#issuecomment-734750855) [Snippet Issue](https://github.com/ThatGuySam/doesitarm/issues/225#issuecomment-757104857)
* [Dash for macOS](https://kapeli.com/dash) - ✅ Yes, Full Native Apple Silicon Support as of v6 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/575#issue-812547431) [Release Notes](https://blog.kapeli.com/dash-6)
* [DataGrip](https://www.jetbrains.com/datagrip/download/#section=mac) - ✅ Yes, full native support as of v2020.3.1
* [DBeaver](https://dbeaver.io/) - ✳️ Yes, works via Rosetta 2 using the pkg installer - [Issue Tracking](https://github.com/dbeaver/dbeaver/issues/10470)
* [Deno](https://deno.land/) - ✅ Yes, Full Native Apple Silicon Support - [Issue](https://github.com/denoland/deno/issues/8346)
@ -60,45 +61,51 @@ Any comments, suggestions? [Let us know!](https://github.com/ThatGuySam/doesitar
* [Dreamweaver](https://www.adobe.com/products/dreamweaver.html) - ✳️ Yes, works via Rosetta 2 - [Official Adobe Status Page](https://helpx.adobe.com/download-install/kb/apple-silicon-m1-chip.html)
* [Emacs](https://www.gnu.org/software/emacs/) - ✅ Yes, full native support via Emacs plus - [Verification](https://github.com/ThatGuySam/doesitarm/issues/226) [Install instructions](https://github.com/d12frosted/homebrew-emacs-plus)
* [Electron](https://www.electronjs.org/releases/stable) - ✅ Yes, full native support as of v11.0 - [Announcement](https://www.electronjs.org/blog/apple-silicon)
* [FFmpeg](https://ffmpeg.org/download.html) - 🚫 Not yet supported because of unsupported or broken dependencies on arm64: rsvg, x264, libvpx, soxr - [Issue](https://trac.macports.org/ticket/61668)
* [FFmpeg](https://ffmpeg.org/download.html) - ✅ Yes, Full Native Apple Silicon Support via Homebrew - [Homebrew ARM Binary Available](https://formulae.brew.sh/formula/ffmpeg#default)
* [Filezilla](https://filezilla-project.org/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/17#issuecomment-729976000)
* [Flutter](https://flutter.dev/docs/get-started/install/macos) - ✳️ Yes, works via Rosetta 2 with native support in development - [Github Issue](https://github.com/flutter/flutter/issues/60118#issuecomment-695341296)
* [Fork](https://git-fork.com/) - ✅ Yes, full native support as of v2.1.0 - [Release notes](https://git-fork.com/releasenotes)
* [ForkLift](https://binarynights.com/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/455#issuecomment-755042429)
* [Flycut](https://apps.apple.com/us/app/flycut-clipboard-manager/id442160987?mt=12) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/330#issue-750781819) [Github Repo](https://github.com/TermiT/Flycut)
* [Flycut](https://apps.apple.com/us/app/flycut-clipboard-manager/id442160987?mt=12) - ✅ Yes, Full Native Apple Silicon Support - [Release Notes](https://github.com/TermiT/Flycut/releases/tag/1.9.6)
* [GCC ARM Embedded](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm) - ✳️ Yes, runs via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/105#issuecomment-750419946)
* [Git Version Control](https://git-scm.com/download/mac) - ✅ Yes, Full Native Apple Silicon Support - [Source](https://github.com/ThatGuySam/doesitarm/issues/54#issuecomment-730568063)
* [GitHub Desktop](https://desktop.github.com/) - ✳️ Yes, works via Rosetta 2 as of v2.6.0 with native support in development - [GitHub issue](https://github.com/ThatGuySam/doesitarm/issues/293)
* [GitKraken](https://www.gitkraken.com/download) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/244#issuecomment-736760318)
* [Go (golang)](https://golang.org/) - ✳️ Runs via Rosetta 2, with native builds available in beta - [Golang M1 Benchmark](https://docs.google.com/spreadsheets/d/1g4U7LAImfEcXRihJbySZcRr32tn6WSWAtslfXltds58/edit#gid=342445681) [Issue](https://github.com/golang/go/issues/38485) [Beta Download](https://golang.org/dl/#go1.16beta1) [Release Notes](https://tip.golang.org/doc/go1.16)
* [Go (golang)](https://golang.org/) - ✅ Yes, full native support as of 1.16 - [Golang M1 Benchmark](https://docs.google.com/spreadsheets/d/1g4U7LAImfEcXRihJbySZcRr32tn6WSWAtslfXltds58/edit#gid=342445681) [Release Notes](https://tip.golang.org/doc/go1.16) [Go 1.16 is released](https://blog.golang.org/go1.16)
* [GoLand](https://www.jetbrains.com/go/download/#section=mac) - ✅ Yes, full native support as of v2020.3.1
* [Godot Engine](https://godotengine.org/) - ⏹ No official binaries yet, but can be compiled from source - [Master PR](https://github.com/godotengine/godot/pull/39788), [v3.2 PR](https://github.com/godotengine/godot/pull/39943)
* [GNU Compiler Collection](https://gcc.gnu.org/) - ✳️ Yes, runs via Rosetta 2 - [Source](https://github.com/ThatGuySam/doesitarm/issues/105#issuecomment-732795155) [Bugzilla Issue](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96168)
* [Haskell](https://www.haskell.org/platform/mac.html) - 🚫 Not yet supported only works on Intel-based Macs - [Gitlab Issue](https://gitlab.haskell.org/ghc/ghc/-/issues/18664)
* [Hex Fiend](https://github.com/HexFiend/HexFiend/releases) - ✅ Yes, full native support as of v2.14.0 - [Source](https://github.com/ThatGuySam/doesitarm/issues/429)
* [Homebrew](https://brew.sh/) - ✳️ Yes, with caveats and some troubleshooting. - [Issue](https://github.com/Homebrew/brew/issues/7857).
* [Homebrew](https://brew.sh/) - ✳️ Yes, fully supported as of v3.0.0 - [Release Notes](https://brew.sh/2021/02/05/homebrew-3.0.0/).
* [Hopper Disassembler](https://www.hopperapp.com/download.html) - ✅ Yes, Full Native Apple Silicon Support as of v4.6 - [Release Notes](https://www.hopperapp.com/blog/?p=263)
* [IDA Pro](https://www.hex-rays.com/products/ida/support/download_freeware/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/405#issue-759952494)
* [Insomnia Designer](https://insomnia.rest/download/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/456#issuecomment-748260642)
* [Insomnia Core](https://insomnia.rest/download/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/456#issuecomment-748260642)
* [IntelliJ IDEA](https://www.jetbrains.com/idea/download/#section=mac) - ✅ Yes, fully supported as of v2020.3.1 - [Release Notes](https://confluence.jetbrains.com/display/IDEADEV/IntelliJ+IDEA+2020.3.1+%28203.6682.168+build%29+Release+Notes)
* [iTerm](https://iterm2.com/downloads.html) - ✅ Yes, fully supported as of v3.4.0 - [PR](https://github.com/gnachman/iTerm2/pull/421)
* [Jetpack Compose for Desktop](https://www.jetbrains.com/lp/compose/) - ✅ Yes, Full Native Apple Silicon Support - [Changelog](https://github.com/JetBrains/compose-jb/blob/a4d59048f50c96970368e884925fd59b1a31ed12/CHANGELOG.md#m2-dec-2020)
* [Julia Language](https://julialang.org/downloads/) - ✳️ Yes, it works via Rosetta 2 - [Github Issue](https://github.com/JuliaLang/julia/issues/36617)
* [KiCad EDA](https://kicad.org/download/macos/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/199#issuecomment-736253625)
* [kitty](https://github.com/kovidgoyal/kitty/releases) - ✅ Yes, Full Native Apple Silicon Support - [Github Issue](https://github.com/kovidgoyal/kitty/issues/3238)
* [LLVM Clang](https://releases.llvm.org/download.html) - ✳️ Yes, it works via Rosetta 2 - [Apple Forums](https://developer.apple.com/forums/thread/649992)
* [LTspice](https://www.analog.com/en/design-center/design-tools-and-calculators/ltspice-simulator.html) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/421#issuecomment-751876882)
* [MacDown](https://macdown.uranusjr.com/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/382)
* [MacPorts](https://www.macports.org/install.php) - ✳️ Yes, some ports are native while others work via Rosetta 2. - [Discussion](https://github.com/ThatGuySam/doesitarm/issues/302).
* [MAMP](https://www.mamp.info/en/mamp/mac/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/309)
* [MongoDB](https://www.mongodb.com/try/download/community) - ✅ Yes, Full Native Apple Silicon Support - [Test Video](https://youtu.be/b_S3CjGRQis?t=227)
* [MongoDB](https://www.mongodb.com/try/download/community) - ✳️ Yes, works via Rosetta 2 - [Issue](https://jira.mongodb.org/browse/SERVER-50115) [Test Video](https://youtu.be/b_S3CjGRQis?t=227)
* [MongoKitten](https://apps.apple.com/us/app/id1484086700) - ✅ Yes, Full Native Apple Silicon Support - [Verification](https://github.com/ThatGuySam/doesitarm/issues/502#issue-778010353)
* [MySQL Community Server](https://dev.mysql.com/downloads/) - ✳️ Yes, works via Rosetta 2 - [Source](https://github.com/ThatGuySam/doesitarm/issues/173#issuecomment-730553003)
* [MySQL Workbench](https://dev.mysql.com/downloads/) - ✳️ Yes, works via Rosetta 2 for v8.0.21 with issues reported on newer versions - [Source](https://github.com/ThatGuySam/doesitarm/issues/173#issuecomment-730553003) [Issues](https://github.com/ThatGuySam/doesitarm/issues/173#issuecomment-763269306)
* [Navicat Premium](https://www.navicat.com/en/products/navicat-premium) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/161#issuecomment-759768321)
* [NixOS](https://nixos.org/download.html) - ⏹ Not yet, but its in development - [Github Issue](https://github.com/NixOS/nixpkgs/issues/95903)
* [NodeJS](https://nodejs.org/en/) - ✳️ Yes, works via Rosetta 2 for Active LTS - [M1 Benchmark](https://docs.google.com/spreadsheets/d/1g4U7LAImfEcXRihJbySZcRr32tn6WSWAtslfXltds58/edit#gid=607735373) [Version Support](https://github.com/ThatGuySam/doesitarm/issues/299#issuecomment-733210648) [Github Issue](https://github.com/nodejs/TSC/issues/886)
* [NodeJS](https://nodejs.org/en/) - ✅ Yes, Full Native Apple Silicon Support as of v15 - [M1 Benchmark](https://docs.google.com/spreadsheets/d/1g4U7LAImfEcXRihJbySZcRr32tn6WSWAtslfXltds58/edit#gid=607735373) [Version Support](https://github.com/ThatGuySam/doesitarm/issues/299#issuecomment-733210648) [Github Issue](https://github.com/nodejs/TSC/issues/886)
* [Nova](https://nova.app) - ✅ Yes, Full Native Apple Silicon Support as of v3 - [Official Tweet](https://twitter.com/panic/status/1326977997732134912?s=20)
* [OCaml](https://ocaml.org/) - ⏹ Not yet, but it's currently in beta. - [Pull Status](https://github.com/ocaml/ocaml/pull/9699)
* [OpenJDK](https://openjdk.java.net/install/) - ✅ Yes, Full Native Apple Silicon Support via Azul Zulu
Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAImfEcXRihJbySZcRr32tn6WSWAtslfXltds58/edit#gid=1469348209) [Azul Builds](https://www.azul.com/downloads/zulu-community/?os=macos&architecture=arm-64-bit&package=jdk) [Early Access Builds](https://github.com/microsoft/openjdk-aarch64/releases) [JEP Ticket](https://openjdk.java.net/jeps/391) [Discussion](https://bugs.openjdk.java.net/browse/JDK-8251280)
* [Parallels Desktop](https://www.parallels.com/) - ⏹ Not entirely working yet, but running ARM guests (such as Windows 10 on ARM) is possible with the preview version - [Blog Post](https://www.parallels.com/blogs/parallels-desktop-apple-silicon-mac/) [Beta Download](https://my.parallels.com/desktop/beta) [MacRumors Discussion](https://forums.macrumors.com/threads/parallels-tech-preview-for-m1.2275996/unread)
* [Paw](https://paw.cloud/) - ✳️ Yes, works via Rosetta 2 - [Official Tweet](https://twitter.com/luckymarmot/status/1332614644654026755?s=20)
* [Paw](https://paw.cloud/) - ✅ Yes, Full Native Apple Silicon Support as of v3.2.1 - [Release Notes](https://paw.cloud/updates/3.2.1)
* [Pelemay](https://github.com/zeam-vm/pelemay/releases) - ✅ Yes, Full Native Apple Silicon Support as of v0.0.14 - [Release Notes](https://github.com/zeam-vm/pelemay/releases/tag/0.0.14)
* [PhpStorm](https://www.jetbrains.com/phpstorm/download/#section=mac) - ✅ Yes, full native Apple Silicon support as of v2020.3.1
* [Postman](https://www.postman.com/downloads/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/160#issuecomment-736772593)
@ -107,27 +114,34 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [PyCharm](https://www.jetbrains.com/pycharm/download/#section=mac) - ✅ Yes, full native support as of v2020.3.1
* [Python](https://www.python.org/) - ✅ Yes, reported working for v2.7.16, v3.8.2, and v3.9 - [PyPerformance Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAImfEcXRihJbySZcRr32tn6WSWAtslfXltds58/edit#gid=1795089557) [Python Tracker](https://bugs.python.org/issue41100) [Github Issue](https://github.com/python/cpython/pull/22855) [Github Issue #2](https://github.com/ThatGuySam/doesitarm/issues/111)
* [PyTorch](https://pytorch.org/) - ✳️ Yes, works via Rosetta 2 - [Report Update](https://github.com/ThatGuySam/doesitarm/issues/432)
* [React Native](https://reactnative.dev/) - 🔶 Unknown, more info needed - [Contribute](https://github.com/ThatGuySam/doesitarm/issues/427)
* [React Native](https://reactnative.dev/) - ✳️ Yes, works on supported Node versions - [Check Node Support](https://doesitarm.com/app/nodejs/)
* [Redis](https://redis.io/download) - ✅ Yes, full native Apple Silicon support as of v6 - [v6.0.9 Benchmark](https://docs.google.com/spreadsheets/d/1g4U7LAImfEcXRihJbySZcRr32tn6WSWAtslfXltds58/edit#gid=1002181585) [Verification](https://github.com/ThatGuySam/doesitarm/issues/298)
* [Robo 3T (formerly Robomongo)](https://robomongo.org/download) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/175#issuecomment-782071460)
* [RubyMine](https://www.jetbrains.com/ruby/download/#section=mac) - ✅ Yes, full native support as of v2020.3.1
* [Rust](https://www.rust-lang.org/) - ✅ Yes, full native support (Tier 2) as of v1.49 - [Issue](https://github.com/rust-lang/rust/issues/73908#issue-648613557) [Official Blog Post](https://blog.rust-lang.org/2020/12/31/Rust-1.49.0.html)
* [Sequel Ace](https://github.com/Sequel-Ace/Sequel-Ace/releases) - ✅ Yes, Full Native Apple Silicon Support as of v3.0.1 - [Release Notes](https://github.com/Sequel-Ace/Sequel-Ace/releases/tag/production%2F3.0.1-3008)
* [Sketch](https://www.sketch.com/) - ✅ Yes, Full Native Apple Silicon Support as of v70 - [Release Notes](https://www.sketch.com/updates/#version-70)
* [SourceTree](https://www.sourcetreeapp.com/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/200)
* [SubEthaEdit](https://subethaedit.net/) - ✅ Yes, full native Apple Silicon Support as of v5.1.5 - [Release Notes](https://github.com/subethaedit/SubEthaEdit/releases/tag/SubEthaEdit-MacFull-5.1.5)
* [Sublime Text](https://www.sublimetext.com/) - ✳️ Yes, works via Rosetta 2 - [Forum Discussion](https://forum.sublimetext.com/t/arm-build/5882/97)
* [Surge](https://nssurge.com/) - ✅ Yes, full native Apple Silicon Support as of v4.0.0 - [Issue](https://github.com/ThatGuySam/doesitarm/issues/157)
* [TablePlus](https://tableplus.com/) - ✅ Yes, Full Native Apple Silicon Support as of Build 352 - [Release Notes](https://twitter.com/TablePlus/status/1327650704295489536)
* [TensorFlow](https://www.tensorflow.org/) - ⏹ Not yet, but a supported pre-release is available - [Pre-Release](https://blog.tensorflow.org/2020/11/accelerating-tensorflow-performance-on-mac.html)
* [TablePlus](https://tableplus.com/) - ✅ Yes, fully supported as of Build 352 - [Release Notes](https://twitter.com/TablePlus/status/1327650704295489536)
* [Tower](https://www.git-tower.com/mac) - ✅ Yes, fully supported as of v6 - [Release Notes](https://www.git-tower.com/blog/tower-mac-6/)
* [Termius](https://termius.com/) - ✅ Yes, Full Native Apple Silicon Support as of v7.4.1 - [Release Notes](https://docs.termius.com/changelog/desktop)
* [Tower](https://www.git-tower.com/mac) - ✅ Yes, Full Native Apple Silicon Support as of v6 - [Release Notes](https://www.git-tower.com/blog/tower-mac-6/)
* [Transmit](https://panic.com/transmit/) - ✅ Yes, Full Native Apple Silicon Support as of v5.7 - [Official Tweet](https://twitter.com/panic/status/1326978002576666624?s=20)
* [Tunnelblick](https://tunnelblick.net/) - ✳️ Yes, works via Rosetta 2 - [Official Website](https://tunnelblick.net/cAppleSilicon.html)
* [Typora](https://typora.io/#download) - ✅ Yes, fully supported as of v0.9.9.36 - [Release Notes](https://typora.io/dev_release.html)
* [Unity](https://store.unity.com/download) - ✳️ Runs via Rosetta with native support currently in development - [CNET Article](https://www.cnet.com/news/microsoft-365-and-adobe-creative-cloud-will-support-mac-arm-natively/#:~:text=At%20its%20annual%20Worldwide%20Developers,which%20it%20calls%20Apple%20silicon.&text=Adobe's%20Creative%20Cloud%20software%20includes,InDesign%2C%20Premiere%20Pro%20and%20Illustrator)
* [VirtualBox](https://www.virtualbox.org/wiki/Downloads) - 🚫 No, not yet supported only works on Intel-based Macs - [Discussion](https://forums.virtualbox.org/viewtopic.php?f=8&t=98742)
* [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/) - ✳️ Yes, works via Rosetta 2 but debugging is not supported - [Verification](https://github.com/ThatGuySam/doesitarm/issues/401#issuecomment-748295469)
* [VisualDiffer](https://apps.apple.com/us/app/visualdiffer/id412386481?ls=1&mt=12) - ✅ Yes, Full Native Apple Silicon Support as of v1.8.0 - [Mantis issue](https://visualdiffer.com/mantis/view.php?id=334)
* [VS Code](https://code.visualstudio.com/) - ✳️ Yes, works via Rosetta 2 with native support on insider builds - [Insider Download](https://code.visualstudio.com/docs/?dv=darwinarm64&build=insiders) [Issue](https://github.com/microsoft/vscode/issues/106770).
* [VS Code](https://code.visualstudio.com/) - ✳️ Yes, works via Rosetta 2 (Native for insiders v1.53) - [Native Progress](https://code.visualstudio.com/updates/v1_53#_apple-silicon-insiders)
* [Vysor](https://www.vysor.io/download/) - ✳️ Yes, works via Rosetta 2 - [Tweet](https://twitter.com/vysorapp/status/1329298424278093825) [Source](https://github.com/ThatGuySam/doesitarm/issues/275#issuecomment-747208601)
* [WebStorm](https://www.jetbrains.com/webstorm/download/#section=mac) - ✅ Yes, full native support as of v2020.3.1 - [Official Download](https://www.jetbrains.com/webstorm/download/#section=mac)
* [Wireshark](https://www.wireshark.org/) - ✳️ Yes, works via Rosetta 2 - [Source](https://github.com/ThatGuySam/doesitarm/issues/336)
* [Xamarin](https://dotnet.microsoft.com/apps/xamarin) - ✳️ Yes, works via Rosetta 2 - [Souorce](https://github.com/xamarin/xamarin-macios/issues/10005#issue-732495019) [Video Demo](https://doesitarm.com/tv/xamarin-and-visual-studio-on-apple-macbook-pro-13-m1-in-4k-i-rwpspmmlos/)
* [XAMPP](https://www.apachefriends.org/download.html) - ✳️ Yes, works via Rosetta 2 - [Video Demonstration](https://doesitarm.com/tv/watch-this-before-buying-apple-m1-macbook-for-xampp-or-apple-silicon-tests-in-4k-i-ebwwewsis8s/)
* [Xcode](https://apps.apple.com/us/app/xcode/id497799835) - ✅ Yes, Full Native Apple Silicon Support as of v12.2 - [Release Notes](https://developer.apple.com/documentation/xcode-release-notes/xcode-12_2-release-notes)
* [Xojo](https://www.xojo.com/download/) - ⏹ Not yet, but its in development - [Blog Post](https://blog.xojo.com/2020/11/10/apple-silicon-and-big-sur-support-coming-in-xojo-2020r2/)
* [.NET](https://dotnet.microsoft.com/download) - ⏹ .NET Core nightly builds available, ongoing work for other frameworks - [Project Board](https://github.com/orgs/dotnet/projects/18)
@ -135,11 +149,21 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
#### Science and Research Software
* [COMSOL Multiphysics](https://www.comsol.com/comsol-multiphysics) - ✳️ Yes, works via Rosetta 2 - [Report #1](https://www.comsol.com/forum/thread/272202/new-apple-m1-machines-and-rosetta-2-intel-emulator?last=2021-02-04T17:09:35Z) [Report #2](https://www.reddit.com/r/mac/comments/kfp8tg/comsol_with_m1/glvd947?utm_source=share&utm_medium=web2x&context=3)
* [GeoGebra Classic 5](https://www.geogebra.org/download) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/418#issue-760869359)
* [GNU Octave](https://www.gnu.org/software/octave/index.html) - ✅ Yes, Full Native Apple Silicon Support - [Verification](https://github.com/ThatGuySam/doesitarm/issues/574#issue-812510611)
* [GraphPad Prism](https://www.graphpad.com/scientific-software/prism/) - ✅ Yes, Full Native Apple Silicon Support as of v9.0.1 - [Release Notes](https://www.graphpad.com/support/faq/prism-901-release-notes/) [Official Article](https://www.graphpad.com/support/faq/prism-mac-big-sur/)
* [IBM SPSS](https://www.ibm.com/analytics/spss-statistics-software) - ✳️ Yes, works via Rosetta 2 - [Official Post](https://community.ibm.com/community/user/datascience/blogs/todd-peterson1/2020/11/20/spss-statistics-on-macos-big-sur-110)
* [Matlab](https://www.mathworks.com/products/get-matlab.html?s_tid=gn_getml) - ✳️ Yes, works via Rosetta 2 as of v9.9.0.1495850 - [Matlab Forums](https://www.mathworks.com/matlabcentral/answers/641925-is-matlab-supported-on-apple-silicon-macs)
* [JMP](https://www.jmp.com/en_us/software/data-analysis-software.html) - ✳️ Yes, works via Rosetta 2 as of v15.2 - [Developer Report](https://community.jmp.com/t5/Discussions/jmp-combatiblity-on-the-apple-M1-mac-book-air/m-p/339577#M58780)
* [LabVIEW](https://www.ni.com/en-us/shop/labview.html) - 🚫 No, not yet stable on under Rosetta 2 - [Official Apple Compatibility](https://www.ni.com/en-us/support/documentation/compatibility/18/labview-and-macos-compatibility.html) [Discussion](https://forums.ni.com/t5/LabVIEW/LabVIEW-on-Apple-Silicon-M1-and-beyond/td-p/4100430?profile.language=en)
* [MATLAB](https://www.mathworks.com/products/get-matlab.html?s_tid=gn_getml) - ✳️ Yes, works via Rosetta 2 as of v9.9.0.1495850 - [MATLAB Forums](https://www.mathworks.com/matlabcentral/answers/641925-is-matlab-supported-on-apple-silicon-macs)
* [Mendeley](https://www.mendeley.com/download-desktop-new/macOS) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/448#issuecomment-751869800)
* [NVivo](https://www.qsrinternational.com/nvivo-qualitative-data-analysis-software/try-nvivo) - ✳️ Yes, works via Rosetta 2 with compatibility patch as of v12.6.1 - [Official Status](https://www.qsrinternational.com/nvivo-qualitative-data-analysis-software/support-services/support-center/user-issues-trending-now)
* [RStudio](https://rstudio.com/products/rstudio/download/) - ✳️ Yes, runs via Rosetta 2 with native support in development - [Source](https://github.com/ThatGuySam/doesitarm/issues/36) [Benchmark Info](https://github.com/ThatGuySam/doesitarm/issues/36#issuecomment-735668887)
* [Stata](https://www.stata.com/) - ✅ Yes, Full Native Apple Silicon Support as of v16, update level 10 Nov 2020 - [Blog Post](https://blog.stata.com/2020/11/10/stata-for-mac-with-apple-silicon/)
* [Tableau Desktop](https://www.tableau.com/products/desktop) - 🚫 No, not yet supported only works on Intel-based Macs - [Issue](https://kb.tableau.com/articles/issue/Tableau-Mac-Software-Does-Not-Yet-Support-Apple-Silicon-CPU) [Video Demonstration](https://youtu.be/vyPm2fOyS7Y?t=625) [Previous version via Rosetta 2](https://www.tableau.com/support/releases/desktop/2020.3.5)
* [Tableau Prep](https://www.tableau.com/products/prep) - 🚫 No, not yet supported only works on Intel-based Macs - [Issue](https://kb.tableau.com/articles/issue/Tableau-Mac-Software-Does-Not-Yet-Support-Apple-Silicon-CPU) [Previous version via Rosetta 2](https://www.tableau.com/support/releases/prep/2020.3.3)
* [Wolfram Mathematica](https://www.wolfram.com/mathematica/) - ✳️ Yes, works via Rosetta 2 as of v12 - [Discussion](https://community.wolfram.com/groups/-/m/t/2118125#_19_message_2121051)
@ -148,6 +172,7 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [Ableton](https://www.ableton.com/en/live/) - ✳️ Yes, it works via Rosetta 2 - [Reddit Post](https://www.reddit.com/r/ableton/comments/jrtpv6/ableton_live_11_on_apple_silicon_m1_processor/gbvxj9r?context=3)
* [Adobe Audition](https://www.adobe.com/products/audition.html) - ✳️ Yes, works via Rosetta 2 - [Official Adobe Status Page](https://helpx.adobe.com/download-install/kb/apple-silicon-m1-chip.html)
* [Airfoil](https://rogueamoeba.com/airfoil/mac/) - ✅ Yes, Initial Native Apple Silicon Support as of v5.10.0 - [Release Notes](https://rogueamoeba.com/airfoil/mac/releasenotes.php) [Official Post](https://weblog.rogueamoeba.com/2020/11/16/rogue-amoeba-software-updates-for-macos-11-big-sur-and-m1-chip-based-macs/)
* [Ardour](https://community.ardour.org/download) - ✳️ Yes, it works via Rosetta 2 with native support in progress - [Apple Silicon Pre-release](https://discourse.ardour.org/t/ardour-for-apple-m1-arm-pre-release/105174)
* [Audacity](https://www.audacityteam.org/download/) - ✳️ Yes, it works via Rosetta 2 with no reported issues - [Github Issue Comment](https://github.com/audacity/audacity/issues/684#issuecomment-710726323)
* [Audio Hijack](https://rogueamoeba.com/audiohijack/) - ✅ Yes, Initial Native Apple Silicon Support as of v3.8.0 - [Release Notes](https://rogueamoeba.com/audiohijack/releasenotes.php) [Official Post](https://weblog.rogueamoeba.com/2020/11/16/rogue-amoeba-software-updates-for-macos-11-big-sur-and-m1-chip-based-macs/)
* [Avid Pro Tools](https://www.avid.com/pro-tools) - 🚫 No official word yet.
@ -164,10 +189,14 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [Loopback](https://rogueamoeba.com/loopback/) - ✅ Yes, Initial Native Apple Silicon Support as of v2.2.0 - [Release Notes](https://rogueamoeba.com/loopback/releasenotes.php) [Official Post](https://weblog.rogueamoeba.com/2020/11/16/rogue-amoeba-software-updates-for-macos-11-big-sur-and-m1-chip-based-macs/)
* [Native Access](https://www.native-instruments.com/en/specials/native-access/) - ⏹ No, not working at all but support is in development - [Official Status](https://support.native-instruments.com/hc/en-us/articles/360013515618-macOS-11-Big-Sur-Compatibility-News) [Official Post](https://support.native-instruments.com/hc/en-us/articles/360014683497)
* [Piezo](https://rogueamoeba.com/piezo/) - ✅ Yes, Initial Native Apple Silicon Support as of v1.7.0 - [Release Notes](https://rogueamoeba.com/piezo/releasenotes.php) [Official Post](https://weblog.rogueamoeba.com/2020/11/16/rogue-amoeba-software-updates-for-macos-11-big-sur-and-m1-chip-based-macs/)
* [Plogue Bidule](https://plogue.com/downloads.html) - ✅ Yes, Full Native Apple Silicon Support - [Verification](https://github.com/ThatGuySam/doesitarm/issues/480#issue-776226694)
* [REAPER](https://www.reaper.fm/download.php) - ✳️ Yes, works via Rosetta 2 with native support in beta - [Apple Silicon Discussion](https://forum.cockos.com/showthread.php?t=245263)
* [rekordbox](https://rekordbox.com/en/download/) - ✳️ Yes, works via Rosetta 2 with native support currently in development - [Official Support List](https://www.pioneerdj.com/en-us/landing/support-for-macos-big-sur/) [Verification](https://github.com/ThatGuySam/doesitarm/issues/560#issue-805540415)
* [SoundSource](https://rogueamoeba.com/soundsource/) - ✅ Yes, Initial Native Apple Silicon Support as of v5.2.0 - [Release Notes](https://rogueamoeba.com/soundsource/releasenotes.php) [Official Post](https://weblog.rogueamoeba.com/2020/11/16/rogue-amoeba-software-updates-for-macos-11-big-sur-and-m1-chip-based-macs/)
* [Super 8 R2](https://www.native-instruments.com/en/products/komplete/synths/super-8/) - ⏹ No, not working at all but support is in development - [Official Status](https://support.native-instruments.com/hc/en-us/articles/360013515618-macOS-11-Big-Sur-Compatibility-News) [Official Post](https://support.native-instruments.com/hc/en-us/articles/360014683497)
* [Traktor DJ 2](https://www.native-instruments.com/en/products/traktor/dj-software/traktor-dj-2/) - ⏹ No, not working at all but support is in development - [Official Status](https://support.native-instruments.com/hc/en-us/articles/360013515618-macOS-11-Big-Sur-Compatibility-News) [Official Post](https://support.native-instruments.com/hc/en-us/articles/360014683497)
* [Traktor Pro 3](https://www.native-instruments.com/en/products/traktor/dj-software/traktor-pro-3/) - ⏹ No, not working at all but support is in development - [Official Status](https://support.native-instruments.com/hc/en-us/articles/360013515618-macOS-11-Big-Sur-Compatibility-News) [Official Post](https://support.native-instruments.com/hc/en-us/articles/360014683497)
* [TwistedWave](https://twistedwave.com/mac) - ✳️ Yes, works via Rosetta 2 with native support in beta - [Verification](https://github.com/ThatGuySam/doesitarm/issues/508#issue-781561446)
* [Traktor DJ 2](https://www.native-instruments.com/en/products/traktor/dj-software/traktor-dj-2/) - ✳️ Yes, works via Rosetta 2 - [Official Apple Silicon Status](https://support.native-instruments.com/hc/en-us/articles/360014683497-) [Official Big Sur Status](https://support.native-instruments.com/hc/en-us/articles/360013515618-macOS-11-Big-Sur-Compatibility-News) [Official Post](https://support.native-instruments.com/hc/en-us/articles/360014683497)
* [Traktor Pro 3](https://www.native-instruments.com/en/products/traktor/dj-software/traktor-pro-3/) - ✳️ Yes, works via Rosetta 2 - [Official Apple Silicon Status](https://support.native-instruments.com/hc/en-us/articles/360014683497-) [Official Big Sur Status](https://support.native-instruments.com/hc/en-us/articles/360013515618-macOS-11-Big-Sur-Compatibility-News) [Official Post](https://support.native-instruments.com/hc/en-us/articles/360014683497)
* [TunesArt](https://www.jibapps.com/apps/tunesart/) - ✅ Yes, Full Native Apple Silicon Support as of v1.9.6 - [Source](https://twitter.com/jibapps/status/1334055652055003137)
* [X Lossless Decoder (XLD)](https://sourceforge.net/projects/xld/) - ✅ Yes, Full Native Apple Silicon Support as of 2021/1/1 - [Scroll to version history here](https://tmkk.undo.jp/xld/index_e.html)
@ -184,8 +213,13 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [Capture One](https://www.captureone.com/) - ✳️ Yes, works via Rosetta 2 - [Source](https://github.com/ThatGuySam/doesitarm/pull/130#issuecomment-736183868) [Capture One Twitter](https://twitter.com/captureonepro/status/1326570278462349312)
* [Darkroom](https://darkroom.co/) - ✅ Yes, it was shown at the November 10th event - [Apple Nov 10 Event](https://youtu.be/5AwdkGKmZ0I?t=1307)
* [Darktable](https://www.darktable.org/install/#macos) - ✳️ Yes, works via Rosetta 2 - [Source](https://github.com/ThatGuySam/doesitarm/issues/328#issuecomment-736769770) [Discussion](https://discuss.pixls.us/t/the-future-of-darktable-on-the-mac-with-arm/21290)
* [EXIF Sync](https://www.lemkesoft.de/en/products/exif-sync/download/) - ✅ Yes, Full Native Apple Silicon Support - [🧪 Apple Silicon App Tested](https://doesitarm.com/apple-silicon-app-test/)
* [Figma](https://www.figma.com/downloads/) - ✳️ Yes, works via Rosetta 2 - [Report #1](https://www.reddit.com/r/FigmaDesign/comments/k58d5h/figma_client_for_apple_silicon/gje6y83/?utm_source=reddit&utm_medium=web2x&context=3) [Report #2](https://twitter.com/joeyabanks/status/1330929000701710345)
* [FontBook](https://www.lemkesoft.de/en/products/fontbook/download/) - ✅ Yes, Full Native Apple Silicon Support - [🧪 Apple Silicon App Tested](https://doesitarm.com/apple-silicon-app-test/)
* [Gimp](https://www.gimp.org/downloads/) - ✳️ Yes, works via Rosetta 2 but with noticeable performance dip - [Verification](https://github.com/ThatGuySam/doesitarm/issues/304#issuecomment-748297707)
* [GraphicConverter](https://www.lemkesoft.de/en/products/graphicconverter/download/) - ✅ Yes, Full Native Apple Silicon Support - [Verification](https://github.com/ThatGuySam/doesitarm/issues/483#issuecomment-752342847)
* [Graphite Sketchbook](https://www.digitalmasterpieces.com/graphite/) - ✅ Yes, it was shown at the November 10th event - [Apple Nov 10 Event](https://youtu.be/5AwdkGKmZ0I?t=1303)
* [iCalamus](https://www.lemkesoft.de/en/products/icalamus/download/) - ✅ Yes, Full Native Apple Silicon Support - [🧪 Apple Silicon App Tested](https://doesitarm.com/apple-silicon-app-test/)
* [Illustrator](https://www.adobe.com/products/illustrator.html) - ✳️ Yes, works via Rosetta 2 - [Official Adobe Status Page](https://helpx.adobe.com/download-install/kb/apple-silicon-m1-chip.html)
* [InCopy](https://www.adobe.com/products/incopy.html) - ✳️ Yes, works via Rosetta 2 - [Official Adobe Status Page](https://helpx.adobe.com/download-install/kb/apple-silicon-m1-chip.html)
* [InDesign](https://www.adobe.com/products/indesign.html) - ✳️ Yes, works via Rosetta 2 - [Official Adobe Status Page](https://helpx.adobe.com/download-install/kb/apple-silicon-m1-chip.html)
@ -199,10 +233,12 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [Pixelmator Classic](https://apps.apple.com/cn/app/pixelmator-classic/id407963104?l=en&mt=12) - ✳️ Yes, works via Rosetta 2, no native upgrade planned - [Verification](https://github.com/ThatGuySam/doesitarm/issues/367)
* [Pixelmator Pro](https://pixelmator.com/pro) - ✅ Yes, full native support as of v2.0
* [Photoshop](https://www.adobe.com/products/photoshop.html) - ✳️ Yes, works via Rosetta 2 with native support in beta - [Beta Post](https://feedback.photoshop.com/conversations/photoshop-beta/photoshop-for-mac-arm-is-here/5fb359d3ca9d527a59c4677e) [Apple Nov 10 Event](https://youtu.be/5AwdkGKmZ0I?t=1092) [WWDC Preview](https://youtu.be/GEZhD3J89ZE?t=5813)
* [Seashore](https://apps.apple.com/us/app/seashore/id1448648921?mt=12&app=apps&ign-mpt=uo%3D4) - ✳️ Yes, works via Rosetta 2, an experimental Apple Silicon build is available - [Verification](https://github.com/ThatGuySam/doesitarm/issues/544#issue-799623568) [Apple Silicon Build](https://github.com/leoplan2/seashore/releases/tag/v2.5.10)
* [Simple Comic](http://dancingtortoise.com/simplecomic/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/407)
* [Simple Comic (Community Fork)](https://github.com/MaddTheSane/Simple-Comic) - ✅ Yes, full native Apple Silicon support as of v1.9.1 - [App Store](https://apps.apple.com/us/app/simple-comic/id1497435571?l=en&mt=12) [Github Repo](https://github.com/MaddTheSane/Simple-Comic) [Verification](https://github.com/ThatGuySam/doesitarm/issues/407)
* [Textify](https://apps.apple.com/app/id1522041836) - ✅ Yes, full native support as of v2.0.1 - [Macrumors Thread](https://forums.macrumors.com/threads/textify-text-recognition-ocr-made-easy-and-accurate-1-product-of-the-day-ph.2245225/page-2?post=29016938#post-29016938)
* [Vectornator](https://www.vectornator.io/) - ✅ Yes, it was shown at the November 10th event - [Apple Nov 10 Event](https://youtu.be/5AwdkGKmZ0I?t=1300)
* [waifu2x](https://github.com/nihui/waifu2x-ncnn-vulkan/releases) - ✅ Yes, Full Native Apple Silicon Support as of v20210102 - [Release Notes](https://github.com/nihui/waifu2x-ncnn-vulkan/releases/tag/20210102)
@ -219,6 +255,7 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [Cinema 4D](https://www.maxon.net/en/downloads) - ✅ Yes, Full Native Apple Silicon Support - [Release Notes](https://www.maxon.net/en/article/cinema-4d-r23-sp1-now-available) [Apple Nov 10 Event](https://youtu.be/5AwdkGKmZ0I?t=924)
* [Claquette](https://www.peakstep.com/claquette/) - ✅ Yes, Full Native Apple Silicon Support as of v2.1 - [Release Notes](https://www.peakstep.com/claquette/releasenotes.html)
* [DaVinci Resolve](https://www.blackmagicdesign.com/products/davinciresolve) - ✅ Yes, it was shown at the November 10th event - [Apple Nov 10 Event](https://youtu.be/5AwdkGKmZ0I?t=950)
* [Ecamm Live](https://www.ecamm.com/mac/ecammlive/?fp_ref=lsp) - ✳️ Yes, works via Rosetta 2 - [Official Article](https://support.ecamm.com/en/articles/4616420-ecamm-live-on-macos-11-big-sur-and-apple-silicon-m1-macs)
* [ffWorks](https://www.ffworks.net/download.html) - ✅ Yes, full native support as of v2.2.3
* [Final Cut Pro](https://www.apple.com/final-cut-pro/) - ✅ Yes, it will available on Apple Silicon launch - [Apple Nov 10 Event](https://youtu.be/5AwdkGKmZ0I?t=1173) [WWDC Preview](https://youtu.be/GEZhD3J89ZE?t=5844)
* [Handbrake](https://handbrake.fr/) - ✅ Yes, natively supported as of v1.4.0 - [Github Issue](https://github.com/HandBrake/HandBrake/issues/2951)
@ -241,25 +278,32 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [Archicad](https://graphisoft.com/solutions/products/archicad) - ✳️ Yes, works via Rosetta 2 - [Graphisoft support update](https://helpcenter.graphisoft.com/knowledgebase/130674/) [Graphisoft Thread](https://archicad-talk.graphisoft.com/viewtopic.php?p=312614) [Reddit thread](https://www.reddit.com/r/ArchiCAD/comments/hsjs6l/archicad_and_macos_armtransition/) [Tudy's feedback](https://github.com/ThatGuySam/doesitarm/pull/189#issuecomment-742729489)
* [AutoCAD](https://www.autodesk.com/products/autocad/overview?plc=ACDIST&term=1-YEAR&support=ADVANCED&quantity=1) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/499#issuecomment-754202196) [AutoDesk Forums](https://forums.autodesk.com/t5/autocad-for-mac-forum/apple-silicon/m-p/9652836)
* [CADintosh](https://www.lemkesoft.de/en/products/cadintosh/download/) - ✅ Yes, Full Native Apple Silicon Support - [🧪 Apple Silicon App Tested](https://doesitarm.com/apple-silicon-app-test/)
* [PrusaSlicer](https://www.prusa3d.com/prusaslicer/) - ✳️ Yes, works via Rosetta 2 with native support in development - [Verification](https://github.com/ThatGuySam/doesitarm/issues/379#issue-755576203)
* [Shaper3D](https://www.shapr3d.com/) - ✅ Yes, it was shown at the November 10th event - [Apple Nov 10 Event](https://youtu.be/5AwdkGKmZ0I?t=2211)
* [SketchUp](https://www.sketchup.com/) - ✳️ Yes, works via Rosetta 2 - [Discussion](https://forums.sketchup.com/t/the-new-m1-processor/141946)
* [SOLIDWORKS](https://www.solidworks.com/sw/support/downloads.htm) - ✳️ Yes, works via Parallels Virtualization - [Working on Parallels](https://www.parallels.com/blogs/solidworks-for-mac/)
* [Timebox 3D Collage Maker](https://timeboxapp.com/) - ✅ Yes, Full Native Apple Silicon Support as of v8.1 - [Release Notes](https://timeboxapp.com/whats-new-81)
* [Ultimaker Cura](https://ultimaker.com/software/ultimaker-cura) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/424#issue-761853484)
* [ZBrush](http://pixologic.com/zbrush/downloadcenter/#) - ✳️ Yes, works via Rosetta 2 - [Official Article](https://support.pixologic.com/article/447-support-for-apple-silicon)
#### Productivity Tools
* [AdBlock Pro for Safari](https://apps.apple.com/app/id1018301773) - ✅ Yes, full native support as of v8.1.0 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/237#issue-746743506)
* [Acrobat Pro](https://acrobat.adobe.com/us/en/acrobat/acrobat-pro.html) - ✳️ Yes, works via Rosetta 2 with some known issues - [Known Issues](https://helpx.adobe.com/acrobat/kb/mac-os11-big-sur-compatibility.html#KnownIssues) [Official Adobe Status Page](https://helpx.adobe.com/download-install/kb/apple-silicon-m1-chip.html)
* [Acrobat Reader](https://get.adobe.com/reader/) - ✳️ Yes, works via Rosetta 2 - [Source](https://helpx.adobe.com/acrobat/kb/mac-os11-big-sur-compatibility.html#WhendoesAdobeplantonativelysupportAppleSilicondevices)
* [Adobe Bridge](https://www.adobe.com/products/bridge.html) - ✳️ Yes, works via Rosetta 2 with known issues - [Known Issues](https://helpx.adobe.com/bridge/kb/bridge-and-macos-big-sur.html#apple-silicon-compatibility) [Official Adobe Status Page](https://helpx.adobe.com/download-install/kb/apple-silicon-m1-chip.html)
* [Agenda](https://agenda.com/) - ✅ Yes, Full Native Apple Silicon Support - [App Store Story](https://apps.apple.com/us/story/id1540024103)
* [Airmail](https://airmailapp.com/) - ✅ Yes, Full Native Apple Silicon Support as of v4.5.1 - [Release History](https://apps.apple.com/app/apple-store/id918858936)
* [AlDente](https://github.com/davidwernhart/AlDente/releases) - ✅ Yes, Full Native Apple Silicon Support as of v2.0 - [Release Notes](https://github.com/davidwernhart/AlDente/releases)
* [Alfred](https://www.alfredapp.com/universal/) - ✅ Yes, fully supported - [Official Announcement](https://www.alfredapp.com/blog/announcements/alfred-ready-for-apple-m1-chip/)
* [AmorphousDiskMark](https://apps.apple.com/us/app/amorphousdiskmark/id1168254295) - ✅ Yes, full native Apple Silicon support as of v3.1
* [Amphetamine](https://apps.apple.com/app/amphetamine/id937984704) - ✅ Yes, full native Apple Silicon support from 5.1 - [GitHub issue](https://github.com/ThatGuySam/doesitarm/issues/295)
* [Anki](https://apps.ankiweb.net/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/495)
* [AppCleaner](https://freemacsoft.net/appcleaner/) - ✅ Yes, Full Native Apple Silicon Support - [Verification](https://github.com/ThatGuySam/doesitarm/issues/559#issue-803995485)
* [Axure RP 9](https://www.axure.com/download) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/38)
* [Backblaze](https://www.backblaze.com/) - ✳ Yes, works via Rosetta 2 - [Verification #1](https://github.com/ThatGuySam/doesitarm/issues/409#issuecomment-744336558) [Verification #2](https://github.com/ThatGuySam/doesitarm/issues/409#issuecomment-777878266)
* [Bandizip](https://en.bandisoft.com/bandizip.mac/) - ✅ Yes, Full Native Apple Silicon Support as of v7.03 - [Release Notes](https://en.bandisoft.com/bandizip.mac/history/)
* [balenaEtcher](https://github.com/balena-io/etcher/releases) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/294#issuecomment-737011519)
* [Bartender](https://www.macbartender.com/) - ✅ Yes, fully supported as of v4.0.20 - [Blog](https://www.macbartender.com/b4blog/Apple-Silicon-Support/)
@ -269,14 +313,17 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [Box Drive](https://www.box.com/resources/downloads) - ⏹ Not yet, but it's currently in development. - [Official Post](https://support.box.com/hc/en-us/community/posts/360051323454-Box-Drive-s-system-extension-failed-to-load?page=1#community_comment_1500000009302)
* [Brave Browser](https://brave.com/#mac-options) - ✅ Yes, Full Native Apple Silicon Support
* [Calibre](https://calibre-ebook.com/download_osx) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/26#issuecomment-736778254)
* [Call Recorder for Skype](https://www.ecamm.com/mac/callrecorder/) - 🚫 No, not supported and no plans for support - [Official Post](https://ecamm.com/blog/call-recorder-for-skype-update/)
* [Camo Studio](https://reincubate.com/camo/) - ✅ Yes, Full Native Apple Silicon Support - [Release Notes](https://reincubate.com/support/camo/release-notes/#1.1.3.122)
* [Chrome](https://www.google.com/chrome/) - ✅ Yes, fully supported as of v87 - [Article](https://9to5google.com/2020/11/17/chrome-mac-apple-silicon/)
* [Citrix Workspace](https://www.citrix.com/downloads/workspace-app/mac/workspace-app-for-mac-latest.html) - ✳️ Yes, works via Rosetta 2 - [Discussion](https://discussions.citrix.com/topic/411196-will-citrix-viewer-run-on-new-apple-hardware-with-apple-silicon-m1/)
* [CleanShot X](https://cleanshot.com) - ✅ Yes, fully supported as of v3.4.4 - [Changelog](https://cleanshot.com/changelog/)
* [coconutBattery](https://www.coconut-flavour.com/coconutbattery/) - ✅ Yes, full native support as of v3.9.2
* [Coloban](https://www.coloban.com) - ⏹ Not yet, but it's currently in development. - [Coloban Forum Issue](https://forum.coloban.com/index.php?u=/topic/21/new-arm-based-apple-computers)
* [CrossOver](https://www.codeweavers.com/) - ✳️ Runs via Rosetta 2 - [Official Blog](https://www.codeweavers.com/blog/jwhite/2020/11/10/its-great-to-live-in-interesting-times)
* [Day One Journal](https://apps.apple.com/app/id1055511498) - ✳️ Yes, works via Rosetta 2 - [Official Tweet](https://twitter.com/dayoneapp/status/1332727758447734784?s=20)
* [Day One Journal](https://apps.apple.com/app/id1055511498) - ✅ Yes, Full Native Apple Silicon Support as of v5.8 - [Release Notes](https://help.dayoneapp.com/en/articles/469749-mac-release-notes)
* [DEVONthink](https://www.devontechnologies.com/download/) - ✅ Yes, Full Native Apple Silicon Support as of v3.5.2 - [Release Notes](https://www.devontechnologies.com/blog/20200814-devonthink-352)
* [DisplayLink Manager](https://www.displaylink.com/downloads/macos) - ✅ Yes, Full Native Apple Silicon Support as of v1.3 - [Release Notes](https://gist.github.com/ThatGuySam/30e5f1d2ee4edacab6323acaa55791fc)
* [Displays for Mac](https://www.jibapps.com/apps/displays/) - ✅ Yes, Full Native Apple Silicon Support as of v1.9.7 - [Source](https://twitter.com/jibapps/status/1338478515453386755)
* [Drafts](https://itunes.apple.com/app/id1236254471?ls=1&mt=8&at=11l4Cf&ct=site) - ✅ Yes, Full Native Apple Silicon Support - [Official Tweet](https://twitter.com/draftsapp/status/1326263191601618945)
* [Dropbox](https://www.dropbox.com) - ✳️ Yes, works via Rosetta 2 as of v110.4.458 - [Forum Post](https://www.dropboxforum.com/t5/Dropbox-desktop-client-builds/Stable-Build-110-4-458/m-p/470973/highlight/true#M6110)
@ -286,14 +333,17 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [Firefox](https://www.mozilla.org/en-US/firefox/new/) - ✅ Yes, Full Native Apple Silicon Support as of v84 - [Release Notes](https://www.mozilla.org/en-US/firefox/84.0/releasenotes/)
* [flickery](https://eternalstorms.at/flickery) - ✅ Yes, Full Native Apple Silicon Support as of v1.9.48 - [Blog Post](https://blog.eternalstorms.at/2020/11/09/app-update-galore/)
* [Geekbench](https://www.geekbench.com/download/mac/) - ✅ Yes, full native support as of v5.3 - [Release Notes](https://www.geekbench.com/blog/2020/11/geekbench-53/)
* [Gemini 2](https://macpaw.com/gemini) - ✳️ Yes, works via Rosetta 2 - [Official Tweet](https://twitter.com/MacPaw/status/1361651643591364613)
* [GitHub Classroom Assistant](https://classroom.github.com/assistant) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/419#issue-760871225)
* [Glimpses](https://eternalstorms.at/glimpses) - ✅ Yes, Full Native Apple Silicon Support as of v2.2.3 - [Blog Post](https://blog.eternalstorms.at/2020/11/09/app-update-galore/)
* [Google Backup and Sync](https://www.google.com/drive/download/) - 🚫 Not yet supported, unknown if Apple or Google issue - [Google Thread](https://support.google.com/drive/thread/85225515?hl=en&msgid=86860457) [Reddit Thread](https://www.reddit.com/r/macbookair/comments/k65aps/m1_mba_google_backup_sync_error_8b227910/?sort=new) [MacRumours Thread](https://forums.macrumors.com/threads/google-backup-and-sync-not-working-on-m1.2269295/page-3)
* [Google Backup and Sync](https://www.google.com/drive/download/) - ✳️ Yes, works via Rosetta 2 as of v3.54 - [Release Notes](https://support.google.com/a/answer/7573023?hl=en) [Verification](https://github.com/ThatGuySam/doesitarm/issues/564#issue-807949490)
* [Google Drive File Stream](https://support.google.com/drive/answer/7329379#zippy=%2Cdownload-install-drive-file-stream) - 🚫 No, not yet supported only works on Intel-based Macs - [Official Status](https://support.google.com/a/answer/7491144?utm_medium=et&utm_source=aboutdrive&utm_content=getstarted&utm_campaign=en_us&hl=en#:~:text=Drive%20File%20Stream%20does%20not%20yet%20support%20Apple%20M1%20devices)
* [GrandPerspective](https://apps.apple.com/app/grandperspective/id1111570163?mt=12) - ✅ Yes, Full Native Apple Silicon Support as of 2.5.3 - [Release Notes](http://grandperspectiv.sourceforge.net/)
* [HazeOver](https://hazeover.com/) - ✅ Yes, Full Native Apple Silicon Support as of 1.8.8 - [Official News](https://hazeover.com/news.html)
* [Highland 2](https://quoteunquoteapps.com/highland-2/) - ✅ Yes, Full Native Apple Silicon Support as of v2.9 - [App Store Story](https://apps.apple.com/us/story/id1540024103)
* [Highlights for Mac](https://highlightsapp.net/) - ✅ Yes, Full Native Apple Silicon Support as of v2020.3 - [Official Blog](https://highlightsapp.net/blog/2020/11/12/Time-for-change/)
* [IA Writer](https://apps.apple.com/us/app/ia-writer/id775737172) - ✅ Yes, Full Native Apple Silicon Support - [Official Twitter](https://twitter.com/iawriter/status/1326284671005696009?s=21)
* [IDrive](https://www.idrive.com/online-backup-download) - ✳ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/542#issue-797628007)
* [iMazing 2](https://imazing.com/download) - ✳️ Yes, works via Rosetta 2 with native support in development - [Release notes](https://downloads.imazing.com/mac/iMazing/2.13.1.14452/release-notes.html)
* [Internal Phone Numbers](https://lighthouse16.com/internal-phone-numbers/) - ✅ Yes, fully supported as of v1.2.2 - [Source](https://lighthouse16.com/journal/apple-silicon-support/)
* [iStat Menus](https://bjango.com/mac/istatmenus/) - ✅ Yes, Full Native Apple Silicon Support as of v6.51 - [Official Twitter](https://twitter.com/bjango/status/1328863648270356482)
@ -306,28 +356,34 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [LibreOffice](https://www.libreoffice.org/download/download/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/371#issue-755004669) [Official Post](https://www.collaboraoffice.com/desktop/update-on-libreoffice-support-for-arm-based-macs/)
* [Logitech Options](https://www.logitech.com/en-us/product/options) - ✳️ Yes, works via Rosetta 2. Some users report issues with the Flow feature. - [MacRumors Discussion](https://forums.macrumors.com/threads/does-logitech-options-works.2270516)
* [Lunar for Mac](https://lunar.fyi/) - 🚫 No, not yet supported only works on Intel-based Macs - [Issue #1](https://github.com/alin23/Lunar/issues/210) [Issue #2](https://github.com/alin23/Lunar/issues/215)
* [Maccy](https://maccy.app/) - ✅ Yes, Full Native Apple Silicon Support - [Release Notes](https://github.com/p0deje/Maccy/releases/tag/0.19.0) [Mac App Store](https://apps.apple.com/us/app/maccy/id1527619437)
* [MacZip](https://ezip.awehunt.com/) - ✅ Yes, Full Native Apple Silicon Support as of v2.0 - [Release Notes](https://ezip.awehunt.com/)
* [Microsoft Edge](https://www.microsoft.com/en-us/edge) - ✳️ Yes, works via Rosetta 2, native Apple Silicon build available for insiders - [Insider Download](https://www.microsoftedgeinsider.com/en-us/download/canary)
* [Microsoft Edge](https://www.microsoft.com/en-us/edge) - ✅ Yes, Full Native Apple Silicon Support as of v88.0.705.50 - [Release Notes](https://docs.microsoft.com/en-us/deployedge/microsoft-edge-relnote-stable-channel)
* [Microsoft Excel](https://apps.apple.com/cn/app/microsoft-excel/id462058435?l=en&mt=12) - ✅ Yes, Full Native Apple Silicon Support as of v16.44
* [Microsoft Office 365](https://www.microsoft.com/en-us/microsoft-365/office-365) - ✅ Yes, Full Native Apple Silicon Support as of v16.44 - [Official Post](https://www.microsoft.com/en-us/microsoft-365/blog/2020/12/15/4-ways-microsoft-365-is-improving-the-experience-for-mac-users/) [WWDC Preview](https://youtu.be/GEZhD3J89ZE?t=5681)
* [Microsoft OneNote](https://apps.apple.com/cn/app/microsoft-onenote/id784801555?l=en&mt=12) - ✅ Yes, Full Native Apple Silicon Support as of v16.44
* [Microsoft Outlook](https://apps.apple.com/app/microsoft-outlook/id985367838?l=en&mt=12) - ✅ Yes, Full Native Apple Silicon Support as of v16.44
* [Microsoft PowerPoint](https://apps.apple.com/cn/app/microsoft-powerpoint/id462062816?l=en&mt=12) - ✅ Yes, Full Native Apple Silicon Support as of v16.44
* [Microsoft Remote Desktop](https://apps.apple.com/au/app/microsoft-remote-desktop/id1295203466?mt=12) - ✳️ Yes, works via Rosetta 2 with native support in beta - [Apple Silicon Beta](https://install.appcenter.ms/orgs/rdmacios-k2vy/apps/microsoft-remote-desktop-for-mac/distribution_groups/all-users-of-microsoft-remote-desktop-for-mac)
* [Microsoft Word](https://apps.apple.com/cn/app/microsoft-word/id462054704?l=en&mt=12) - ✅ Yes, Full Native Apple Silicon Support as of v16.44
* [MindNode](https://mindnode.com/) - ✅ Yes, Full Native Apple Silicon Support - [App Store Story](https://apps.apple.com/us/story/id1540024103)
* [Monero GUI Wallet](https://www.getmonero.org/downloads/) - ✳️ Yes, works via Rosetta 2 with a few minor bugs - [Source](https://github.com/ThatGuySam/doesitarm/issues/435)
* [Moom](https://manytricks.com/moom/) - ✅ Yes, Full Native Apple Silicon Support as of v3.2.20 - [Official Tweet](https://twitter.com/manytricks/status/1333456606449774595)
* [Moon FM](https://apps.apple.com/us/app/moon-fm-premium-podcast-app/id1465712037?mt=12) - ✅ Yes, Full Native Apple Silicon Support as of v2.0.3
* [Newton Mail](https://newtonhq.com/#app) - ✅ Yes, Full Native Apple Silicon Support
* [Nisus Writer Pro](https://nisus.com/pro/) - ✅ Yes, Full Native Apple Silicon Support as of v3.2 (some file conversion helpers run in Rosetta) - [Release notes](https://www.nisus.com/pro//whatsnew.php)
* [Nisus Writer Express](https://nisus.com/Express/) - ✅ Yes, Full Native Apple Silicon Support as of v3.2 (some file conversion helpers run in Rosetta) - [Release notes](https://www.nisus.com/pro//whatsnew.php)
* [Notability](https://www.gingerlabs.com/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/417#issue-760864996)
* [Notion Desktop](https://www.notion.so) - ✅ Yes, Full Native Apple Silicon Support - [Official Tweet](https://twitter.com/NotionHQ/status/1333867094463582208?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Etweet) [Verification](https://github.com/ThatGuySam/doesitarm/issues/378#issue-755529762)
* [Noto](http://noto.ink/) - ✅ Yes, Full Native Apple Silicon Support - [App Store Story](https://apps.apple.com/us/story/id1540024103)
* [NVIDIA GeForce NOW](https://www.nvidia.com/en-us/geforce-now/download/) - ✅ Yes, Full Native Apple Silicon Support as of v2.0.27 - [Release Notes](https://www.nvidia.com/pt-br/geforce/release-notes/GFN/2_0_27/Rich/gfn-v2_0_27-rich-release-highlights/)
* [Obsidian](https://obsidian.md/download) - ✅ Yes, full native support as of v0.10.1
* [OmniFocus](https://www.omnigroup.com/omnifocus) - ✅ Yes, Full Native Apple Silicon Support as of v3.10 - [Release Notes](https://www.omnigroup.com/releasenotes/omnifocus)
* [OmniGraffle](https://www.omnigroup.com/omnigraffle) - ✅ Yes, Full Native Apple Silicon Support as of v7.18 - [Release Notes](https://www.omnigroup.com/releasenotes/omnigraffle)
* [OmniOutliner](https://www.omnigroup.com/omnioutliner) - ✅ Yes, Full Native Apple Silicon Support as of v5.8 - [Release Notes](https://www.omnigroup.com/releasenotes/omnioutliner)
* [OmniPlan](https://www.omnigroup.com/omniplan) - ✅ Yes, Full Native Apple Silicon Support as of v4.2 - [Release Notes](https://www.omnigroup.com/releasenotes/omniplan)
* [ONLYOFFICE](https://www.onlyoffice.com/download-desktop.aspx?from=desktop) - ✳️ Yes, works via Rosetta 2 - [Official Post](https://www.onlyoffice.com/blog/2020/12/onlyoffice-desktop-editors-6-1-goes-to-arm-based-apple-silicon-macs/?utm_source=twi&utm_medium=social&utm_campaign=desktop_6_1)
* [Pacifist](https://www.charlessoft.com/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/573#issue-812045761)
* [Paragon NTFS](https://www.paragon-software.com/home/ntfs-mac/) - ✅ Yes, Full Native Apple Silicon Support
* [Parcel](https://parcelapp.net/) - ✅ Yes, Full Native Apple Silicon Support as of 6.6 - [Tweet](https://twitter.com/parcel_app/status/1325751301322362880)
* [PDF Viewer](https://pdfviewer.io/) - ✅ Yes, Full Native Apple Silicon Support as of v5.1 - [Blog Post](https://pdfviewer.io/blog/2020/pdf-viewer-5-1-for-ipad-iphone-mac/)
@ -339,17 +395,20 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [Remotix](https://remotix.com/downloads-mac/) - ✅ Yes, fully supported as of v6.3 - [Release Notes](https://downloads.remotix.com/remotix-mac/release-notes.html?v=6.3)
* [Razer macOS](https://github.com/1kc/razer-macos/releases) - ✳️ Yes, runs via Rosetta 2
* [Razer Synapse](https://www.razer.com/synapse-2) - 🚫 No, not yet supported only works on Intel-based Macs - [Working Alternative](https://github.com/1kc/razer-macos)
* [restic](https://restic.net/) - ✅ Yes, Full Native Apple Silicon Support - [Verification](https://github.com/ThatGuySam/doesitarm/issues/492#issuecomment-754580871)
* [RingCentral](https://apps.apple.com/us/app/id715886894) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/251#issuecomment-736105390)
* [Safari Web Browser](https://www.apple.com/safari/) - ✅ Yes, fully supported
* [ScreenFloat](https://eternalstorms.at/ScreenFloat/) - ✅ Yes, Full Native Apple Silicon Support as of v1.5.18 - [Blog Post](https://blog.eternalstorms.at/2020/11/09/app-update-galore/)
* [SeaDrive](https://www.seafile.com/en/download/) - ✳️ Yes, works via Rosetta 2 as of v2.0.10 - [Source](https://forum.seafile.com/t/seadrive-2-0-8-is-released-support-for-macos-11/13199/25)
* [SeaFile](https://www.seafile.com/en/download/) - ✳️ Yes, works via Rosetta 2 as of v7.0.10 - [Source](https://forum.seafile.com/t/native-support-for-apple-silicon/13390)
* [ShortcutRecorder](https://github.com/Kentzo/ShortcutRecorder/releases) - ✅ Yes, Full Native Apple Silicon Support - [Source](https://github.com/Kentzo/ShortcutRecorder/issues/134#event-4282523497)
* [SiriMote](https://eternalstorms.at/sirimote) - ✅ Yes, Full Native Apple Silicon Support as of v1.3.9 - [Blog Post](https://blog.eternalstorms.at/2020/11/09/app-update-galore/)
* [Skim PDF Reader](https://skim-app.sourceforge.io/) - ✅ Yes, Full Native Apple Silicon Support - [Verification](https://github.com/ThatGuySam/doesitarm/issues/468#issuecomment-751807890)
* [SnagIt](https://www.techsmith.com/download/snagit/) - ✳️ Yes, works via Rosetta 2 but without video capture - [Source](https://github.com/ThatGuySam/doesitarm/issues/413) [Official documentation](https://support.techsmith.com/hc/en-us/articles/360052555611-Snagit-and-Apple-Silicon-Compatibility-Info)
* [Synology Drive Client](https://www.synology.com/en-us/support/download/DDSM#utilities) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/399#issuecomment-742175817)
* [Tablecruncher](https://tablecruncher.com/download/) - ✅ Yes, Full Native Apple Silicon Support - [Official Post](https://tablecruncher.com/blog/2020/version-1.5.1-apple-silicon-ready/)
* [TeamViewer](https://www.teamviewer.com/en-us/) - ✅ Yes, Full Native Apple Silicon Support as of v15.12.4 - [Release Notes](https://community.teamviewer.com/t5/Change-Logs-EN/macOS-v15-12-4-Full-Change-Log/m-p/107706)
* [TextSniper](https://textsniper.app/) - ✅ Yes, Full Native Apple Silicon Support as of v1.3.1 - [Release Notes](https://textsniper.app/release-notes) [Verification](https://github.com/ThatGuySam/doesitarm/issues/571#issue-811238095)
* [TG Pro](https://www.tunabellysoftware.com/tgpro/) - ✅ Yes, Full Native Apple Silicon Support as of v2.53 - [Release Notes](https://www.tunabellysoftware.com/tgpro/releasenotes/)
* [Thunderbird](https://www.thunderbird.net/en-US/) - ✳️ Yes, works via Rosetta 2 - [Bugzilla Tracker](https://bugzilla.mozilla.org/show_bug.cgi?id=1678775)
* [TouchSwitcher](https://hazeover.com/touchswitcher.html) - ✅ Yes, Full Native Apple Silicon Support as of 1.4 - [Official News](https://hazeover.com/news.html)
@ -373,28 +432,31 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [Dolphin](https://dolphin-emu.org/download/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/452)
* [DOSBox](https://sourceforge.net/projects/dosbox/) - ✳️ Yes, it works via Rosetta 2 - [Project Ticket 149](https://sourceforge.net/p/dosbox/feature-requests/149/)
* [DOSBox-X](https://dosbox-x.com) - ✅ Yes, Full Native Apple Silicon Support as of 0.83.8 - [Github Release](https://github.com/joncampbell123/dosbox-x/releases/tag/dosbox-x-v0.83.8)
* [IINA](https://iina.io/download/) - ✳️ Yes, works via Rosetta with native support on the way - [Github Issue](https://github.com/iina/iina/issues/3067#issuecomment-671804703)
* [IINA](https://iina.io/download/) - ✅ Yes, Full Native Apple Silicon Support as of 1.2.0 - [Github Release](https://github.com/iina/iina/releases/tag/v1.2.0)
* [Infuse](https://apps.apple.com/cn/app/infuse-6/id1136220934) - ⏹ Not released yet, macOS support is currently in alpha test and it runs via Rosetta 2 - [Discussion](https://github.com/ThatGuySam/doesitarm/issues/458) [Sign up for Alpha](http://firecore.com/macos)
* [Movist](https://movistprime.com/) - ✅ Yes, Full Native Apple Silicon Support as of v2.6 - [Changelog](https://movistprime.com/changelog.html)
* [NetEase Music](https://music.163.com/#/download) - ✅ Yes, Full Native Apple Silicon Support as of v2.3.4 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/528#issue-789094015)
* [News Explorer](https://betamagic.nl/products/newsexplorer.html) - ✅ Yes, Full Native Apple Silicon Support as of v1.9.11 - [Blog Post](https://betamagic.nl/news/2020/2020_09.html)
* [QQ音乐(QQ Music)](https://apps.apple.com/cn/app/qq音乐-让生活充满音乐/id595615424?l=en&mt=12) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/368)
* [PPSSPP](https://build.ppsspp.org/?page/downloads#osx) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/347)
* [Parsec](https://parsec.app/downloads) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/513#issue-782309694)
* [PPSSPP](https://build.ppsspp.org/?page/downloads#osx) - ✅ Yes, Full Native Apple Silicon Support as of v1.11 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/347#issuecomment-776444965)
* [PS Remote Play](https://remoteplay.dl.playstation.net/remoteplay/lang/en/ps5_mac.html) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/441#issuecomment-748282150)
* [Remote Buddy](https://www.iospirit.com/products/remotebuddy/download/) - ✅ Yes, Full Native Apple Silicon Support - [Verification](https://github.com/ThatGuySam/doesitarm/issues/556#issue-802733637)
* [RetroArch](https://www.retroarch.com/?page=platforms) - ✳️ Yes, works via Rosetta 2 with native support in development - [Verification](https://github.com/ThatGuySam/doesitarm/issues/348)
* [Spotify](https://www.spotify.com/us/download/mac/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/172)
* [Steam](https://store.steampowered.com/about/) - ✳️ Yes, reported working via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/153)
* [Tidal](https://tidal.com/download) - ✳️ Yes, working via Rosetta 2 but with occasional force quits as of 2.23.0.488 - [GitHub issue](https://github.com/ThatGuySam/doesitarm/issues/314)
* [Twitch](https://www.twitch.tv/downloads/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/387)
* [UU Booster](https://uu.163.com/down/mac/) - ✅ Yes, Full Native Apple Silicon Support - [Verification](https://github.com/ThatGuySam/doesitarm/issues/464#issue-771607189)
* [Vienna](https://github.com/ViennaRSS/vienna-rss/releases/latest) - ✅ Yes, Full Native Apple Silicon Support as of v3.6 - [Release Notes](https://github.com/ViennaRSS/vienna-rss/releases/tag/v/3.6.0)
* [VLC](https://www.videolan.org/vlc/download-macosx.html) - ✅ Yes, Full Native Apple Silicon Support as of v3.0.12 - [Release Notes](https://www.videolan.org/news.html#news-2021-01-12)
* [Zwift](https://www.zwift.com/eu-de/download) - ✳️ Yes, works via Rosetta 2 as of v1.0 (25) - [Source](https://forums.zwift.com/t/m1-apple-silicon-compatibility/514491/81) [Verification](https://raw.githubusercontent.com/steve1878/images_does_it_arm/main/zwift_1.0_25.png)
#### Social and communication
#### Social and Communication
* [Cisco Webex Meetings](https://www.webex.com/downloads.html) - ✳️ Yes, works via Rosetta 2 - [Source](https://github.com/ThatGuySam/doesitarm/issues/59#issuecomment-731506903)
* [Cisco Webex Meetings](https://www.webex.com/downloads.html) - ✅ Yes, Full Native Apple Silicon Support - [Verification](https://github.com/ThatGuySam/doesitarm/issues/530#issue-790322821)
* [Discord](https://discord.com/download) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/192#issuecomment-734753133)
* [Mattermost](https://mattermost.com/download/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/245#issuecomment-735282100)
* [Facebook Messenger Desktop](https://www.messenger.com/desktop) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/520)
@ -403,7 +465,9 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
* [QQ](https://im.qq.com/macqq/) - ✅ Yes, Full Native Apple Silicon Support as of v6.7.0.20110 - [Release Notes](https://im.qq.com/macqq/support.html)
* [QQ 体验版(MacCatalyst)](https://im.qq.com/macqq/) - ✳️ Runs via Rosetta 2
* [Signal](https://www.signal.org/) - ✳️ Yes, works via Rosetta 2 - [Source](https://github.com/ThatGuySam/doesitarm/issues/337)
* [Slack](https://slack.com/) - ✳️ Yes, works via Rosetta 2 with native support in beta. - [Official Tweet](https://twitter.com/SlackEng/status/1326237727667314688)
* [Skype](https://www.skype.com/en/get-skype/) - ✳️ Yes, works via Rosetta 2 - [Video](https://doesitarm.com/tv/the-new-m1-macbook-running-microsoft-office-business-apps-teams-skype-excel-cpu-and-ram-usage-i-ibseaue3se8/)
* [Skype for Business](https://www.microsoft.com/en-us/microsoft-365/skype-for-business/download-app) - ✳️ Yes, works via Rosetta 2 - [Video](https://doesitarm.com/tv/the-new-m1-macbook-running-microsoft-office-business-apps-teams-skype-excel-cpu-and-ram-usage-i-ibseaue3se8/)
* [Slack](https://slack.com/) - ✅ Yes, Full Native Apple Silicon Support as of 4.13.0 - [Release Notes](https://slack.com/intl/en-au/release-notes/mac)
* [Telegram](https://macos.telegram.org/) - ✅ Yes, Full Native Apple Silicon Support as of 7.2.4 - [GitHub issue](https://github.com/ThatGuySam/doesitarm/issues/52) [Changelog](https://macos.telegram.org/#v7-2-4-2020-11-29)
* [WeChat](https://apps.apple.com/cn/app/wechat/id836500024?l=en&mt=12) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/369)
* [Welly BBS](https://wellybbs.com/) - ✅ Yes, Full Native Apple Silicon Support as of Version 2020.9 - [App Store](https://apps.apple.com/us/app/id1521402269)
@ -415,16 +479,21 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
#### VPNs, Security, and Privacy
* [1Password](https://1password.com/) - ✳️ Runs via Rosetta with native support currently in development. - [Forum Discussion](https://1password.community/discussion/114181/will-1password-run-on-apple-silicon-based-mac)
* [AdGuard](https://adguard.com/en/welcome.html) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/565#issue-808854867)
* [Bitwarden](https://bitwarden.com/) - ✳️ Yes, works via Rosetta 2 with a patch in development - [Issue Tracker](https://github.com/bitwarden/desktop/issues/567)
* [Cisco AnyConnect Secure Mobility Client](https://www.cisco.com/c/en/us/products/security/anyconnect-secure-mobility-client/index.html) - ✳️ Yes, works via Rosetta 2 - [Source](https://github.com/ThatGuySam/doesitarm/issues/416#issue-760860704)
* [ClashX](https://github.com/yichengchen/clashX#install) - ✅ Yes, Full Native Apple Silicon Support as of v1.31.1.1 - [Release Notes](https://github.com/yichengchen/clashX/releases/tag/1.31.1)
* [Cryptomator](https://cryptomator.org/) - 🚫 No, crashes under Rosetta 2 only recommended on Intel-based Macs - [Crashing Issue](https://github.com/cryptomator/cryptomator/issues/1419)
* [Elpass](https://elpass.app/) - ✅ Yes, full native Apple Silicon Support as of v1.1.10 - [Issue](https://github.com/ThatGuySam/doesitarm/issues/176)
* [Enpass](https://www.enpass.io/) - ✳️ Runs via Rosetta 2 - [Forum Discussion](https://discussion.enpass.io/index.php?/topic/24222-enpass-on-m1-mac-arm-silicon/&tab=comments#comment-56371)
* [GPG Suite](https://gpgtools.org/) - ✅ Yes, Full Native Apple Silicon Support as of 2020.2 - [Release notes](https://gpgtools.org/releases/gpgsuite/2020.2/release-notes.html?ni=1)
* [IVPN](https://www.ivpn.net/apps-macos/) - ✳️ Yes, works via Rosetta 2 - [GitHub issue](https://github.com/ThatGuySam/doesitarm/issues/315)
* [Jamf Protect](https://www.jamf.com/products/jamf-protect/) - ✅ Yes, Full Native Apple Silicon Support as of v1.2.0.217 - [Release Notes](https://docs.jamf.com/jamf-protect/administrator-guide/Release_History.html)
* [KeePassXC](https://keepassxc.org/download/#mac) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/234)
* [KeePassXC](https://keepassxc.org/download/#mac) - ✅ Yes, Full Native Apple Silicon Support as of v2.6.4 - [Release Notes](https://keepassxc.org/blog/2021-01-31-2.6.4-released/)
* [KeeWeb](https://keeweb.info/) - ✅ Yes, Full Native Apple Silicon Support - [Official Tweet](https://twitter.com/kee_web/status/1334885117584609295)
* [LastPass](https://www.lastpass.com/) - ✳️ Yes, works via Rosetta 2, but the Safari extension has issues - [Verification](https://github.com/ThatGuySam/doesitarm/issues/233#issuecomment-731506984) [Release Notes](https://lastpass.com/upgrade.php?fromwebsite=1&releasenotes=1) [Safari Issue](https://community.logmein.com/t5/Support-Discussions/macOS-Big-Sur-Safari-14-0-1-Official-Support/m-p/256549)
* [Little Snitch](https://www.obdev.at/products/littlesnitch/index.html) - ✅ Yes, Full Native Apple Silicon Support from 5.0 - [Release notes](https://www.obdev.at/products/littlesnitch/releasenotes.html)
* [Mullvad VPN](https://mullvad.net/en/download/macos/) - ✳️ Yes, works via Rosetta 2 - [Verification](https://github.com/ThatGuySam/doesitarm/issues/566#issue-808856204)
* [NordVPN](https://nordvpn.com/download/nordvpn-site/) - ✳️ Yes, works via Rosetta 2 - [Source](https://github.com/ThatGuySam/doesitarm/issues/317#issuecomment-736876490)
* [SecKey](https://lighthouse16.com/seckey/) - ✅ Yes, fully supported as of v1.3.3 - [Source](https://lighthouse16.com/journal/apple-silicon-support/)
* [Secrets for Mac](https://apps.apple.com/app/secrets/id973049011?mt=12) - ✅ Yes, Full Native Apple Silicon Support as of v3.4.0 - [Official Post](https://outercorner.com/blog/2020/11/password-autofill-now-on-macos-big-sur/)
@ -444,6 +513,7 @@ Builds - [Java on M1 Benchmarks](https://docs.google.com/spreadsheets/d/1g4U7LAI
## More Apple Silicon Lists
* [Is Apple silicon ready?](https://isapplesiliconready.com/) - Great list with detailed app status
* [Apple Silicon Games](https://applesilicongames.com/) - List of reported Games support including performance info.
* [SweetWater Compatibility Guide](https://www.sweetwater.com/sweetcare/articles/macos-11-big-sur-compatibility-guide/) - Big Sur and Apple Silicon reports for producstion and live performance software
* [Ported2M1](https://ported2m1.com/) - Beautiful list with app support discussion
* [MacRumors List](https://forums.macrumors.com/threads/universal-and-native-apple-silicon-apps.2267176/) - List of Universal and Native Apple Silicon Apps
* [RoaringApps](https://roaringapps.com/collections/list-of-apple-silicon-native-apps) - List of apps ready for Apple Silicon M1 chip Macs

View file

@ -142,3 +142,21 @@ html {
.hover\:bg-blur:hover {
backdrop-filter: blur(15px);
}
.shimmer {
animation: placeHolderShimmer 1s infinite;
animation-timing-function: linear;
background: #f6f7f8;
background: linear-gradient(to right, rgba(0, 0, 0, 0.07) 8%, rgba(0, 0, 0, 0.45) 18%, rgba(0, 0, 0, 0.07) 33%);
background-size: 200% 100px;
background-attachment: fixed;
}
@keyframes placeHolderShimmer {
0% {
background-position: 100% 0;
}
100% {
background-position: -100% 0;
}
}

View file

@ -0,0 +1,148 @@
<template>
<div
:class="[
'vue-full-screen-file-drop',
'fixed inset-0',
classes
]"
:style="{
'z-index': 10000
}"
>
<slot>
<div
class="vue-full-screen-file-drop__content"
>
{{ text }}
</div>
</slot>
<input
ref="file-selector"
:style="{
//'z-index': 10001
}"
type="file"
accept="application/**"
multiple
class="absolute inset-0 w-screen h-screen"
@change="fileInputChanged"
>
</div>
</template>
<script>
export default {
// name: 'VueFullScreenFileDrop',
props: {
formFieldName: {
type: String,
default: 'upload',
},
text: {
type: String,
default: 'Upload Files',
},
},
data() {
return {
visible: false,
lastTarget: null,
};
},
computed: {
classes() {
return {
'vue-full-screen-file-drop--visible': true //this.visible,
};
},
},
mounted () {
window.addEventListener('dragenter', this.onDragEnter);
window.addEventListener('dragleave', this.onDragLeave);
window.addEventListener('dragover', this.onDragOver);
// window.addEventListener('drop', this.onDrop);
},
beforeDestroy () {
window.removeEventListener('dragenter', this.onDragEnter);
window.removeEventListener('dragleave', this.onDragLeave);
window.removeEventListener('dragover', this.onDragOver);
// window.removeEventListener('drop', this.onDrop);
},
methods: {
onDragEnter(e) {
this.lastTarget = e.target;
this.visible = true;
},
onDragLeave(e) {
if (e.target === this.lastTarget) {
this.visible = false;
}
},
onDragOver(e) {
e.preventDefault();
},
onDrop(e) {
e.preventDefault();
// this.visible = false;
// const files = e.dataTransfer.files;
// const formData = this.getFormData(files);
// this.$emit('drop', formData, files);
},
async fileInputChanged () {
console.log('file-selector', this.$refs['file-selector'])
const files = this.$refs['file-selector'].files
console.log('fileInputChanged files', files)
this.visible = false;
// const files = e.dataTransfer.files;
const formData = this.getFormData(files);
this.$emit('drop', formData, files);
},
getFormData(files) {
const formData = new FormData();
Array.prototype.forEach.call(files, file => {
formData.append(this.formFieldName, file, file.name);
});
return formData;
},
},
}
</script>
<style lang='css'>
.vue-full-screen-file-drop {
/* position: fixed;
top: 0;
left: 0;
z-index: 10000;
width: 100%;
height: 100%; */
background-color: rgba(0,0,0,0.4);
visibility: hidden;
opacity: 0;
transition: visibility 200ms, opacity 200ms;
}
.vue-full-screen-file-drop--visible {
opacity: 1;
visibility: visible;
}
.vue-full-screen-file-drop__content {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
color: #fff;
font-size: 4em;
}
.vue-full-screen-file-drop__content:before {
border: 5px dashed #fff;
content: "";
bottom: 60px;
left: 60px;
position: absolute;
right: 60px;
top: 60px;
}
</style>

View file

@ -6,7 +6,7 @@
isOpen ? 'bg-blur' : ''
]"
>
<div class="max-w-7xl mx-auto px-4 lg:px-6 lg:px-8">
<div class="max-w-7xl mx-auto px-4 lg:px-6">
<div class="flex justify-between h-16">
<div class="flex">
<div class="-ml-2 mr-2 flex items-center lg:hidden">
@ -83,13 +83,15 @@
</LinkButton>
</span> -->
<a
href="https://www.producthunt.com/posts/does-it-arm-benchmarks?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-does-it-arm-benchmarks"
href="https://www.producthunt.com/posts/apple-silicon-app-test?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-apple-silicon-app-test"
rel="noopener"
target="_blank"
>
<img
src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=279410&theme=light"
alt="Does It ARM Benchmarks - Curated App Benchmark Videos for Apple Silicon and Apple M1 | Product Hunt"
src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=285320&theme=light"
alt="Apple Silicon App Test - Test your apps for compatibility before you buy an M1 Mac | Product Hunt"
style="width: 200px; height: 43px;"
width="200"
height="43"
@ -161,6 +163,10 @@ export default {
label: 'Games',
url: '/games',
},
{
label: 'Apple Silicon App Test',
url: '/apple-silicon-app-test',
},
])
}
},

View file

@ -0,0 +1,615 @@
import plist from 'plist'
import axios from 'axios'
import parseMacho from './macho/index.js'
const prettyBytes = require('pretty-bytes')
const knownArchiveExtensions = new Set([
'app',
'dmg',
// 'pkg',
'zip',
// 'gz',
// 'bz2'
])
const notAppFileTypes = new Set([
'image',
'text',
'audio',
'video'
])
const knownAppExtensions = new Set([
'.app',
'.app.zip'
])
function isString( maybeString ) {
return (typeof maybeString === 'string' || maybeString instanceof String)
}
function isValidHttpUrl( string ) {
if ( !isString( string ) ) return false
let url
try {
url = new URL(string)
} catch (_) {
return false
}
return url.protocol === "http:" || url.protocol === "https:"
}
function callWithTimeout(timeout, func) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error("timeout")), timeout)
func().then(
response => resolve(response),
err => reject(new Error(err))
).finally(() => clearTimeout(timer))
})
}
let zip
export default class AppFilesScanner {
constructor( {
observableFilesArray,
testResultStore
} ) {
// Files to process
this.files = observableFilesArray
this.testResultStore = testResultStore
// https://gildas-lormeau.github.io/zip.js/
zip = require('@zip.js/zip.js')
// https://gildas-lormeau.github.io/zip.js/core-api.html#configuration
zip.configure({
workerScripts: true,
// workerScripts: {
// inflate: ["lib/z-worker-pako.js", "pako_inflate.min.js"]
// }
})
}
isApp ( file ) {
if ( file.type.includes('/') && notAppFileTypes.has( file.type.split('/')[0] ) ) return false
return true
}
getStatusMessage () {
// 'Drag and drop one or multiple apps'
// return `Searching for apps at ${ file.url }`
}
getFileStatusMessage ( file ) {
// CORS error - 'This page has asked not to be scanned. '
// Status Code Error - 'This page is not loading properly. '
// No app urls found - 'No apps found on this page. Try a different page or entering the package URL directly. You can also manually download the package then drop it on here. '
// 'Found # apps'
// Fetching / File Loading from drag and drop - 'Loading # apps'
// Unzipping, archive search and Parsing - 'Processing # of #'
// Not able to unzip - 'Unable to open package. Try a different file. '
// No Mach-o binary found - 'Could not find Mac App data in package. Try a different package. '
// Mach-o Parsing Error - 'Unable to scan package. Try a different one. '
// No ARM64 Architecture found - 'This App's binary is not compatible with Apple Silicon and will only run via Rosetta 2 translation, however, software vendors will sometimes will ship separate install files for Intel and ARM instead of a single one. You can try submitting the download page link for an app and we'll scan that. '
// ARM64 Architecture found -
return 'This App is natively compatible with Apple Silicon!'
}
// async scanPageForAppUrls () {
// }
// async downloadArchiveFromUrl () {
// }
async unzipFile ( file ) {
const fileReader = new zip.BlobReader( file.instance )//new FileReader()
fileReader.onload = function() {
// do something on FileReader onload
console.log('File Read')
file.statusMessage = '📖 Reading file'
}
fileReader.onerror = error => {
// do something on FileReader onload
console.error('File Read Error', error)
throw new Error('File Read Error', error)
}
fileReader.onprogress = (data) => {
if (data.lengthComputable) {
const progress = parseInt( ((data.loaded / data.total) * 100), 10 );
console.log('Read progress', progress)
file.statusMessage = `📖 Reading file. ${ progress }% read`
}
}
// console.log('fileReader', fileReader)
// https://gildas-lormeau.github.io/zip.js/core-api.html#zip-reading
const zipReader = new zip.ZipReader( fileReader )
// zipReader.onprogress = console.log
// zipReader.onerror = console.log
const entries = await zipReader.getEntries()
.then( entries => entries.map( entry => {
return entry
// return {
// filename: entry.filename,
// directory: entry.directory
// }
}) )
.catch( error => {
// console.warn('Unzip Error', error)
return error
})
// console.log('entries', entries)
if ( !Array.isArray(entries) ) {
file.statusMessage = '❔ Could not decompress file'
file.status = 'finished'
throw new Error('Could not decompress file')
// return new Error('Could not decompress file')
}
return entries
}
matchesMacho ( entry ) {
// Skip files that are deeper than 3 folders
if ( entry.filename.split('/').length > 4 ) return false
// Skip folders
if ( entry.filename.endsWith('/') ) return false
// `${ appName }.app/Contents/MacOS/${ appName }`
// Does this entry path match any of our wanted paths
return [
// `${ appName }.app/Contents/MacOS/${ appName }`
`.app/Contents/MacOS/`
].some( pathToMatch => {
return entry.filename.includes(pathToMatch)
})
}
matchesRootInfo ( entry ) {
// Skip files that are deeper than 2 folders
if ( entry.filename.split('/').length > 3 ) return false
// Skip folders
if ( entry.filename.endsWith('/') ) return false
// Does this entry path match any of our wanted paths
return [
// `zoom.us.app/Contents/Info.plist`
`.app/Contents/Info.plist`,
`.zip/Contents/Info.plist`
].some( pathToMatch => {
return entry.filename.endsWith(pathToMatch)
})
}
findEntries ( entries, matchersObject ) {
const matches = {}
// const matcherKeys = Object.keys( matchers )
// Create a new set to store found App Names
const appNamesInArchive = new Set()
// Search App Names in entries
entries.forEach( entry => {
// Look through filename parts
entry.filename.split('/').forEach( filenamePart => {
if ( filenamePart.includes('.app') ) {
const appName = filenamePart.split('.')[0]
appNamesInArchive.add( appName )
}
} )
for ( const key in matchersObject ) {
// Deos it match the matcher method
const entryMatches = matchersObject[key]( entry )
if ( entryMatches ) {
// If we haven't set up an array for this key
// then create one
if ( !Array.isArray(matches[key]) ) matches[key] = []
// Push this entry to our matching list
matches[key].push( entry )
}
}
} )
return matches
}
async parseMachOBlob ( machOBlob, fileName ) {
const machOFile = new File([machOBlob], fileName)
return await parseMacho( machOFile )
}
getBundleExecutablePath ( info ) {
if ( info.CFBundleExecutable.includes('/') ) return `/Contents/${ info.CFBundleExecutable }`
return `/Contents/MacOS/${ info.CFBundleExecutable }`
}
classifyBinaryEntryArchitecture ( binaryEntry ) {
// Find an ARM Architecture
const armArchitecture = binaryEntry.architectures.find( architecture => {
// if ( architecture.processorType === 0 ) return false
// If processorType not a string
// then return false
if ( !isString(architecture.processorType) ) return false
return architecture.processorType.toLowerCase().includes('arm')
})
// Was an ARM Architecture found
return (armArchitecture !== undefined)
}
async submitScanInfo ({
filename,
appVersion,
result,
machoMeta,
infoPlist
}) {
// Each file scanned: Filename, Type(Drop or URL), File URL, Datetime, Architectures, Mach-o Meta
// console.log( 'this.testResultStore', this.testResultStore )
const { supportedVersionNumber } = await axios.post( this.testResultStore , {
filename,
appVersion,
result,
machoMeta: JSON.stringify( machoMeta ),
infoPlist: JSON.stringify( infoPlist )
})
.then( response => response.data )
.catch(function (error) {
console.error(error)
})
return {
supportedVersionNumber
}
}
async scanFile ( file, scanIndex ) {
// If we've already scanned this
// then skip
if ( file.status === 'finished' ) return
if ( !this.isApp( file ) ) {
file.statusMessage = '⏭ Skipped. Not app or archive'
file.status = 'finished'
return
}
// console.log('file', file)
await new Promise(r => setTimeout(r, 1500 * scanIndex))
file.statusMessage = '🗃 Decompressing file'
console.log(`Decompressing file at ${ file.size }`)
let entries
try {
entries = await this.unzipFile( file )
} catch ( Error ) {
// console.warn( Error )
this.submitScanInfo ({
filename: file.name,
appVersion: null,
result: 'error_decompression_error',
machoMeta: null,
infoPlist: null
})
// Set status message as error
file.statusMessage = `${ Error.message }`
file.status = 'finished'
return
}
file.statusMessage = '👀 Scanning App Files'
console.log(`Searching entries`)
const foundEntries = this.findEntries( entries, {
macho: this.matchesMacho,
rootInfo: this.matchesRootInfo
})
// Clean out entries now that we're done with them
entries = undefined
// console.log('foundEntries', foundEntries)
// file.machOEntries = this.findMachOEntries( entries )
file.machOEntries = foundEntries.macho
// If no Macho files were found
// then report and stop
if ( file.machOEntries.length === 0 ) {
console.log(`No Macho files found for ${file.name}`, file.machOEntries)
this.submitScanInfo ({
filename: file.name,
appVersion: null,
result: 'error_no_macho_files',
machoMeta: null,
infoPlist: null
})
file.statusMessage = `❔ Unkown app format`
file.status = 'finished'
return
}
// Warn if Info.plist doesn't look right
if ( foundEntries.rootInfo.length > 1) {
console.warn('More than one root Info.plist found', foundEntries.rootInfo)
} else if ( foundEntries.rootInfo.length === 0 ) {
console.warn('No root Info.plist found', foundEntries.rootInfo)
}
// Break out root entry into a variable
const [ rootInfoEntry ] = foundEntries.rootInfo
// Get blob data from zip
// https://gildas-lormeau.github.io/zip.js/core-api.html#zip-entry
const infoXml = await rootInfoEntry.getData(
// writer
// https://gildas-lormeau.github.io/zip.js/core-api.html#zip-writing
new zip.TextWriter(),
// options
{
useWebWorkers: true,
// onprogress: (index, max) => {
// const percentageNumber = (index / max * 100)
// // onprogress callback
// console.log(`Writer progress ${percentageNumber}`)
// }
}
)
// Parse the Info.plist data
const info = plist.parse( infoXml )
file.appVersion = info.CFBundleShortVersionString
file.displayName = info.CFBundleDisplayName
// Set details
const detailsData = [
[ 'Version', info.CFBundleShortVersionString ],
[ 'Bundle Identifier', info.CFBundleIdentifier ],
[ 'File Mime Type', file.type ],
[ 'Copyright', info.NSHumanReadableCopyright ],
// [ 'Version', info.CFBundleShortVersionString ],
]
detailsData.forEach( ([ label, value ]) => {
if ( !value || value.length === 0 ) return
file.details.push({
label,
value,
})
} )
// console.log('infoFiles', file.name, {
// path: rootInfoEntry.filename,
// info
// })
console.log(`Parsing Macho ${ file.machOEntries.length } files`)
// console.log('info.CFBundleExecutable', info.CFBundleExecutable)
// console.log('info', info)
// console.log('file.machOEntries', file.machOEntries)
const bundelExecutablePath = this.getBundleExecutablePath( info )
const bundleExecutables = file.machOEntries.filter( machoEntry => {
return machoEntry.filename.includes(bundelExecutablePath)
})
// Warn if Bundle Executable doesn't look right
if ( bundleExecutables.length > 1) {
console.warn('More than one root bundleExecutable found', bundleExecutables)
} else if ( bundleExecutables.length === 0 ) {
console.warn('No root bundleExecutable found', bundleExecutables)
}
const [ bundleExecutable ] = bundleExecutables
console.log('Parsing ', bundleExecutable.filename, bundleExecutable.uncompressedSize / 1000 )
file.displayBinarySize = prettyBytes( bundleExecutable.uncompressedSize )
file.binarySize = bundleExecutable.uncompressedSize
// Get blob data from zip
// https://gildas-lormeau.github.io/zip.js/core-api.html#zip-entry
const bundleExecutableBlob = await bundleExecutable.getData(
// writer
// https://gildas-lormeau.github.io/zip.js/core-api.html#zip-writing
new zip.BlobWriter(),
// options
{
useWebWorkers: true
}
)
const mainExecutableMeta = await this.parseMachOBlob( bundleExecutableBlob, file.name )
console.log( 'mainExecutableMeta', mainExecutableMeta )
const binarySupportsNative = this.classifyBinaryEntryArchitecture( mainExecutableMeta )
// Submit the scan to get any reports on preexisting native reports
const { supportedVersionNumber } = await this.submitScanInfo ({
filename: file.name,
appVersion: file.appVersion,
result: binarySupportsNative ? '✅' : '🔶',
machoMeta: {
...mainExecutableMeta,
file: undefined,
architectures: mainExecutableMeta.architectures.map( architecture => {
return {
bits: architecture.bits,
fileType: architecture.fileType,
header: architecture.header,
loadCommandsInfo: architecture.loadCommandsInfo,
magic: architecture.magic,
offset: architecture.offset,
processorSubType: architecture.processorSubType,
processorType: architecture.processorType,
}
})
},
infoPlist: info
})
console.log('supportedVersionNumber', supportedVersionNumber)
let finishedStatusMessage = ''
if ( binarySupportsNative ) {
finishedStatusMessage = '✅ This app is natively compatible with Apple Silicon!'
// Shift this scan to the top
this.files.unshift( this.files.splice( scanIndex, 1 )[0] )
} else if ( supportedVersionNumber !== null ) {
finishedStatusMessage = [
'✅ A native version of this has been reported',
(supportedVersionNumber.length > 0) ? `as of v${supportedVersionNumber}` : null
].join(' ')
} else {
finishedStatusMessage = `🔶 This app file is not natively compatible with Apple Silicon and may only run via Rosetta 2 translation, however, software vendors will sometimes will ship separate install files for Intel and ARM instead of a single one. `
}
file.statusMessage = finishedStatusMessage
file.status = 'finished'
return
}
async scan ( fileList ) {
// Push files to our files array
Array.from(fileList).forEach( (fileInstance, scanIndex) => {
this.files.unshift( {
status: 'loaded',
displayName: null,
statusMessage: '⏳ File Loaded and Queud',
details: [],
appVersion: null,
displayAppSize: prettyBytes( fileInstance.size ),
displayBinarySize: null,
binarySize: null,
name: fileInstance.name,
size: fileInstance.size,
type: fileList.item( scanIndex ).type,
lastModifiedDate: fileInstance.lastModifiedDate,
instance: fileInstance,
item: fileList.item( scanIndex )
} )
})
const scanTimeoutSeconds = 30
// Scan for archives
await Promise.all( this.files.map( ( file, scanIndex ) => {
return new Promise( (resolve, reject) => {
const timer = setTimeout(() => {
file.statusMessage = '❔ Scan timed out'
file.status = 'finished'
reject(new Error('Scan timed out'))
}, scanTimeoutSeconds * 1000)
this.scanFile( file, scanIndex ).then(
response => resolve(response),
err => reject(new Error(err))
).finally(() => clearTimeout(timer))
})
}))
// Go through and set all files to finished to clean up any straglers
this.files.forEach( file => {
file.status = 'finished'
})
console.log('All Scans Finished')
return
}
}

4
helpers/macho/index.js Normal file
View file

@ -0,0 +1,4 @@
import MachoParser from './macho.js'
export default MachoParser

View file

@ -0,0 +1,13 @@
export let SECTION_ATTRIBUTES_USR = 0xff000000;
export let S_ATTR_PURE_INSTRUCTIONS = 0x80000000;
export let SECTION_ATTRIBUTES_SYS = 0x00ffff00;
export let S_ATTR_SOME_INSTRUCTIONS = 0x0000400;
export let S_ATTR_EXT_RELOC = 0x00000200;
export let S_ATTR_LOC_RELOC = 0x00000100;
export let uint128_t = 16;
export let uint64_t = 8;
export let uint32_t = 4;
export let uint16_t = 2;
export let uint8_t = 1;

134
helpers/macho/macho.cpu.js Normal file
View file

@ -0,0 +1,134 @@
//Global Constants
var CPU_TYPES = [];
var CPUSubTypeARM = [];
let CPU_ARCH_CONST = {
MASK: 0x01000000,
ABI64: 0xff000000,
toString: function() {
JSON.stringify(this);
}
};
let CPU_TYPE = {
ANY: -1,
VAX: 1,
MC680: 6,
X86: 7,
MIPS: 8,
MC98000: 10,
HPPA: 11,
ARM: 12,
ARM64: 16777228,
MC88000: 13,
SPARC: 14,
I860: 15,
POWERPC: 18,
POWERPC64: 16777234,
DESCRIPTION: function(search) {
let result = CPU_TYPES[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
};
CPU_TYPES[CPU_TYPE.ANY] = "Any";
CPU_TYPES[CPU_TYPE.VAX] = "VAX";
CPU_TYPES[CPU_TYPE.MC680] = "MC680";
CPU_TYPE[CPU_TYPE.HPPA] = "HPPA";
CPU_TYPES[CPU_TYPE.ARM] = "ARM";
CPU_TYPES[CPU_TYPE.ARM64] = "ARM64";
CPU_TYPES[CPU_TYPE.X86] = "X86";
CPU_TYPES[CPU_TYPE.I860] = "I860";
CPU_TYPES[CPU_TYPE.MIPS] = "Mips";
CPU_TYPES[CPU_TYPE.MC98000] = "MC98000";
CPU_TYPES[CPU_TYPE.SPARC] = "Sparc";
CPU_TYPES[CPU_TYPE.POWERPC] = "Power PC";
CPU_TYPES[CPU_TYPE.POWERPC64] = "Power PC 64-bit";
let CPU_SUB_TYPE = {
ARM: {
MULTIPLE: -1,
ALL: 0,
ARM_A500_ARCH: 1,
ARM_A500: 2,
ARM_A440: 3,
ARM_M4: 4,
V4T: 5,
V6: 6,
V5TEJ: 7,
XSCALE: 8,
V7: 9,
V7F: 10,
V7S: 11,
V7K: 12,
V8: 13,
V6M: 14,
V7M: 15,
V7EM: 16,
DESCRIPTION: function(search) {
let result = CPUSubTypeARM[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
},
ARM64: {
MULTIPLE: -1,
ALL: 0,
V8: 1,
DESCRIPTION: function(search) {
var CPUSubTypeARM64 = [];
CPUSubTypeARM64[CPU_SUB_TYPE.ARM64.ALL] = 'all';
let result = CPUSubTypeARM64[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
},
POWERPC64: {
MULTIPLE: -1,
POWERPC_ALL: 0,
POWERPC_601: 1,
POWERPC_602: 2,
POWERPC_603: 3,
POWERPC_603e: 4,
POWERPC_603ev: 5,
POWERPC_604: 6,
POWERPC_604e: 7,
POWERPC_620: 8,
POWERPC_750: 9,
POWERPC_7400: 10,
POWERPC_7450: 11,
POWERPC_970: 100,
POWERPC_ALL_LIB64: 2147483648,
toString: function() {
return JSON.stringify(this);
}
},
toString: function() {
return JSON.stringify(this);
}
};
CPUSubTypeARM[CPU_SUB_TYPE.ARM.ALL] = 'all';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V4T] = 'v4t';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V6] = 'v6';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V5] = 'v5';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.XSCALE] = 'xscale';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7] = 'v7';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7F] = 'v7f';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7S] = 'v7s';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7K] = 'v7k';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V6M] = 'v6m';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7M] = 'v7m';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7EM] = 'v7em';
export { CPU_TYPES, CPUSubTypeARM, CPU_ARCH_CONST, CPU_TYPE, CPU_SUB_TYPE }

View file

@ -0,0 +1,12 @@
var Cstr = function Cstr(buf) {
this.toString = function() {
return JSON.stringify(this);
};
var cstr = '';
for(var i = 0; i < buf.length; i++) {
cstr += String.fromCharCode(buf[i]);
}
return cstr;
};
export default Cstr

View file

@ -0,0 +1,72 @@
var Dylib = function Dylib(name, timestamp, current_version, compatibility_version) {
this.name = name || 0x00000000;
this.timestamp = timestamp || 0x00000000;
this.current_version = current_version || 0x00000000;
this.compatibility_version = compatibility_version || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var DylibCommand = function DylibCommand(cmd, cmdsize, dylib) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.dylib = dylib || new Dylib(); //needs better input validation
this.toString = function() {
return JSON.stringify(this);
};
};
var DylibTableOfContents = function DylibTableOfContents(symbol_index, module_index) {
this.symbol_index = symbol_index || 0x00000000;
this.module_index = module_index || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var DylibModule = function DylibModule(module_name, iextdefsym, nextdefsym, irefsym, nrefsym, ilocalsym, nlocalsym, iextrel, nextrel, iinit_iterm, ninit_nterm, objc_module_info_addr, objc_module_info_size) {
this.module_name = module_name || 0x00000000;
this.iextdefsym = iextdefsym || 0x00000000;
this.nextdefsym = nextdefsym || 0x00000000;
this.irefsym = irefsym || 0x00000000;
this.nrefsym = nrefsym || 0x00000000;
this.ilocalsym = ilocalsym || 0x00000000;
this.nlocalsym = nlocalsym || 0x00000000;
this.iextrel = iextrel || 0x00000000;
this.nextrel = nextrel || 0x00000000;
this.iinit_iterm = iinit_iterm || 0x00000000;
this.ninit_nterm = ninit_nterm || 0x00000000;
this.objc_module_info_addr = objc_module_info_addr || 0x00000000;
this.objc_module_info_size = objc_module_info_size || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var DylibModule64 = function DylibModule64(module_name, iextdefsym, nextdefsym, irefsym, nrefsym, ilocalsym, nlocalsym, iextrel, nextrel, iinit_iterm, ninit_nterm, objc_module_info_addr, objc_module_info_size) {
this.module_name = module_name || 0x00000000;
this.iextdefsym = iextdefsym || 0x00000000;
this.nextdefsym = nextdefsym || 0x00000000;
this.irefsym = irefsym || 0x00000000;
this.nrefsym = nrefsym || 0x00000000;
this.ilocalsym = ilocalsym || 0x00000000;
this.nlocalsym = nlocalsym || 0x00000000;
this.iextrel = iextrel || 0x00000000;
this.nextrel = nextrel || 0x00000000;
this.iinit_iterm = iinit_iterm || 0x00000000;
this.ninit_nterm = ninit_nterm || 0x00000000;
this.objc_module_info_addr = objc_module_info_addr || 0x00000000;
this.objc_module_info_size = objc_module_info_size || 0x0000000000000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var DylibReference = {
isym:24,
flags:8,
toString: function() {
return JSON.stringify(this);
}
};

View file

@ -0,0 +1,7 @@
var DylinkerCommand = function DylinkerCommand(cmd, cmdsize) {
this.cmd = 0x00000000;
this.cmdsize = 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,73 @@
var FILE_TYPES = [];
var FILE_FLAGS = [];
/*
@Class FILE_TYPE
@Description
File Type is the class for identifying what MACH-O file is being dealed with.
*/
let FILE_TYPE = {
MH_OBJECT: 0x1, /* relocatable object file */
MH_EXECUTE: 0x2, /* demand paged executable file */
MH_FVMLIB: 0x3, /* fixed VM shared library file */
MH_CORE: 0x4, /* core file */
MH_PRELOAD: 0x5, /* preloaded executable file */
MH_DYLIB: 0x6, /* dynamicly bound shared library file*/
MH_DYLINKER: 0x7, /* dynamic link editor */
MH_BUNDLE: 0x8, /* dynamicly bound bundle file */
MH_DYLIB_STUB: 0x9,
MH_DSYM: 0xa,
MH_KEXT_BUNDLE: 0xb,
DESCRIPTION: function(search) {
let result = FILE_TYPES[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
},
debugdescription: ""
};
FILE_TYPES[FILE_TYPE.MH_OBJECT] = 'Relocatable Object File';
FILE_TYPES[FILE_TYPE.MH_EXECUTE] = 'Demand Paged Executable File';
FILE_TYPES[FILE_TYPE.MH_FVMLIB] = 'Fixed Virtual Memory Shared Library File';
FILE_TYPES[FILE_TYPE.MH_CORE] = 'Core File';
FILE_TYPES[FILE_TYPE.MH_PRELOAD] = 'Preloaded Executable File';
FILE_TYPES[FILE_TYPE.MH_DYLIB] = 'Dynamically Bound Shared Library File';
FILE_TYPES[FILE_TYPE.MH_DYLINKER] = 'Dynamic Link Editor';
FILE_TYPES[FILE_TYPE.MH_BUNDLE] = 'Dynamically Bound Bundle File';
FILE_TYPES[FILE_TYPE.MH_DYLIB_STUB] = 'Dynamic Library Predefined Symbol';
FILE_TYPES[FILE_TYPE.MH_DSYM] = 'Dynamic Symbol';
FILE_TYPES[FILE_TYPE.MH_KEXT_BUNDLE] = 'Kernel Extension Bundle';
let FILE_FLAG = {
MH_NOUNDEFS: 0x1, /* the object file has no undefined references, can be executed */
MH_INCRLINK: 0x2, /* the object file is the output of an incremental link against a base file and can't be link edited again */
MH_DYLDLINK: 0x4, /* the object file is input for the dynamic linker and can't be staticly link edited again */
MH_BINDATLOAD: 0x8, /* the object file's undefined references are bound by the dynamic linker when loaded. */
MH_PREBOUND: 0x10, /* the file has it's dynamic undefined references prebound. */
DESCRIPTION: function(search) {
let result = FILE_FLAGS[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
};
FILE_FLAGS[FILE_FLAG.MH_NOUNDEFS] = 'The object file has no undefined references and is executable.';
FILE_FLAGS[FILE_FLAG.MH_INCRLINK] = 'The object file is the output of an incremental link against a base file and can not be link edited again.';
FILE_FLAGS[FILE_FLAG.MH_DYLDLINK] = 'The object file is the input for the dynamic linker and can not be staticly link edited again.';
FILE_FLAGS[FILE_FLAG.MH_BINDATLOAD] = 'The object file\'s undefined references are bound by the dynamic linker when loaded.';
FILE_FLAGS[FILE_FLAG.MH_PREBOUND] = 'The file has it\'s dynamic undefined references prebound.';
export { FILE_TYPES, FILE_FLAGS, FILE_TYPE, FILE_FLAG }

View file

@ -0,0 +1,31 @@
let FLAGS = {
NOUNDEFS: 1,
INCRLINK: 2,
DYLDLINK: 4,
BINDATLOAD: 8,
PREBOUND: 16,
SPLIT_SEGS: 32,
LAZY_INIT: 64,
TWOLEVEL: 128,
FORCE_FLAT: 256,
NOMULTIDEFS: 512,
NOFIXPREBINDING: 1024,
PREBINDABLE: 2048,
ALLMODSBOUND: 4096,
SUBSECTIONS_VIA_SYMBOLS: 8192,
CANONICAL: 32768,
WEAK_DEFINES: 32768,
BINDS_TO_WEAK: 65536,
ALLOW_STACK_EXECUTION: 131072,
ROOT_SAFE: 262144,
SETUID_SAFE: 524288,
NOREEXPORTED_DYLIBS: 1048576,
PIE: 2097152,
DEAD_STRIPPABLE_DYLIB: 4194304,
HAS_TLV_DESCRIPTORS: 8388608,
NO_HEAP_EXECUTION: 16777216,
APP_EXTENSION_SAFE: 33554432
toString: function(){
return JSON.stringify(this);
}
};

View file

@ -0,0 +1,17 @@
var Fvmlib = function Fvmlib(name, minor_version, header_addr) {
this.name = name || 0x00000000;
this.minor_version = minor_version || 0x00000000;
this.header_addr = header_addr || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var FvmlibCommand = function FvmlibCommand(cmd, cmdsize, fvmlib) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.fvmlib = fvmlib || new Fvmlib(); //needs better input validation
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,49 @@
//Mach-O Fat file header
export var FatHeader = function FatHeader() {
this.magic = 0x00000000;
this.nfat_arch = 0x00000000;
this.toString = function() {
return JSON.stringify(this);
}
};
//Mach-O Fat file header
export var FatArch = function FatArch() {
this.cputype = 0x00000000;
this.cpusubtype = 0x00000000;
this.offset = 0x00000000;
this.size = 0x00000000;
this.align = 0x00000000;
this.toString = function() {
return JSON.stringify(this);
}
}
//Mach-O Binary Executable header 32-bit
export var MachoHeader = function MachoHeader() {
this.magic = 0x00000000;
this.cputype = 0x00000000;
this.cpusubtype = 0x00000000;
this.filetype = 0x00000000;
this.ncmds = 0x00000000;
this.sizeofcmds = 0x00000000;
this.flags = 0x00000000;
this.toString = function() {
return JSON.stringify(this);
}
};
//Mach-O Binary Executable header 64-bit
export var MachoHeader64 = function MachoHeader64() {
this.magic = 0x00000000;
this.cputype = 0x00000000;
this.cpusubtype = 0x00000000;
this.filetype = 0x00000000;
this.ncmds = 0x00000000;
this.sizeofcmds = 0x00000000;
this.flags = 0x00000000;
this.reserved = 0x00000000;
this.toString = function() {
return JSON.stringify(this);
}
};

317
helpers/macho/macho.js Normal file
View file

@ -0,0 +1,317 @@
//macho.js
//Written by Sem Voigtländer
//Licensed under the MIT License
import { mime_binary } from './mimetypes.js'
import { ReadUint32, ReadUint16LE, ReadUint32LE, ReadUint16 } from './memory.js'
import { uint32_t, uint64_t } from './macho.constants.js'
import { MAGIC } from './macho.magic.js'
import { MachoHeader64, MachoHeader } from './macho.header.js'
import { LOAD_COMMAND_TYPE, LoadCommand } from './macho.loadcommand.js'
import { CPU_TYPE, CPU_SUB_TYPE } from './macho.cpu.js'
import { FILE_FLAGS, FILE_TYPE } from './macho.file.js'
import Cstr from './macho.cstr.js'
import { SegmentCommand } from './macho.segment.js'
function default_callback(buffer) {
console.log('Received ' + buffer.byteLength / (1024 * 1024) + ' MB');
}
// https://stackoverflow.com/a/57139182/1397641
async function arrayBufferToBlob( buffer ) {
return new Blob([buffer])
}
let readers = []
let tempFile
let tempFiles
var ChunkReader = function ChunkReader(file, chunksize = (1024 * 1024), callback = default_callback) {
if(file == undefined) {
throw new Error('Invalid argument for file parameter.');
}
if(readers == undefined) { readers = []; } //Free list
this.chunksize = chunksize; //Read a kilobyte at a time
this.filesize = file.size;
this.offset = 0;
//Start reading the chunks
while(this.offset + this.chunksize <= this.filesize) {
this.blob = file.slice(this.offset, this.offset+this.chunksize);
readers[readers.length] = new FileReader();
readers[readers.length-1].onloadend = function(e) {
callback(e.target.result);
};
readers[readers.length-1].readAsArrayBuffer(this.blob);
// console.log('Sending chunk from 0x'+this.offset.toString(16));
this.offset+=this.chunksize;
}
for(obj = 0; obj < readers.length; obj++) {
readers[obj] = undefined;
}
// Clean up readers
readers = undefined
// free("readers");
};
export function MachoParser(file, callback) {
const machoOutputData = {}
//properties
this.reader = new FileReader();
function writeToCallback(val) {
return
// if(callbackElement) {
// callbackElement.innerHTML +='<tr>'+val+'</tr>';
// } else {
// throw new Error('Invalid callback.');
// }
}
/*
@Function FindMagic
@Params (Uint8Array) buffer, (bool) breakwhenfound
@Return (Array) offsets of found magics
*/
function FindMagic(data, breakwhenfound = false) {
var results = [];
for(var byte = 0; byte < (data.length - uint32_t); byte++) { //Read 32-bits at a time until the end of the buffer
var magic = ReadUint32(data, byte); //Read the next 32-bit magic value
if(MAGIC.VALIDATE(magic)) {
results.push(byte);
if(breakwhenfound) {
break;
}
}
}
return results;
}
/*
@Function MapFlags
@Params (Uint8Array)flags, (Object)map
@Return (Object) key-value mapped dictionary
*/
function MapFlags(value, map) {
var res = {};
for (var bit = 1; (value < 0 || bit <= value) && bit !== 0; bit <<= 1)
if (value & bit) res[map[bit]] = true; //If value and the bit are equal then map the value to the result
return res;
}
function ParseCommand(type, data, size, off) {
var cmd = null;
if(type == LOAD_COMMAND_TYPE.LC_SEGMENT) {
if(data.length < 48) {
if(process.env.VERBOSE){ console.log('Segment command OOB'); }
return new LoadCommand(type, data, size, off);
}
let name = new Cstr(data.slice(0, (4*uint32_t)));
cmd = new SegmentCommand(
type,
size,
name,
ReadUint32(data, (4*uint32_t)),
ReadUint32(data, (5*uint32_t)),
ReadUint32(data, (6*uint32_t)),
ReadUint32(data, (7*uint32_t)),
ReadUint32(data, (8*uint32_t)),
ReadUint32(data, (9*uint32_t)),
ReadUint32(data, (10*uint32_t)),
ReadUint32(data, (11*uint32_t))
);
function prot(p) {
var res = {read: false, write: false, exec: false};
return res;
}
let sectSize = 17 * uint32_t;
var sections = [];
//for(var i = 0, off = 48; i < nsects)
return cmd;
} else {
return new LoadCommand(type, data, size, off);
}
}
this.reader.onloadend = function(e) {
let fileType = mime_binary;
//Handle the file buffer and eventually create a Blob of the result
// blobUtil.
arrayBufferToBlob(e.target.result, fileType).then(function(blob) {
let filesize = ((blob.size / 1024) / 1024); //Calculate FileSize in Megabyte
tempFile = blob;
//Set up the file and print out for verbosity
machoOutputData.file = file
machoOutputData.fileSize = filesize
machoOutputData.architectures = []
// writeToCallback('<td><strong>File</strong></td><td>'+file.name.toString()+'</td>');
// writeToCallback('<td><strong>Size</strong></td><td>' + filesize.toFixed(2).toString() + 'MB</td>');
//Construct a new 8-bit array from the file buffer
let data = new Uint8Array(e.target.result);
let magics = FindMagic(data, false); //Try to find all Mach-O magics in the byte array
if ( process.env.DEBUG ) { console.log('Parsing all magics...'); }
//If magics where found, parse the binary.
if(magics.length > 0) {
for(var cMagic = 0; cMagic < magics.length; cMagic++) { //Start parsing the binary from each found magic's offset
const architecture = {}
let magicOff = magics[cMagic]; //The offset of the magic currently being parsed
let magic = ReadUint32(data, magicOff); //Read the magic from the byte array
let littleendian = MAGIC.ISLITTLEENDIAN(magic); //Get the endianness of the magic
let x64 = MAGIC.IS64BIT(magic); //Check which bit architecture is being used
// machoOutputData = {}; //Create the Mach-O information object
architecture.bits = (x64 ? "64-bit" : "32-bit"); //Get the architecture
architecture.endianness = (littleendian ? "little endian" : "big endian"); //Get the endianness
architecture.header = (x64 ? new MachoHeader64() : new MachoHeader()); //Depending on architecture, construct a new header
architecture.header.magic = magic; //Add the magic to the header
architecture.header.cputype = (littleendian ? ReadUint16LE(data, magicOff+uint32_t) : ReadUint16(data, magicOff+uint32_t)); //Read the cputype which comes after the magic
architecture.header.cpusubtype = (littleendian ? ReadUint16LE(data, magicOff+(2*uint32_t)) : ReadUint16(data, magicOff+(2*uint32_t))); //Read the cpu subtype which comes after the cputype
architecture.header.filetype = (littleendian ? ReadUint32LE(data, magicOff+(3*uint32_t)) : ReadUint32(data, magicOff+(3*uint32_t))); //Read the file type which comes after the cpu subtype
architecture.header.ncmds = (littleendian ? ReadUint32LE(data, magicOff+(4*uint32_t)) : ReadUint32(data, magicOff+(4*uint32_t))); //Read the number of commands which comes after the filetype
architecture.header.sizeofcmds =(littleendian ? ReadUint32LE(data, magicOff+(5*uint32_t)) : ReadUint32(data, magicOff+(5*uint32_t))); //Read the size of the commands which comes after the number of commands
architecture.header.flags = (littleendian ? ReadUint32LE(data, magicOff+(6*uint32_t)) : ReadUint32(data, magicOff+(6*uint32_t))); //Read the flags which come after the size of the commands
architecture.loadcommands = [];
var align = (x64 ? uint64_t : uint32_t); //Depending on our architecture set an align for parsing the load commands
for(var i = 0, off = magicOff; off < data.length, i < architecture.header.ncmds; i++) {
var curr_cmd = {};
curr_cmd.cmd = (littleendian ? ReadUint32LE(data, off) : ReadUint32(data, off)); //Read the command type from the offset
curr_cmd.cmdsize = (littleendian ? ReadUint32LE(data, off+align) : ReadUint32(data, off+align)); //Read the size of the command from the offset
curr_cmd.fileoff = off; //Add the offset of the loadcommand for later use
curr_cmd.data = data.slice(off, curr_cmd.cmdsize);
curr_cmd = ParseCommand(curr_cmd.cmd, curr_cmd.data, curr_cmd.cmdsize, curr_cmd.fileoff);
if(curr_cmd.cmdsize > 0) { //Commands with a size of zero are not valid or not interesting
architecture.loadcommands.push(curr_cmd);
}
off+=8;
i++; //Increate the loadcommand counter
}
architecture.offset = magicOff.toString(16)
architecture.magic = architecture.header.magic.toString(16)
architecture.processorType = CPU_TYPE.DESCRIPTION(architecture.header.cputype)
architecture.processorSubType = CPU_SUB_TYPE.ARM.DESCRIPTION(architecture.header.cpusubtype)
architecture.fileType = FILE_TYPE.DESCRIPTION(architecture.header.filetype)
/* Parse all collected information to Human Readable strings */
// writeToCallback('');
// writeToCallback('<td><strong>Header</strong></td>');
// writeToCallback('<td><strong>Offset</strong></td><td>0x'+magicOff.toString(16)+'</td>');
// writeToCallback('<td><strong>Magic</strong></td><td>0x'+architecture.header.magic.toString(16)+'</td>');
// writeToCallback('<td><strong>Bits</strong></td><td>'+architecture.bits+'</td>');
// writeToCallback('<td><strong>Endianness</strong></td><td>'+architecture.endianness+'</td>');
// writeToCallback('<td><strong>Processor type</strong></td><td>' + CPU_TYPE.DESCRIPTION(architecture.header.cputype)+'</td>');
// writeToCallback('<td><strong>Processor subtype</strong></td><td>'+ CPU_SUB_TYPE.ARM.DESCRIPTION(architecture.header.cpusubtype)+'</td>');
// writeToCallback('<td><strong>File type</strong></td><td>'+FILE_TYPE.DESCRIPTION(architecture.header.filetype)+'</td>');
// writeToCallback('<td><strong>Number of commands</strong></td><td>'+architecture.header.ncmds+'</td>');
// writeToCallback('<td><strong>Size of commands</strong></td><td>'+architecture.header.sizeofcmds+'</td>');
architecture.header.flags = MapFlags(architecture.header.flags, FILE_FLAGS);
architecture.header.flags = Object.keys(architecture.header.flags).map(function(k) { if(k){return k}});
// writeToCallback('<td><strong>Flags</strong></td><td>'+architecture.header.flags.toString().replace(',','<br>').replace(',','<br>')+"</td>");
// writeToCallback('');
// writeToCallback('<td><strong>Load Command</strong></td><td><strong>Size</strong></td><td><strong>Offset</strong></td>');
architecture.loadCommandsInfo = []
for(var curr_lc = 0; curr_lc < architecture.loadcommands.length; curr_lc++) {
architecture.loadCommandsInfo.push({
description: LOAD_COMMAND_TYPE.DESCRIPTION(architecture.loadcommands[curr_lc].cmd),
size: architecture.loadcommands[curr_lc].cmdsize,
offset: ` 0x${architecture.loadcommands[curr_lc].fileoff.toString(16)}`
})
// writeToCallback(
// '<td>'+
// LOAD_COMMAND_TYPE.DESCRIPTION(architecture.loadcommands[curr_lc].cmd) +
// '</td>'+
// '<td>'+
// architecture.loadcommands[curr_lc].cmdsize+
// '</td>'+
// '<td>'+
// ' 0x' + architecture.loadcommands[curr_lc].fileoff.toString(16) +
// '</td>');
}
magicOff = null;
littleendian = null;
x64 = null;
// blobUtil.
arrayBufferToBlob(data.buffer, fileType).then(function(blob){
if(!tempFiles) { tempFiles = []; }
tempFiles[tempFiles.length] = blob;
}).catch(console.log.bind(console));
machoOutputData.architectures.push( architecture )
}
callback( machoOutputData )
// console.log('The parser has finished')
} else { //(magics.length <= 0) (If we end up here it means no magics were found in the file).
// writeToCallback('This is not a valid Mach-O file.');
throw new Error('This is not a valid Mach-O file.')
}
}).catch(console.log.bind(console));
};
this.reader.readAsArrayBuffer(file);
// console.log('Parsing, please wait...');
};
export default async function ( file ) {
return new Promise( ( resolve, reject ) => {
try {
(new MachoParser( file, resolve ))
} catch ( error ) {
reject( error )
}
} )
}

View file

@ -0,0 +1,9 @@
var LinkeditDataCommand = function LinkeditDataCommand(cmd, cmdsize, dataoff, datasize) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.dataoff = dataoff || 0x00000000;
this.datasize = datasize || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,133 @@
//Global Constants
var LOAD_COMMAND_TYPES = [];
/*
@Class LoadCommand
@Description
*/
let LOAD_COMMAND_TYPE = {
LC_UNKNOWN: 0,
LC_SEGMENT: 1,
LC_SYMTAB: 2, //Symbol table
LC_SYMSEG: 3, //Segment
LC_THREAD: 4,
LC_UNIXTHREAD: 5,
LC_LOADFVMLIB: 6, /* load a specified fixed VM shared library */
LC_IDFVMLIB: 7, /* fixed VM shared library identification */
LC_IDENT: 8, /* object identification info (obsolete) */
LC_FVMFILE: 9, /* fixed VM file inclusion (internal use) */
LC_PREPAGE: 10, /* prepage command (internal use) */
LC_DYSYMTAB: 11, /* dynamic link-edit symbol table info */
LC_LOAD_DYLIB: 12, /* load a dynamicly linked shared library */
LC_ID_DYLIB: 13, /* dynamicly linked shared lib identification */
LC_LOAD_DYLINKER: 14, /* load a dynamic linker */
LC_ID_DYLINKER: 15,
LC_PREBOUND_DYLIB: 16, /* modules prebound for a dynamicly */
LC_ROUTINES: 17,
LC_SUB_FRAMEWORK: 18,
LC_SUB_UMBRELLA: 19,
LC_SUB_CLIENT: 20,
LC_SUB_LIBRARY: 21,
LC_TWOLEVEL_HINTS: 22,
LC_PREBIND_CKSUM: 23,
LC_SEGMENT_64: 25,
LC_ROUTINES_64: 26,
LC_UUID: 27,
LC_CODE_SIGNATURE: 29,
LC_SEGMENT_SPLIT_INFO: 30,
LC_LAZY_LOAD_DYLIB: 32,
LC_ENCRYPTION_INFO: 33,
LC_DYLD_INFO: 34,
LC_VERSION_MIN_MACOSX: 36,
LC_VERSION_MIN_IPHONEOS: 37,
LC_FUNCTION_STARTS: 38,
LC_DYLD_ENVIRONMENT: 39,
LC_DATA_IN_CODE: 41,
LC_SOURCE_VERSION: 42,
LC_DYLIB_CODE_SIGN_DRS: 43,
LC_ENCRYPTION_INFO_64: 44,
LC_LINKER_OPTION: 45,
LC_LINKER_OPTIMIZATION_HINT: 46,
LC_VERSION_MIN_TVOS: 47,
LC_VERSION_MIN_WATCHOS: 48,
LC_NOTE: 49,
LC_BUILD_VERSION: 50,
LC_LOAD_WEAK_DYLIB: 2147483672,
LC_RPATH: 2147483676,
LC_REEXPORT_DYLIB: 2147483679,
LC_DYLD_INFO_ONLY: 2147483682,
LC_LOAD_UPWARD_DYLIB: 2147483683,
LC_MAIN: 2147483688,
DESCRIPTION: function(search) {
let result = LOAD_COMMAND_TYPES[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
};
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SEGMENT] = '32-bits Segment command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SYMTAB] = 'Symbol table command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SYMSEG] = 'Symbol segment command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_THREAD] = 'Thread command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_UNIXTHREAD] = 'UNIX Thread command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LOADFVMLIB] = 'Fixed Virtual Memory Library Load command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_IDFVMLIB] = 'Fixed Virtual Memory Library identification information command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_IDENT] = 'Object identification information command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_FVMFILE] = 'Fixed VM File inclusion commmand';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_PREPAGE] = 'Prepage command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DYSYMTAB] = 'Dynamic Link-Edit Symbol Table information command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LOAD_DYLIB] = 'Dynamically linked shared library identification command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ID_DYLIB] = 'Dynamic Library Identifier';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LOAD_DYLINKER] = 'Dynamic Linker Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ID_DYLINKER] = 'Dynamic Linker Identifier';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_PREBOUND_DYLIB] = 'Prebound Dynamic Library Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ROUTINES] = 'Routines Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SUB_FRAMEWORK] = 'Sub Framework Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SUB_UMBRELLA] = 'Sub Umbrella Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SUB_CLIENT] = 'Sub Client Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SUB_LIBRARY] = 'Sub Library Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_TWOLEVEL_HINTS] = 'TwoLevel Hints Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_PREBIND_CKSUM] = 'Prebind Checksum Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SEGMENT_64] = '64-bits Segment Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ROUTINES_64] = '64-bits Routines Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_UUID] = 'UUID Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_CODE_SIGNATURE] = 'Code Signature';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SEGMENT_SPLIT_INFO] = 'Segment Split Information Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LAZY_LOAD_DYLIB] = 'Lazy Dynamic Library Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ENCRYPTION_INFO] = '32-bits encryption Information';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DYLD_INFO] = 'Dynamic Loader Information Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_VERSION_MIN_MACOSX] = 'Minimum Version Requirement Command for OSX';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_VERSION_MIN_IPHONEOS] = 'Minimum Version Requirement Command for iPhone';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_FUNCTION_STARTS] = 'Function Starts Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DYLD_ENVIRONMENT] = 'Dynamic Loader Environment Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DATA_IN_CODE] = 'Data In Code Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SOURCE_VERSION] = 'Source Version Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DYLIB_CODE_SIGN_DRS] = 'Dynamic Library Code Sign Directories Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ENCRYPTION_INFO_64] = '64-bits Encryption Information';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LINKER_OPTION] = 'Linker Option Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LINKER_OPTIMIZATION_HINT] = 'Linker Optimization Hint';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_VERSION_MIN_TVOS] = 'Minimum Version Requirement Command for tvOS';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_VERSION_MIN_WATCHOS] = 'Minimum Version Requirement Command for watchOS';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_NOTE] = 'Additional Note';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_BUILD_VERSION] = 'Build Version';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LOAD_WEAK_DYLIB] = 'Weak Dynamic Library Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_RPATH] = 'Executable Path';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_REEXPORT_DYLIB] = 'Re-Exported Dynamic Library Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DYLD_INFO_ONLY] = 'Dynamic Library Loader Information Only';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LOAD_UPWARD_DYLIB] = 'Upward Dynamic Library Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_MAIN] = 'Main Entrypoint';
var LoadCommand = function LoadCommand(type, data, size, fileoff) {
this.cmd = type || 0;
this.cmdsize = size || 0;
this.data = data || new Uint8Array();
this.fileoff = fileoff || 0;
};
export { LOAD_COMMAND_TYPE, LOAD_COMMAND_TYPES, LoadCommand }

View file

@ -0,0 +1,72 @@
//Global Constants
var MAGICS = [];
/*
@Class MAGIC
@Description
Magic is a specific byte that indicates what for file it is.
In Mach-O there a multiple magics differing from endianess, bits or file type.
*/
let MAGIC =
{
//Macho Magics
FAT_MAGIC: 0xcafebabe,
FAT_CIGAM: 0xbebafeca,
FAT_MAGIC64: 0xcafebabf,
FAT_CIGAM64: 0xbfbafeca,
MH_MAGIC: 0xfeedface,
MH_CIGAM: 0xcefaedfe,
MH_MAGIC64: 0xfeedfacf,
MH_CIGAM64: 0xcffaedfe,
//Retrieve the magic name of a specified magic
//If an invalid magic was specifed undefined is returned
KEYFORVALUE: function(value) {
return MAGICS[value];
},
//Validate that a specified magic is correct
VALIDATE: function(magic) {
return MAGIC.KEYFORVALUE(magic) != undefined;
},
//returns true if the specified magic is a little-endian magic
ISLITTLEENDIAN: function(magic) {
if(!MAGIC.VALIDATE(magic)) //If it is not a valid magic we are basically done here
return false;
return MAGIC.KEYFORVALUE(magic).split('CIGAM').length > 1; //hacky trick to check if the magic value's keyname contains CIGAM which basically indicates little endian
},
//returns true if the specified magic is 64-bit
IS64BIT: function(magic) {
if(!MAGIC.VALIDATE(magic))
return false;
return MAGIC.KEYFORVALUE(magic).split('64').length > 1; //hacky trick to check if the magic value's keyname contains 64 which basically indicates 64-bit
},
toString : function() {
return JSON.stringify(this);
},
debugdescription: ""
};
MAGICS[MAGIC.FAT_MAGIC] = "FAT_MAGIC";
MAGICS[MAGIC.FAT_CIGAM] = "FAT_CIGAM";
MAGICS[MAGIC.FAT_MAGIC64] = "FAT_MAGIC64";
MAGICS[MAGIC.FAT_CIGAM64] = "FAT_CIGAM64";
MAGICS[MAGIC.MH_MAGIC] = "MH_MAGIC";
MAGICS[MAGIC.MH_CIGAM] = "MH_CIGAM";
MAGICS[MAGIC.MH_MAGIC64] = "MH_MAGIC64";
MAGICS[MAGIC.MH_CIGAM64] = "MH_CIGAM64";
export { MAGIC, MAGICS }

View file

@ -0,0 +1,25 @@
let OPERATORS = {
False: 0,
True: 1,
Ident: 2,
AppleAnchor: 3,
AnchorHash: 4,
InfoKeyValue: 5,
And: 6,
Or: 7,
CDHash: 8,
Not: 9,
InfoKeyField: 10,
CertField: 11,
TrustedCert: 12,
TrustedCerts: 13,
CertGeneric: 14,
AppleGenericAnchor: 15,
EntitlementField: 16,
CertPolicy: 17,
NamedAnchor: 18,
Platform: 20,
toString: function() {
return JSON.stringify(this);
}
};

View file

@ -0,0 +1,8 @@
var PrebindCksumCommand = function PrebindCksumCommand(cmd, cmdsize, cksum) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.cksum = cksum || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,10 @@
var PreboundDylibCommand = function PreboundDylibCommand(cmd, cmdsize, name, nmodules, linked_modules) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.name = name || 0x00000000;
this.nmodules = nmodules || 0x00000000;
this.linked_modules = linked_modules || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,30 @@
var RoutinesCommand = function RoutinesCommand(cmd, cmdsize, init_address, init_module, reserved1, reserved2, reserved3, reserved4, reserved5, reserved6) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.init_address = init_address || 0x00000000;
this.init_module = init_module || 0x00000000;
this.reserved1 = reserved1 || 0x00000000;
this.reserved2 = reserved2 || 0x00000000;
this.reserved3 = reserved3 || 0x00000000;
this.reserved4 = reserved4 || 0x00000000;
this.reserved5 = reserved5 || 0x00000000;
this.reserved6 = reserved6 || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var RoutinesCommand64 = function RoutinesCommand64(cmd, cmdsize, init_address, init_module, reserved1, reserved2, reserved3, reserved4, reserved5, reserved6) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.init_address = init_address || 0x0000000000000000;
this.init_module = init_module || 0x0000000000000000;
this.reserved1 = reserved1 || 0x0000000000000000;
this.reserved2 = reserved2 || 0x0000000000000000;
this.reserved3 = reserved3 || 0x0000000000000000;
this.reserved4 = reserved4 || 0x0000000000000000;
this.reserved5 = reserved5 || 0x0000000000000000;
this.reserved6 = reserved6 || 0x0000000000000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,8 @@
var RpathCommand = function RpathCommand(cmd, cmdsize, path) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.path = path || 0x00000000;
this.toString = function() {
JSON.stringify(this);
};
};

View file

@ -0,0 +1,90 @@
//Global Constants
let SECTION_MASK = {
SECTION_TYPE: 0x000000ff,
SECTION_ATTRIBUTES: 0xffffff00
toString = function() {
return JSON.stringify(this);
}
};
let SECTION_TYPE = {
REGULAR: 0,
ZEROFILL: 1,
CSTRING_LITERALS: 2,
BYTE4_LITERALS: 3,
BYTE8_LITERALS: 4,
LITERAL_POINTERS: 5,
NON_LAZY_SYMBOL_POINTERS: 6,
LAZY_SYMBOL_POINTERS: 7,
SYMBOL_STUBS: 8,
MOD_INIT_FUNC_POINTERS: 9,
MOD_TERM_FUNC_POINTERS: 0xa,
COALESCED: 0xb,
GB_ZEROFILL: 0xc,
INTERPOSING: 0xd,
BYTE16_LITERALS: 0xe,
DTRACE_DOF: 0xf,
LAZY_DYLIB_SYMBOL_POINTERS: 0x10,
THREAD_LOCAL_REGULAR: 0x11,
THREAD_LOCAL_ZEROFILL: 0x12,
THREAD_LOCAL_VARIABLES: 0x13,
THREAD_LOCAL_VARIABLE_POINTERS: 0x14,
THREAD_LOCAL_INIT_FUNCTION_POINTERS: 0x15,
toString: function() {
return JSON.stringify(this);
}
};
let SECTION = {
SECT_TEXT: "__text",
SECT_FVMLIB_INIT0: "__fvmlib_init0",
SECT_FVMLIB_INIT1: "__fvmlib_init1",
SECT_DATA: "__data",
SECT_BSS: "__bss",
SECT_COMMON: "__common",
SECT_OBJC_SYMBOLS: "__symbol_table",
SECT_OBJC_MODULES: "__module_info",
SECT_OBJC_STRINGS: "__selector_strs",
SECT_OBJC_REFS: "__selector_refs",
SECT_ICON_HEADER: "__header",
SECT_ICON_TIFF: "__tiff",
toString: function() {
return JSON.stringify(this);
}
};
var Section = function Section(sectname, segname, addr, size, offset, align, reloff, nreloc, flags, reserved1, reserved2) {
this.sectname = new Uint8Array(16);
this.segname = new Uint8Array(16);
this.addr = addr || 0x00000000;
this.size = size || 0x00000000;
this.offset = offset || 0x00000000;
this.align = align || 0x00000000;
this.reloff = reloff || 0x00000000;
this.nreloc = nreloc || 0x00000000;
this.flags = flags || 0x00000000;
this.reserved1 = reserved1 || 0x00000000;
this.reserved2 = reserved2 || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var Section64 = function Section64(sectname, segname, addr, size, offset, align, reloff, nreloc, flags, reserved1, reserved2, reserved3) {
this.sectname = new Uint8Array(16);
this.segname = new Uint8Array(16);
this.addr = addr || 0x0000000000000000;
this.size = size || 0x0000000000000000;
this.offset = offset || 0x00000000;
this.align = align || 0x00000000;
this.reloff = reloff || 0x00000000;
this.nreloc = nreloc || 0x00000000;
this.flags = flags || 0x00000000;
this.reserved1 = reserved1 || 0x00000000;
this.reserved2 = reserved2 || 0x00000000;
this.reserved3 = reserved3 || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,73 @@
//Global Constants
var SG_FLAGS = [];
let SG_FLAG = {
SG_HIGHVM: 0x1,
SG_FVMLIB: 0x2,
SG_NORELOC: 0x4,
DESCRIPTION: function(search) {
let result = SG_FLAGS[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
};
SG_FLAGS[SG_FLAG.SG_HIGHVM] = 'SG_HIGHVM';
SG_FLAGS[SG_FLAG.SG_FVMLIB] = 'SG_FVMLIB';
SG_FLAGS[SG_FLAG.SG_NORELOC] = 'SG_NORELOC';
let SEGMENT = {
SEG_PAGEZERO: "__PAGEZERO",
SEG_TEXT: "__TEXT",
SEG_ICON: "__ICON",
SEG_OBJC: "__OBJC",
SEG_LINKEDIT: "__LINKEDIT",
SEG_UNIXSTACK: "__UNIXSTACK",
SEG_DATA: "__DATA",
toString: function() {
return JSON.stringify(this);
}
};
//32-bits segment command
var SegmentCommand = function SegmentCommand(type, size, segname, vmaddr, vmsize, fileoff, filesize, maxprot, initprot, nsects, flags) {
this.cmd = type || 0x00000000;
this.cmdsize = size || 0x00000000;
this.segname = new TextEncoder("utf-8").encode(segname) || new Uint8Array(16);
this.vmaddr = vmaddr || 0x00000000;
this.vmsize = vmsize || 0x00000000;
this.fileoff = fileoff || 0x00000000;
this.filesize = filesize || 0x00000000;
this.maxprot = maxprot || 0x00000000;
this.initprot = initprot || 0x00000000;
this.nsects = nsects || 0x00000000;
this.flags = flags || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
//64-bits segment command
var SegmentCommand64 = function SegmentCommand64(cmd, cmdsize, segname, vmaddr, vmsize, fileoff, filesize, maxprot, initprot, nsects, flags) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.segname = new TextEncoder("utf-8").encode(segname) || new Uint8Array(16);
this.vmaddr = vmaddr || 0x0000000000000000;
this.vmsize = vmsize || 0x0000000000000000;
this.fileoff = fileoff || 0x0000000000000000;
this.filesize = filesize || 0x0000000000000000;
this.maxprot = maxprot || 0x00000000;
this.initprot = initprot || 0x00000000;
this.nsects = nsects || 0x00000000;
this.flags = flags || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
export { SG_FLAGS, SG_FLAG, SEGMENT, SegmentCommand, SegmentCommand64 }

View file

@ -0,0 +1,12 @@
//Global Constants
let SIGNATURES = {
REQUIREMENT: 0xfade0c00,
REQUIREMENTS: 0xfade0c01,
CODEDIRECTORY: 0xfade0c02,
ENTITLEMENT: 0xfade7171,
BLOBWRAPPER: 0xfade0b01,
EMBEDDED_SIGNATURE: 0xfade0cc0,
DETACHED_SIGNATURE: 0xfade0cc1,
CODE_SIGN_DRS: 0xfade0c05
};

View file

@ -0,0 +1,40 @@
let STABS = {
GSYM: 0x20,
FNAME: 0x22,
FUN: 0x24,
STSYM: 0x26,
LCSYM: 0x28,
MAIN: 0x2a,
BNSYM: 0x2e,
PC: 0x30,
AST: 0x32,
MAC_UNDEF: 0x3a,
OPT: 0x3c,
RSYM: 0x40,
SLINE: 0x44,
DSLINE: 0x46,
BSLINE: 0x48,
ENSYM: 0x4e,
SSYM: 0x60,
SO: 0x64,
OSO: 0x66,
LSYM: 0x80,
BINCL: 0x82,
SOL: 0x84,
PARAMS: 0x86,
VERSION: 0x88,
OLEVEL: 0x8a,
PSYM: 0xa0,
EINCL: 0xa2,
ENTRY: 0xa4,
LBRAC: 0xc0,
EXCL: 0xc2,
RBRAC: 0xe0,
BCOMM: 0xe2,
ECOMM: 0xe4,
ECOML: 0xe8,
LENG: 0xfe,
toString: function() {
return JSON.stringify(this);
}
};

View file

@ -0,0 +1,8 @@
var SubClientCommand = function SubClientCommand(cmd, cmdsize, client) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.client = client || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,5 @@
var SubFrameworkCommand = function SubFrameworkCommand(cmd, cmdsize, umbrella) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.umbrella = umbrella || 0x00000000;
};

View file

@ -0,0 +1,8 @@
var SubLibraryCommand = function SubLibraryCommand(cmd, cmdsize, sub_library) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.sub_library = sub_library || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,8 @@
var SubUmbrellaCommand = function SubUmbrellaCommand(cmd, cmdsize, sub_umbrella) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.sub_umbrella = sub_umbrella || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,56 @@
var SymtabCommand = function SymtabCommand(cmd, cmdsize, symoff, nsyms, stroff, strsize) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.symoff = symoff || 0x00000000;
this.nsyms = nsyms || 0x00000000;
this.stroff = stroff || 0x00000000;
this.strsize = strsize || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var DySymtabCommand = function DySymtabCommand(cmd,
cmdsize,
ilocalsym,
nlocalsym,
iextdefsym,
nextdefsym,
iundefsym,
nundefsym,
ntoc,
modtaboff,
nmodtab,
extrefsymoff,
nextrefsymoff,
nextrefsyms,
indirectsymoff,
ninderectsyms,
extreloff,
nextrel,
locreloff,
nlocrel) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.ilocalsym = ilocalsym || 0x00000000;
this.nlocalsym = nlocalsym || 0x00000000;
this.iextdefsym = iextdefsym || 0x00000000;
this.nextdefsym = nextdefsym || 0x00000000;
this.iundefsym = iundefsym || 0x00000000;
this.nundefsym = nundefsym || 0x00000000;
this.ntoc = ntoc || 0x00000000;
this.modtaboff = modtaboff || 0x00000000;
this.nmodtab = nmodtab || 0x00000000;
this.extrefsymoff = extrefsymoff || 0x00000000;
this.nextrefsymoff = nextrefsymoff || 0x00000000;
this.nextrefsyms = nextrefsyms || 0x00000000;
this.indirectsymoff= indirectsymoff || 0x00000000;
this.ninderectsyms = ninderectsyms || 0x00000000;
this.extreloff = extreloff || 0x00000000;
this.nextrel = nextrel || 0x00000000;
this.locreloff = locreloff || 0x00000000;
this.nlocrel = nlocrel || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,8 @@
var ThreadCommand = function ThreadCommand(cmd, cmdsize, name) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.name = name || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,17 @@
var TwoLevelHintsCommand = function TwoLevelHintsCommand(cmd, cmdsize, offset, nhints) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.offset = offset || 0x00000000;
this.nhints = nhints || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var TwoLevelHint = {
isub_image:8,
itoc:24,
toString: function() {
return JSON.stringify(this);
}
};

View file

@ -0,0 +1,8 @@
var UUIDCommand = function UUIDCommand(cmd, cmdsize, uuid) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.uuid = uuid || new Uint8Array(16); //needs better input validation
this.toString = function() {
return JSON.stringify(this);
};
};

429
helpers/macho/memory.js Normal file
View file

@ -0,0 +1,429 @@
//memory.js
//Written by Sem Voigtländer
//Licensed under the MIT License
/*
Functionality for geting the memory size of a javascript object
*/
export function free(objectName)
{
if(eval(objectName) != 'undefined')
{
console.log('Helping the garbage collector a little bit with freeing.');
eval(objectName + '=undefined;');
}
}
export function sizeof(object) {
var objectList = [];
var stack = [object];
var bytes = 0;
while (stack.length) {
var value = stack.pop();
if (typeof value === 'boolean') {
bytes += 4;
} else if (typeof value === 'string') {
bytes += value.length * 2;
} else if (typeof value === 'number') {
bytes += 8;
} else if (
typeof value === 'object' &&
objectList.indexOf(value) === -1
) {
objectList.push(value);
for (var i in value) {
stack.push(value[i]);
}
}
}
return bytes;
}
/*
Functions for swapping the endianness of an integer
Supports 16, 32 and 64 bit integers. (Experimental 128-bits as well)
Smaller integers are automatically casted to the corresponding size.
Bigger integers are not casted to smaller integers as they may lose precision.
*/
export function SwapEndian16(integer) {
var _hex = '0';
var _output = '';
//Input validation
if(typeof integer !== 'number')
throw new Error('Invalid argument. argument provided is not an integer.');
if(integer < 0)
throw new Error('Invalid argument. argument provided may not be negative.');
_hex = integer.toString(16); //Conver the input to a hexadecimal string
//Conver the hexadecimal string to a 16-bit integer hexadecimal string
while(_hex.length < 4)
_hex = '0'+_hex;
let _arr = _hex.split(''); //Convert the 16-bit integer hexadecimal string to a char array
//Sanity check
if (_arr.length != 4)
throw new Error('Invalid argument. argument provided is not a 16-bit integer.');
//Swap the endianness
_output += (_arr[2] + _arr[3]).toString();
_output += (_arr[0] + _arr[1]).toString();
//Output sanity check
if(_output.length != 4)
throw new Error('Sanity check failed. Output is not a 16-bit integer');
_output = parseInt('0x'+_output); //convert the hexadecimal output string to an integer
//Conversion sanity check
if(_output === NaN)
throw new Error('Conversion from a hexadecimal string to an integer failed.');
return _output;
}
export function SwapEndian32(integer) {
var _hex = '0';
var _output = '';
//Input validation
if(typeof integer !== 'number')
throw new Error('Invalid argument. argument provided is not an integer.');
if(integer < 0)
throw new Error('Invalid argument. argument provided may not be negative.');
_hex = integer.toString(16); //Conver the input to a hexadecimal string
//Conver the hexadecimal string to a 32-bit integer hexadecimal string
while(_hex.length < 8)
_hex = '0'+_hex;
let _arr = _hex.split(''); //Convert the 32-bit integer hexadecimal string to a char array
//Sanity check
if (_arr.length != 8)
throw new Error('Invalid argument. argument provided is not a 32-bit integer.');
//Swap the endianness
_output += (_arr[6] + _arr[7]).toString();
_output += (_arr[4] + _arr[5]).toString();
_output += (_arr[2] + _arr[3]).toString();
_output += (_arr[0] + _arr[1]).toString();
//Output sanity check
if(_output.length != 8)
throw new Error('Sanity check failed. Output is not a 32-bit integer');
_output = parseInt('0x'+_output); //convert the hexadecimal output string to an integer
//Conversion sanity check
if(_output === NaN)
throw new Error('Conversion from a hexadecimal string to an integer failed.');
//Lets help javascripts garbage collector a bit
_arr = undefined;
_hex = undefined;
return _output;
}
export function SwapEndian64(integer) {
var _hex = '0';
var _output = '';
//Input validation
if(typeof integer !== 'number')
throw new Error('Invalid argument. argument provided is not an integer.');
if(integer < 0)
throw new Error('Invalid argument. argument provided may not be negative.');
_hex = integer.toString(16); //Conver the input to a hexadecimal string
//Conver the hexadecimal string to a 64-bit integer hexadecimal string
while(_hex.length < 16)
_hex = '0'+_hex;
let _arr = _hex.split(''); //Convert the 64-bit integer hexadecimal string to a char array
//Sanity check
if (_arr.length != 16)
throw new Error('Invalid argument. argument provided is not a 64-bit integer.');
//Swap the endianness
_output += (_arr[14] + _arr[15]).toString();
_output += (_arr[12] + _arr[13]).toString();
_output += (_arr[10] + _arr[11]).toString();
_output += (_arr[8] + _arr[9]).toString();
_output += (_arr[6] + _arr[7]).toString();
_output += (_arr[4] + _arr[5]).toString();
_output += (_arr[2] + _arr[3]).toString();
_output += (_arr[0] + _arr[1]).toString();
//Output sanity check
if(_output.length != 16)
throw new Error('Sanity check failed. Output is not a 64-bit integer');
_output = parseInt('0x'+_output); //convert the hexadecimal output string to an integer
//Conversion sanity check
if(_output === NaN)
throw new Error('Conversion from a hexadecimal string to an integer failed.');
//Lets help javascripts garbage collector a bit
_arr = undefined;
_hex = undefined;
return _output;
}
export function SwapEndian128(integer) {
var _hex = '0';
var _output = '';
//Input validation
if(typeof integer !== 'number')
throw new Error('Invalid argument. argument provided is not an integer.');
if(integer < 0)
throw new Error('Invalid argument. argument provided may not be negative.');
_hex = integer.toString(16); //Conver the input to a hexadecimal string
//Conver the hexadecimal string to a 128-bit integer hexadecimal string
while(_hex.length < 32)
_hex = '0'+_hex;
let _arr = _hex.split(''); //Convert the 128-bit integer hexadecimal string to a char array
//Sanity check
if (_arr.length != 32)
throw new Error('Invalid argument. argument provided is not a 128-bit integer.');
//Swap the endianness
_output += (_arr[30] + _arr[31]).toString();
_output += (_arr[28] + _arr[29]).toString();
_output += (_arr[26] + _arr[27]).toString();
_output += (_arr[24] + _arr[25]).toString();
_output += (_arr[22] + _arr[23]).toString();
_output += (_arr[20] + _arr[21]).toString();
_output += (_arr[18] + _arr[19]).toString();
_output += (_arr[16] + _arr[17]).toString();
_output += (_arr[14] + _arr[15]).toString();
_output += (_arr[12] + _arr[13]).toString();
_output += (_arr[10] + _arr[11]).toString();
_output += (_arr[8] + _arr[9]).toString();
_output += (_arr[6] + _arr[7]).toString();
_output += (_arr[4] + _arr[5]).toString();
_output += (_arr[2] + _arr[3]).toString();
_output += (_arr[0] + _arr[1]).toString();
//Output sanity check
if(_output.length != 32)
throw new Error('Sanity check failed. Output is not a 128-bit integer');
_output = parseInt('0x'+_output); //convert the hexadecimal output string to an integer
//Conversion sanity check
if(_output === NaN)
throw new Error('Conversion from a hexadecimal string to an integer failed.');
//Lets help javascripts garbage collector a bit
_arr = undefined;
_hex = undefined;
return _output;
}
/*
Functions for reading integers from a given offset in a given array.
Supports 16, 32 and 64 bit integers. (Experimental 128-bits as well)
It also supports reading with a different Endianness.
*/
//Big Endian
export function ReadUint16(arr, off) {
if(arr.length < 2 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off].toString(16) +
arr[off + 1].toString(16)
);
}
export function ReadUint32(arr, off) {
if(arr.length < 4 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off].toString(16) +
arr[off + 1].toString(16) +
arr[off + 2].toString(16) +
arr[off + 3].toString(16)
);
}
export function ReadUint64(arr, off) {
if(arr.length < 8 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off].toString(16) +
arr[off + 1].toString(16) +
arr[off + 2].toString(16) +
arr[off + 3].toString(16) +
arr[off + 4].toString(16) +
arr[off + 5].toString(16) +
arr[off + 6].toString(16) +
arr[off + 7].toString(16)
);
}
export function ReadUint128(arr, off) {
if(arr.length < 16 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off].toString(16) +
arr[off + 1].toString(16) +
arr[off + 2].toString(16) +
arr[off + 3].toString(16) +
arr[off + 4].toString(16) +
arr[off + 5].toString(16) +
arr[off + 6].toString(16) +
arr[off + 7].toString(16) +
arr[off + 8].toString(16) +
arr[off + 9].toString(16) +
arr[off + 10].toString(16) +
arr[off + 11].toString(16) +
arr[off + 12].toString(16) +
arr[off + 13].toString(16) +
arr[off + 14].toString(16) +
arr[off + 15].toString(16)
);
}
//Little Endian
export function ReadUint16LE(arr, off) {
if(arr.length < 2 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off + 1].toString(16) +
arr[off].toString(16)
);
}
export function ReadUint32LE(arr, off) {
if(arr.length < 4 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off + 3].toString(16) +
arr[off + 2].toString(16) +
arr[off + 1].toString(16) +
arr[off].toString(16)
);
}
export function ReadUint64LE(arr, off) {
if(arr.length < 8 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off + 7].toString(16) +
arr[off + 6].toString(16) +
arr[off + 5].toString(16) +
arr[off + 4].toString(16) +
arr[off + 3].toString(16) +
arr[off + 2].toString(16) +
arr[off + 1].toString(16) +
arr[off].toString(16)
);
}
export function ReadUint128LE(arr, off) {
if(arr.length < 16 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off + 15].toString(16) +
arr[off + 14].toString(16) +
arr[off + 13].toString(16) +
arr[off + 12].toString(16) +
arr[off + 11].toString(16) +
arr[off + 10].toString(16) +
arr[off + 9].toString(16) +
arr[off + 8].toString(16) +
arr[off + 7].toString(16) +
arr[off + 6].toString(16) +
arr[off + 5].toString(16) +
arr[off + 4].toString(16) +
arr[off + 3].toString(16) +
arr[off + 2].toString(16) +
arr[off + 1].toString(16) +
arr[off].toString(16)
);
}
export function writeUint8(arr, off, val) {
if(arr.length < 2 || off > arr.length || off < 0) {
throw new Error('Cannot write OOB.');
}
if(val.length > 0xff)
throw new Error('Invalid argument. This should be a valid 8-bit integer.');
let old = arr[off];
arr[off] = val;
}
export function writeUint16(arr, off, val) {
if(arr.length < 4 || off > arr.length || off < 0) { //We should never underflow or overflow our buffer
throw new Error('Cannot write OOB.');
}
if(val.length > 0xffff) //Values that after serialization never will be a 16 bit integer should never be treated
throw new Error('Invalid argument. This should be a valid 16-bit integer.');
let old = new Array(arr[off], arr[off+1]);
if(val <= 0xff) { //Integers below 256 are always valid
arr[off] = val;
} else if(val > 0xff && val <= 0xfff) { //Integers bigger than 256 but below 4096 should be treated as two bytes instead of one and fixed with a leading zero
arr[off] = parseInt('0x'+(val.toString(16).split('')[0] + val.toString(16).split('')[1]));
arr[off+1] = parseInt('0x0'+val.toString(16).split('')[2]);
} else if(val > 0xff && val <= 0xffff) { //Integers bigger than 256 and below 65535 should be treated as two bytes and can be splitted without having to fix them with a leading zero
arr[off] = parseInt('0x'+(val.toString(16).split('')[0] + val.toString(16).split('')[1]));
arr[off+1] = parseInt('0x'+val.toString(16).split('')[2] + val.toString(16).split('')[3]);
}
}

View file

@ -0,0 +1,6 @@
//MimeTypes Library
export let mime_binary = 'application/octet-stream';
export let mime_zip = 'application/octet-stream';
export let mime_html = 'text/html';
export let mime_text = 'text/plain';

View file

@ -25,7 +25,7 @@
</div>
</div>
<p class="mt-8 text-center text-base leading-6 text-gray-400">
&copy; 2020 Does it ARM All rights reserved.
&copy; {{ currentYear }} Does it ARM All rights reserved.
</p>
</div>
</footer>
@ -49,6 +49,11 @@ export default {
components: {
Navbar,
AllUpdatesSubscribe
},
computed: {
currentYear () {
return new Date().getFullYear()
}
}
}

View file

@ -16,7 +16,15 @@
from = "/app/node"
to = "/app/nodejs"
status = 301
# old git redirect
[[redirects]]
from = "/app/git"
to = "/app/git-version-control"
status = 301
# Category Redirects
[[redirects]]
from = "/kind/entertainment"
to = "/kind/entertainment-and-media-apps/"
@ -26,3 +34,17 @@
from = "/kind/photo-tools"
to = "/kind/photo-and-graphic-tools/"
status = 301
# Other Redirects
# Random broken link from Chinese sites
[[redirects]]
from = "/。"
to = "/"
status = 301
[[redirects]]
from = "/%E3%80%82"
to = "/"
status = 301

View file

@ -7,7 +7,8 @@ export default {
target: 'static',
publicRuntimeConfig: {
allUpdateSubscribe: process.env.ALL_UPDATE_SUBSCRIBE
allUpdateSubscribe: process.env.ALL_UPDATE_SUBSCRIBE,
testResultStore: process.env.TEST_RESULT_STORE
},
/*
@ -151,8 +152,19 @@ export default {
** You can extend webpack config here
*/
extend(config, ctx) {
// Client
if (ctx.isClient) {
// Push meta import rule for zip.js
config.module.rules.push({
test: /\.js$/,
loader: require.resolve('@open-wc/webpack-import-meta-loader')
})
}
// Run ESLint on save
if (ctx.isDev && ctx.isClient) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,

7192
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,8 @@
"@11ty/eleventy-assets": "^1.0.5",
"@fontsource/inter": "^4.0.1",
"@nuxtjs/sitemap": "^2.4.0",
"@open-wc/webpack-import-meta-loader": "^0.4.7",
"@zip.js/zip.js": "^2.2.6",
"axios": "^0.21.0",
"cross-env": "^5.2.0",
"lazysizes": "^5.3.0-beta1",
@ -30,8 +32,11 @@
"marked": "^1.2.7",
"node-html-parser": "^2.0.0",
"observe-element-in-viewport": "0.0.15",
"plist": "^3.0.1",
"pretty-bytes": "^5.5.0",
"scroll-into-view-if-needed": "^2.2.26",
"slugify": "^1.4.6"
"slugify": "^1.4.6",
"vue-full-screen-file-drop": "^2.0.0"
},
"devDependencies": {
"@11ty/eleventy": "^0.11.1",

View file

@ -0,0 +1,350 @@
<template>
<section class="container py-24">
<div class="flex flex-col items-center space-y-24">
<header class="flex flex-col items-center space-y-6 md:px-12">
<div class="title-container relative">
<h1 class="title text-3xl md:text-5xl font-hairline leading-tight text-center">
Apple Silicon App Test
</h1>
<div
class="beta-pill absolute h-5 text-xs bg-white-2 flex justify-center items-center outline-0 rounded-full ease px-2"
style="top: -1em; right: 0;"
>
Beta
</div>
</div>
<h2 class="subtitle md:text-xl text-center">
Check for Apple Silicon compatibility for your apps before you buy an M1 Mac.
</h2>
</header>
<div class="app-tester w-full space-y-4 pb-64">
<div
class="relative w-full flex flex-col justify-center items-center space-y-4 pb-8"
>
<button
:class="[
'rounded-xl text-3xl font-semibold scale-150 bg-darkest neumorphic-shadow focus:outline-none py-4 px-6',
isLoadingFiles ? 'shimmer' : ''
]"
@click="triggerFilepicker"
>{{ isLoadingFiles ? 'Loading Files' : 'Select Apps' }}</button>
<template v-if="isLoadingFiles">
<div>Loading usually takes about a minute per 500mb</div>
<button
class="underline"
@click="isLoadingFiles = false"
>Cancel</button>
</template>
<div>
<small>
<span>Supports: Mac Apps, Zip files, and <em>some</em> DMG files. Bigger files take longer. </span>
<a
href="https://www.youtube.com/watch?v=icq9wJx7wbg"
class="underline"
rel="noopener"
>How it works</a>
</small>
</div>
<input
ref="file-selector"
type="file"
accept="application/**"
multiple
hidden
@change="fileInputChanged"
>
<!-- Directories only: webkitdirectory directory -->
</div>
<div
v-if="foundFiles.length !== 0"
class="w-full text-center"
>
Total Files: {{ foundFiles.length }}
</div>
<div
v-if="foundFiles.length !== 0"
class="app-scans-container relative divide-y divide-gray-700 w-full rounded-lg border border-gray-700 bg-gradient-to-br from-darker to-dark spac-y-3 my-4 px-5"
>
<ul
class="results-container divide-y divide-gray-700"
>
<li
v-for="( appScan, index ) in foundFiles"
:key="`${appScan.name}-${index}`"
:ref="`${appScan.name}-row`"
class="relative"
>
<!-- app.endpoint: {{ app.endpoint }} -->
<div
:class="[
'flex flex-col justify-center inset-x-0 hover:bg-darkest border-2 border-white border-opacity-0 hover:border-opacity-50 focus:outline-none focus:bg-gray-50 duration-300 ease-in-out rounded-lg space-y-3 -mx-5 pl-5 md:pl-20 pr-6 md:pr-64 py-5',
(appScan.status !== 'finished') ? 'shimmer' : ''
]"
style="transition-property: border;"
>
<div class="absolute hidden left-0 h-12 w-12 rounded-full md:flex items-center justify-center bg-darker">
{{ appScan.name.charAt(0) }}
</div>
{{ appScan.displayName || appScan.name }}
{{ appScan.appVersion ? `- v${appScan.appVersion}` : '' }}
{{ appScan.displayAppSize ? `- App ${appScan.displayAppSize}` : '' }}
{{ appScan.displayBinarySize ? `- Binary ${appScan.displayBinarySize}` : '' }}
<div class="text-sm leading-5 font-bold">
{{ appScan.statusMessage }}
</div>
<!-- appScan.binarySize: {{ appScan.binarySize }} -->
<div
v-if="appScan.binarySize && appScan.binarySize < (10 ^ 6)"
class="text-sm leading-5 font-bold"
>
Large Binary - This scan may take a while an/or have issues
</div>
<details class="w-full pt-6">
<summary class="cursor-pointer mb-3">Details</summary>
<div>
<div v-if="appScan.details.length === 0">No details available</div>
<ul v-else>
<li
v-for="( detail ) in appScan.details"
:key="`${appScan.name}-detail-${detail.label}`"
><strong>{{ detail.label }}</strong> <span v-html="detail.value" /></li>
</ul>
</div>
</details>
<div class="flex flex-col md:flex-row space-x-0 space-y-4 md:space-y-0 md:space-x-4">
<a
:href="`https://github.com/ThatGuySam/doesitarm/issues?q=is%3Aissue+${appScan.displayName || appScan.name}`"
class="underline"
>Request a Review</a>
</div>
</div>
</li>
</ul>
</div>
</div>
<div class="w-full max-w-2xl">
<details
v-for="([ question, answer ], index) in faqs"
:key="`question-${index}`"
class="w-full"
>
<summary class="cursor-pointer">{{ question }}</summary>
<div class="p-4">
<p>{{ answer }}</p>
</div>
</details>
</div>
<!-- <pre class="w-full">{{ appsBeingScanned }}</pre> -->
<AllUpdatesSubscribe
:input-class-groups="{
shadow: 'hover:neumorphic-shadow',
bg: '',
focus: 'bg-transparent neumorphic-shadow pl-8',
blur: 'placeholder-white text-center border border-transparent bg-transparent opacity-50 hover:opacity-100 px-3',
}"
class="my-12"
/>
</div>
<!-- <client-only>
<FullScreenFileDrop @drop="onDrop" />
</client-only> -->
</section>
</template>
<script>
// import axios from 'axios'
// import AppFilesScanner from '~/helpers/app-files-scanner.js'
import LinkButton from '~/components/link-button.vue'
import AllUpdatesSubscribe from '~/components/all-updates-subscribe.vue'
export default {
// async asyncData () {
// return {
// allAppSearchLinks,
// customSummaryNumbers: getListSummaryNumbers(allList)
// }
// },
components: {
// FullScreenFileDrop: () => process.client ? import('~/components/fullscreen-file-drop.vue') : null,
LinkButton,
AllUpdatesSubscribe
},
data: function () {
return {
query: '',
isLoadingFiles: false,
appsBeingScanned: []
}
},
computed: {
foundFiles () {
return this.appsBeingScanned.filter( appScan => {
return !appScan.statusMessage.includes('⏭')
})
},
faqs () {
return [
[
'Non-native Apps (🔶)',
`
You can try getting the latest version from the developer\'s the download page scan that.
You can also request a manual review to determine the current status of the app on Rosetta 2.
`
],
[
'Why can\'t it tell me if an app will work on Rosetta 2? ',
`
Currently, Rosetta 2 is a proprietary Apple software that is only available on macOS on Apple Silicon devices.
This means there isn't any way to test Rosetta 2 compatibility with an app without a physical Apple Silicon device and so you definitely can't test that with just a website alone... for now...
Feel free to signup for email updates.
`
],
[
'Don\'t all previous Mac Apps work via Rosetta 2 translation? ',
`
Most apps will work with Rosetta 2 translation well but it's not a perfect technology.
Some apps will have various small issues and graphical bugs but will work well enough, a few apps will fail to launch entirely and some apps will runs with virtually no issues and perform even faster than an equivalent Intel-based Mac.
For now the best way to determine how well an app will run under Rosetta 2 is by human review.
`
]
]
},
title () {
return `Apple Silicon Compatibility`
},
description () {
return `Check for Apple Silicon compatibility for any of your apps instantly before you buy an M1 Mac. `
}
},
mounted () {
this.scanner = null
},
methods: {
log ( thing ) {
console.log( thing )
},
triggerFilepicker () {
this.isLoadingFiles = true
// this.watchFileInput()
this.$refs['file-selector'].dispatchEvent(new MouseEvent('click'))
},
async fileInputChanged () {
this.isLoadingFiles = false
// console.log('file-selector', this.$refs['file-selector'])
// Get FileList from input
const fileList = this.$refs['file-selector'].files
// If the scanner instance is not set up yet
// then create and initialize it
if ( this.scanner === null ) {
console.log('Initializing scanner instance')
// Bring in code
const { default: AppFilesScanner} = await import('~/helpers/app-files-scanner.js')
// Initialize instance
this.scanner = new AppFilesScanner({
observableFilesArray: this.appsBeingScanned,
testResultStore: this.$config.testResultStore
})
}
// console.log('fileInputChanged files', fileList)
this.scanner.scan( fileList )
},
// async onDrop ( formData, fileList ) {
// console.log('Off to the races')
// // await new Promise(r => setTimeout(r, 2000))
// const formValues = formData.values()
// for ( const value of formValues ) {
// console.log( 'value', value )
// }
// // console.log( 'formData', formData.values() ) // Can be posted to server
// // console.log( 'fileList', fileList ) // Can get access to things like file name and size
// this.scanner.scan( fileList )
// }
// async onQueryUpdate ( $event ) {
// // console.log('$event', $event)
// this.query = $event
// return
// }
},
head() {
return {
title: this.title,
meta: [
// hid is used as unique identifier. Do not use `vmid` for it as it will not work
{
'hid': 'description',
'name': 'description',
'content': this.description
},
// Twitter Card
{
'hid': 'twitter:title',
'property': 'twitter:title',
'content': this.title
},
{
'hid': 'twitter:description',
'property': 'twitter:description',
'content': this.description
},
{
'property': 'twitter:url',
'content': `${process.env.URL}${this.$nuxt.$route.path}`
},
]
}
}
}
</script>

View file

@ -40,6 +40,13 @@
>
Request an App with Twitter
</LinkButton>
<LinkButton
:href="`/apple-silicon-app-test/`"
class="text-xs"
>
Scan Your Own App
</LinkButton>
</div>
<AllUpdatesSubscribe

View file

@ -44,6 +44,13 @@
>
Request an App with Twitter
</LinkButton>
<LinkButton
:href="`/apple-silicon-app-test/`"
class="text-xs"
>
Scan Your Own App
</LinkButton>
</template>
</div>