mirror of
https://github.com/ThatGuySam/doesitarm.git
synced 2026-05-15 06:35:20 -07:00
Merge branch 'master' into feat/build-lists
# Conflicts: # package-lock.json
This commit is contained in:
commit
a7551e1dd8
46 changed files with 3164 additions and 7153 deletions
124
README.md
124
README.md
|
|
@ -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 it’s 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 it’s 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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
148
components/fullscreen-file-drop.vue
Normal file
148
components/fullscreen-file-drop.vue
Normal 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>
|
||||
|
|
@ -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',
|
||||
},
|
||||
])
|
||||
}
|
||||
},
|
||||
|
|
|
|||
615
helpers/app-files-scanner.js
Normal file
615
helpers/app-files-scanner.js
Normal 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
4
helpers/macho/index.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import MachoParser from './macho.js'
|
||||
|
||||
|
||||
export default MachoParser
|
||||
13
helpers/macho/macho.constants.js
Normal file
13
helpers/macho/macho.constants.js
Normal 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
134
helpers/macho/macho.cpu.js
Normal 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 }
|
||||
12
helpers/macho/macho.cstr.js
Normal file
12
helpers/macho/macho.cstr.js
Normal 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
|
||||
72
helpers/macho/macho.dylib.js
Normal file
72
helpers/macho/macho.dylib.js
Normal 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);
|
||||
}
|
||||
};
|
||||
7
helpers/macho/macho.dylinker.js
Normal file
7
helpers/macho/macho.dylinker.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
var DylinkerCommand = function DylinkerCommand(cmd, cmdsize) {
|
||||
this.cmd = 0x00000000;
|
||||
this.cmdsize = 0x00000000;
|
||||
this.toString = function() {
|
||||
return JSON.stringify(this);
|
||||
};
|
||||
};
|
||||
73
helpers/macho/macho.file.js
Normal file
73
helpers/macho/macho.file.js
Normal 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 }
|
||||
31
helpers/macho/macho.flags.js
Normal file
31
helpers/macho/macho.flags.js
Normal 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);
|
||||
}
|
||||
};
|
||||
17
helpers/macho/macho.fvmlib.js
Normal file
17
helpers/macho/macho.fvmlib.js
Normal 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);
|
||||
};
|
||||
};
|
||||
49
helpers/macho/macho.header.js
Normal file
49
helpers/macho/macho.header.js
Normal 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
317
helpers/macho/macho.js
Normal 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 )
|
||||
}
|
||||
} )
|
||||
}
|
||||
9
helpers/macho/macho.linkeditdata.js
Normal file
9
helpers/macho/macho.linkeditdata.js
Normal 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);
|
||||
};
|
||||
};
|
||||
133
helpers/macho/macho.loadcommand.js
Normal file
133
helpers/macho/macho.loadcommand.js
Normal 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 }
|
||||
72
helpers/macho/macho.magic.js
Normal file
72
helpers/macho/macho.magic.js
Normal 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 }
|
||||
25
helpers/macho/macho.operators.js
Normal file
25
helpers/macho/macho.operators.js
Normal 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);
|
||||
}
|
||||
};
|
||||
8
helpers/macho/macho.prebindcksum.js
Normal file
8
helpers/macho/macho.prebindcksum.js
Normal 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);
|
||||
};
|
||||
};
|
||||
10
helpers/macho/macho.prebounddylib.js
Normal file
10
helpers/macho/macho.prebounddylib.js
Normal 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);
|
||||
};
|
||||
};
|
||||
30
helpers/macho/macho.routines.js
Normal file
30
helpers/macho/macho.routines.js
Normal 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);
|
||||
};
|
||||
};
|
||||
8
helpers/macho/macho.rpath.js
Normal file
8
helpers/macho/macho.rpath.js
Normal 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);
|
||||
};
|
||||
};
|
||||
90
helpers/macho/macho.section.js
Normal file
90
helpers/macho/macho.section.js
Normal 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);
|
||||
};
|
||||
};
|
||||
73
helpers/macho/macho.segment.js
Normal file
73
helpers/macho/macho.segment.js
Normal 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 }
|
||||
12
helpers/macho/macho.signatures.js
Normal file
12
helpers/macho/macho.signatures.js
Normal 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
|
||||
};
|
||||
40
helpers/macho/macho.stabs.js
Normal file
40
helpers/macho/macho.stabs.js
Normal 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);
|
||||
}
|
||||
};
|
||||
8
helpers/macho/macho.subclient.js
Normal file
8
helpers/macho/macho.subclient.js
Normal 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);
|
||||
};
|
||||
};
|
||||
5
helpers/macho/macho.subframework.js
Normal file
5
helpers/macho/macho.subframework.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
var SubFrameworkCommand = function SubFrameworkCommand(cmd, cmdsize, umbrella) {
|
||||
this.cmd = cmd || 0x00000000;
|
||||
this.cmdsize = cmdsize || 0x00000000;
|
||||
this.umbrella = umbrella || 0x00000000;
|
||||
};
|
||||
8
helpers/macho/macho.sublibrary.js
Normal file
8
helpers/macho/macho.sublibrary.js
Normal 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);
|
||||
};
|
||||
};
|
||||
8
helpers/macho/macho.subumbrella.js
Normal file
8
helpers/macho/macho.subumbrella.js
Normal 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);
|
||||
};
|
||||
};
|
||||
56
helpers/macho/macho.symtab.js
Normal file
56
helpers/macho/macho.symtab.js
Normal 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);
|
||||
};
|
||||
};
|
||||
8
helpers/macho/macho.thread.js
Normal file
8
helpers/macho/macho.thread.js
Normal 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);
|
||||
};
|
||||
};
|
||||
17
helpers/macho/macho.twolevelhints.js
Normal file
17
helpers/macho/macho.twolevelhints.js
Normal 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);
|
||||
}
|
||||
};
|
||||
8
helpers/macho/macho.uuid.js
Normal file
8
helpers/macho/macho.uuid.js
Normal 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
429
helpers/macho/memory.js
Normal 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]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
6
helpers/macho/mimetypes.js
Normal file
6
helpers/macho/mimetypes.js
Normal 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';
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<p class="mt-8 text-center text-base leading-6 text-gray-400">
|
||||
© 2020 Does it ARM All rights reserved.
|
||||
© {{ 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
22
netlify.toml
22
netlify.toml
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
7192
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -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",
|
||||
|
|
|
|||
350
pages/apple-silicon-app-test.vue
Normal file
350
pages/apple-silicon-app-test.vue
Normal 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>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue