8 ms·
Reverse-Engineering Apple Dictionary (2020)
- enragedcacti 5y agoFor anyone else needing to tackle something like this, its definitely worth checking out Binwalk [1]. It is meant for extracting firmware but it works decently well on most files-in-files type data formats. [1] https://github.com/ReFirmLabs/binwalk https://github.com/ReFirmLabs/binwalk
- bouk 5y agoThis was my first instinct as well! Running binwalk on the binary dictionary file immediately outputs that it's a series of zlib-compressed values.
- gilgoomesh 5y agoIt seems highly likely (given that this is a dictionary and requires fast lookups) that you're reverse engineering something like CEVFS (i.e. a virtual file system for compressing a database). Which is why the dictionary is broken into chunks... these are the compressed pages of the database.
- ChrisMarshallNY 5y agoThat's awesome! But be aware (i.e. "beware") that Apple can pull the rug out of unpublished APIs, without warning. I have been caught out, by this, myself.
- gfaure 5y agoI assume one reason Apple has made it more challenging to extract the dictionary resources is in order to satisfy licensing constraints with the dictionary authors. I wonder if they'd block an app like this through the App Store submission process, if submitted.
- macintux 5y agoI’d definitely assume this would be a copyright problem if used in an app.
- peterburkimsher 5y agoYes, a lot of people involved in dictionary processing are worried about copyright! After I wrote my post about Apple's dictionary files, I got a mysterious email showing up in my inbox. The email was from someone who's spent some time writing code to do the same thing, but doesn't want to post it under his own name in case he falls fowl of his country's DMCA equivalent. Crazy. He said I could post his code under the condition that I took his name off it. https://josephg.com/blog/apple-dictionaries-part-2/ https://josephg.com/blog/apple-dictionaries-part-2/
- tkgally 5y agoI have helped with the writing and editing of a number of dictionaries over the years. It's difficult, highly specialized work. For some of the jobs, the only compensation has been a share of the royalties from future sales. I doubt if many people like me are enthusiastic about the dictionary data becoming accessible for free.
- tasogare 5y agoYes, dictionary content is the revenue source of dictionary vendors, so of course they don't want anyone to use it without permission. On the other hand there are more and more open-data projects (I started one myself), often based on printed dictionaries that felt in the public domain.
- simondotau 5y agoWhat’s the state of Wiktionary like in your opinion?
- tasogare 5y ago
- avianlyric 5y agoI suspect it’s more likely they have a bunch of internal frameworks for creating, accessing, and distributing simple databases (something akin to SQLite). So the difficulty we’re seeing here isn’t deliberate obfuscation, but rather just an dev using a database structure to make app design and word lookup easier. If there really was licensing concerns I would expect there to at-least be some basic encryption, not just some basic compression.
- simonw 5y agoApple use regular SQLite for a whole bunch of other applications, such as Apple Photos. I wonder why they didn't use it here?
- spitfire 5y agoThe dictionary app (and hence its database) may go all the way back to NeXTStep/Openstep. Maybe not all of it. But I wouldn't doubt if bits of it went all the way back to the early days where a fancy dictionary was one of the star features of NeXTStep.
- simondotau 5y agoThe underlying file format and associated libraries are probably largely unchanged from the NeXTStep era. If it ain’t broke, don’t fix it. http://toastytech.com/guis/ns20mail.png http://toastytech.com/guis/ns20mail.png (Edit: beaten by 30 seconds!)
- jahewson 5y agoThat’s highly unlikely. The author is incorrect about it being a Zip file, it’s actually a simple gzip/zlib stream. Because it’s not possible to seek within such a stream, they are always chunked in any file that requires random access. Elsewhere there will be an index file which maps words to their corresponding chunks, so that the definition can be quickly loaded without having to decompress the entire file - or even load it all into memory. This is very normal stuff in the world of file formats.
- etaioinshrdlu 5y agoThis is fun. I have another idea: I'd be interested on calling Siri from the command line. Even if using private APIs. (But without hacky fake drivers, or accessibility tools)
- crabl 5y agoThe closest I've managed to this has been through AppleScript (which likely violates your "no accessibility tools" criteria): https://forum.keyboardmaestro.com/t/type-to-siri/13328/17 https://forum.keyboardmaestro.com/t/type-to-siri/13328/17
- etaioinshrdlu 5y agoYeah, I guess another requirement, it should be as "invisible" as possible. So you could programmatically interact with Siri in the background and perhaps not notice.
- wazzaps 5y agoThe knowledge part is powered by Wolfram Alpha, which has an API, I believe
- cogburnd02 5y agowould be really really cool if someone could make a small script to convert these into a format understandable by dict:// https://en.wikipedia.org/wiki/DICT https://en.wikipedia.org/wiki/DICT
- solarmist 5y agoI've created a first step towards that. A general purpose tool for extracting the data back into XML. https://github.com/solarmist/apple-peeler https://github.com/solarmist/apple-peeler
- cogburnd02 5y agoI bet it'd be pretty easy to make an awk script to convert XML into something like dictfmt(1)'s -j Jargon File format text. https://linux.die.net/man/1/dictfmt https://linux.die.net/man/1/dictfmt http://www.catb.org/jargon/oldversions/jarg447.txt http://www.catb.org/jargon/oldversions/jarg447.txt
- solarmist 5y agoMaybe. Don't know. I've never really used dictfmt or the like. What's it good for?
- cogburnd02 5y agoonce you get the dictd server set up, all you need to do to get a definition is run curl. google 'curl dict' for some stuff.
- peterburkimsher 5y agoThank you for posting this code on Github! There has been some reverse-engineering done on the language dictionaries bundled with Mac OS, and it's nice to know that the same model is being used on the Apple Watch! I look forward to seeing your dictionary app. https://josephg.com/blog/reverse-engineering-apple-dictionaries/ https://josephg.com/blog/reverse-engineering-apple-dictionar... There's also a command-line tool that can query the dictionary: https://github.com/takumakei/osx-dictionary https://github.com/takumakei/osx-dictionary Something I haven't yet reverse-engineered is Apple's word segmentation. I can get the word breaks in Chinese by pressing option + right arrow + space, repeatedly. But I have no idea how the backend for that works.
- krackers 5y ago>Apple's word segmentation Unless they changed it, it's probably similar to CFStringTokenizer which used ICU Boundary Analysis (and maybe mecab for Japanese).
- peterburkimsher 5y agoThank you! The ICU Boundary Analysis documentation says it uses a dictionary to split Chinese, Japanese, Thai or Khmer. https://unicode-org.github.io/icu/userguide/boundaryanalysis/ https://unicode-org.github.io/icu/userguide/boundaryanalysis... Is that the same as the macOS dictionary being parsed here? It seems like a pretty big file to grep every time!
- krackers 5y agoNo, the ICU dictionaries are seen at: https://github.com/unicode-org/icu/tree/main/icu4c/source/data/brkitr/dictionaries https://github.com/unicode-org/icu/tree/main/icu4c/source/da... I assume at compile time it's converted to a more efficient query format
- btn 5y agoAnother approach for this is to explore the format through Apple's tools for building dictionaries – as they provide a "Dictionary Development Kit" in Xcode's downloadable "Additional Tools" package (which has documentation for the XML format and a bunch of scripts/binaries for building the bundle). I wound up doing this a while ago for a similar toy project. After some poking around, it turned out that dictionary bundles are entirely supported by system APIs in CoreServices! The APIs are private, but Apple accidentally shipped a header file with documentation for them in the 10.7 SDK [1]. You can load a dictionary with `IDXCreateIndexObject()`, read through its indices with the search methods (and the convenient `kIDXSearchAllMatch`), and get pointers to its entry data with `IDXGetFieldDataPtrs()`. It takes a bit of fiddling to figure out the structure (there are multiple indices for headwords, search keywords, cross-references, etc., and the API is a general-purpose trie library) and request the right fields, but those property lists in the bundle are there to help! (As the author of this article discovered, the entries are compressed and are proceeded with a 4-byte length marker.) [1] https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.7.sdk/usr/include/IndexedSearch.h https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10...
- kccqzy 5y agoI have memories of using the Dictionary Development Kit to create custom dictionaries (I remember creating one for medical jargon) about ten years ago. (At that time custom dictionaries are placed in ~/Library/Dictionaries, and system dictionaries in /System/Library/Dictionaries, not some obfuscated path like now.) To find the Kit in question, simply Google "com.apple.TrieAccessMethod" and you should find it online.
- dunham 5y agoThe "seemingly random bytes" look like a small 32-bit little endian number to me, probably the length of the subsequent payload.
- octref 5y agoI have thought about building a vocabulary learning tool for learning Japanese on top of Apple Dictionary. My idea is simple: user collects dicitionary items and the tool offers lookup / spaced-repetition. However, I'm concerned that the dictionary is copyrighted. Is there any precedent that says whether such a tool would be legal/illegal?
- tasogare 5y agoIf your tool doesn't come with bundled data from Apple, extract data in local and doesn't leak it to another party it's probably safe to do so (like emulators).
- tim-- 5y agoAnother way to extract all of those compressed zip files would have been to use binwalk. binwalk --dd='.*' *.asset Edit: should have read the comments before I posted this, because enragedcacti already mentioned this tool an hour ago.
- solarmist 5y agoThank you I didn't know about this Binwalk. I used it and was able to figure out the remaining bits of the file format thanks to you and other tips in this thread. https://github.com/solarmist/apple-peeler https://github.com/solarmist/apple-peeler
- ranvel 5y agoThis was an amazingly delightful read. I was hoping it would shed some light on a long-time project I had which was reversing the Oxford language dictionaries that were included on CDROM with the big printed texts. (I already did it, but with a debugger instead of by reversing the binary format). Alas, it did not, but it was super encouraging to see the enthusiasm and interest in language dictionaries.
- bhl 5y agoHas anyone reversed-engineered the Apple emoji dictionary that maps some keywords to emojis? Last time I checked, they only shipped binaries on the newest MacOS. Would love to use that mapping to elevate search on my custom emoji picker.
- luigi23 5y agoyou may try assign text replacements for emojis: https://www.iphonehacks.com/2016/04/text-replacement-mac.html https://www.iphonehacks.com/2016/04/text-replacement-mac.htm...
- bhl 5y agoI'm trying to find the source data Apple uses for text replacements / suggestions.
- bumblebritches5 5y agoThat data is actually present in the UCD already.
- cprecioso 5y agoI think it’s just the name data from the Unicode standard? (possibly the CLDR data but I might be wrong)
- bhl 5y agoIt's more than just the CLDR keywords (https://unicode.org/emoji/charts/emoji-list.html https://unicode.org/emoji/charts/emoji-list.html), since text replacement or autocomplete shows up for words not on that list.
- cratermoon 5y agoIs this a plist?
- hellothereworld 5y agoI also found this Dictionary API which imports the dictionaries into NodeJs by utilizing a utility called „dedict“. https://github.com/nikvdp/dictionary-api/blob/master/convertDicts.js https://github.com/nikvdp/dictionary-api/blob/master/convert...
- atorodius 5y agoAuthor here, funny to see this popping up on HN :) Was definitly a fun ride making this.
- LinguaBrowse 5y agoNice read! Just to mention that Core Foundation includes tokenisers (CFStringTokenizer) and lemmatisers (NSLinguisticTagger) of its own in case you ever wanted to avoid the Python processing!
- solarmist 5y agoThanks for sharing this. I've used your article and other previous attempts to clear up the remaining unknown bits of the file format and build apple-peeler, a tool for extracting the XML from the dictionary files. https://github.com/solarmist/apple-peeler https://github.com/solarmist/apple-peeler
- hyperstar 5y agoAt the moment, I'm using a slight modification of the gist plus `sed 's/<[^>]*>//g'` to look up words from the shell on Linux. It would be nice to have some XML parsing into plain text, but it kind of works.
- diimdeep 5y agoUnfortunately it is not possible to implement add-on(add source) to Dictionary.app that is dynamic, like built-in Wikipedia; for example to query urbandictionary.com; only static offline is possible. I tried to investigate this years ago, don't think something changed since then.