MacOS.Applications.MRU

Parse the MRU from MacOS users


name: MacOS.Applications.MRU
description: |
   Parse the MRU from MacOS users

reference:
  - https://mac-alias.readthedocs.io/en/latest/bookmark_fmt.html
  - https://github.com/al45tair/mac_alias
  - https://www.mac4n6.com/blog/2016/7/10/new-script-macmru-most-recently-used-plist-parser

type: CLIENT

parameters:
   - name: FinderPlistPath
     default: /Users/*/Library/Preferences/com.apple.finder.plist

export: |
        -- Parser for MAC Bookmark format
        LET type_lookup <= dict(
           `0x100`="__DataString",
           `0x200`="__DataData",
           `0x300`="__DataUint32",
           `0x400`="__DataDate",
           `0x500`="__DataBool",
           `0x600`="__DataArray",
           `0x700`="__DataDict",
           `0x800`="__DataUUID",
           `0x900`="__DataURL"
           )

        LET MRULookup <= dict(
           `0x2040`="Volume Bookmark",
           `0x2002`="Volume Path",
           `0x2020`="Volume Flags",
           `0x2030`="Volume is Root FS",
           `0x2011`="Volume UUID",
           `0x2012`="Volume Size",
           `0x2013`="Volume Creation Date",
           `0x2005`="Volume URL",
           `0x2040`="Volume Bookmark",
           `0x2050`="Volume Mount Point",
           `0xf080`="Security Extension",
           `0xf081`="Security Extension",
           `0x1004`="Target Path",
           `0x1005`="Target CNID Path",
           `0xc001`="Containing Folder Index",
           `0x1040`="Target Creation Date",
           `0x1010`="Target Flags",
           `0x1020`="Target Filename",
           `0xc011`="Creator Username",
           `0xc012`="Creator UID"
        )

        LET BookmarkProfile = '''[
         ["Header", 0, [
          ["Magic", 0, "String", {
              length: 4,
          }],
          ["Size", 4, "uint32"],
          ["HeaderSize", 12, "uint32"],
          ["TOCOffset", "x=>x.HeaderSize", "uint32"],
          ["TOC", "x=>x.TOCOffset + x.HeaderSize", "TOC"]
         ]],
         ["TOC", 0, [
          ["SizeOfTOC", 0, "uint32"],
          ["Magic", 4, "uint32"],
          ["TOCId", 8, "uint32"],
          ["NextTOC", 12, "uint32"],
          ["TOCCount", 16, "uint32"],
          ["Items", 20, "Array", {
              type: "TOCItem",
              count: "x=>x.TOCCount",
          }]
         ]],
         ["__TOCArrayPtr", 4, [
          ["Offset", 0, "uint32"],
          ["Item", 0, "Profile", {
            type: "TOCValue",
            offset: "x=>x.Offset + 48"
           }]
         ]],
         ["TOCValue", 0, [
           ["MyOffset", 0, "Value", {
               value: "x=>x.StartOf",
           }],
           ["length", 0, "uint32"],
           ["subtype", 4, "BitField", {
               type: "uint32",
               start_bit: 0,
               end_bit: 8,
            }],
            ["data_type", 4, "BitField", {
               type: "uint32",
               start_bit: 8,
               end_bit: 32,
            }],
            ["data", 0, "Value", {
               value: "x=>get(item=x, field=get(item=type_lookup, field=format(format='%#x', args=x.data_type)))",
            }],
            ["__DataString", 8, "String", {
               length: "x=>x.length",
               term: "",
            }],
            ["__DataData", 0, "Value", {
               value: "x=>format(format='%x', args=x.__DataStr)",
            }],
            ["__DataDateFloat", 8, "float64be"],
            ["__DataDate", 0, "Value", {
               value: "x=>timestamp(cocoatime=x.__DataDateFloat)",
            }],
            ["__DataUint32", 8, "uint32"],
            ["__DataBool", 0, "Value", {
                value: "x=>if(condition=x.subtype, then=TRUE, else=FALSE)",
            }],
            ["__DataURL", 0, "Value", {
               value: "x=>x.__DataString",
            }],
            ["__DataArrayOffsets", 8, "Array", {
               count: "x=>x.length / 4",
               type: "__TOCArrayPtr"
            }],
            ["__DataArray", 0, "Value", {
               value: "x=>x.__DataArrayOffsets.Item.data",
            }],
         ]],
         ["TOCItem", 12, [
           ["ID", 0, "uint32"],
           ["Offset", 4, "uint32"],
           ["TOCValue", "x=>x.Offset + 48 - x.StartOf", "TOCValue"],
         ]]
        ]
        '''

        LET ParseBookmark(Bookmark) =
           SELECT _value.name AS Name,
                  get(item=MRULookup, field=format(format="%#x", args=ID)) AS Field,
                  format(format="%#x", args=ID) AS FieldID,
                  format(format="%#x", args=TOCValue.data_type) AS data_type,
                  regex_replace(re="__Data", replace="",
                        source=get(item=type_lookup,
                        field=format(format="%#x",
                              args=TOCValue.data_type))) AS type,
                  TOCValue.data AS data

           FROM foreach(row=parse_binary(
                        accessor="data", filename=Bookmark,
                        profile=BookmarkProfile, struct="Header").TOC.Items)

sources:
  - query: |
        -- Parse the Plist file
        SELECT * FROM foreach(row={
          SELECT OSPath FROM glob(globs=FinderPlistPath)
        }, query={
          SELECT * FROM foreach(row={
            SELECT FXRecentFolders FROM plist(file=OSPath)
          }, query={
            SELECT *
            FROM foreach(row=FXRecentFolders, query={
               SELECT *, OSPath
               FROM ParseBookmark(Bookmark=_value.`file-bookmark`)
            })
          })
        })