DHowett / go-plist

A pure Go Apple Property List transcoder
Other
416 stars 97 forks source link

Question/Help: How to parse terminal theme file? #80

Closed assayire closed 1 year ago

assayire commented 1 year ago

Say you have to parse a terminal theme file like this one. Is it possible to parse it using this library?

I tried defining this:

type Theme struct {
    ANSIBlackColor         string `plist:"ANSIBlackColor"`
    ANSIBlueColor          string `plist:"ANSIBlueColor"`
    ANSIBrightBlackColor   string `plist:"ANSIBrightBlackColor"`
    ANSIBrightBlueColor    string `plist:"ANSIBrightBlueColor"`
    ANSIBrightCyanColor    string `plist:"ANSIBrightCyanColor"`
    ANSIBrightGreenColor   string `plist:"ANSIBrightGreenColor"`
    ANSIBrightMagentaColor string `plist:"ANSIBrightMagentaColor"`
    ANSIBrightRedColor     string `plist:"ANSIBrightRedColor"`
    ANSIBrightWhiteColor   string `plist:"ANSIBrightWhiteColor"`
    ANSIBrightYellowColor  string `plist:"ANSIBrightYellowColor"`
    ANSICyanColor          string `plist:"ANSICyanColor"`
    ANSIGreenColor         string `plist:"ANSIGreenColor"`
    ANSIMagentaColor       string `plist:"ANSIMagentaColor"`
    ANSIRedColor           string `plist:"ANSIRedColor"`
    ANSIWhiteColor         string `plist:"ANSIWhiteColor"`
    ANSIYellowColor        string `plist:"ANSIYellowColor"`
    BackgroundColor        string `plist:"BackgroundColor"`
    CursorColor            string `plist:"CursorColor"`
    ProfileCurrentVersion  string `plist:"ProfileCurrentVersion"`
    SelectionColor         string `plist:"SelectionColor"`
    TextBoldColor          string `plist:"TextBoldColor"`
    TextColor              string `plist:"TextColor"`
}

But whenI try decode I get the following error:

plist: type mismatch: tried to decode plist type `data' into value of type `string'

I think I understand the error but not sure how to make the library treat data as string or even decode the data to whatever it actually holds.

DHowett commented 1 year ago

Hi there! Sorry for the delay.

Unfortunately, the data inside each key -- ANSIBlackColor, ANSIBlueColor, etc. is an embedded data stream. You will need to use []byte instead of string to access it.

Unfortunately, your problems won't end there. The person who authored these property lists actually embedded smaller, individual property lists inside each value!

There's a tool in this repository that can help you understand the topology of a property list, and also decode property lists that are embedded inside other property lists. That tool is called ply.

As an example, this is what it thinks about one of those terminal color schemes. (I've removed some of the data for brevity!)

$ ply .\Chalkboard.terminal
{
  columnCount: 90
  name: Chalkboard
  rowCount: 50
  type: Window Settings
  ANSIBlackColor: 00000000  62 70 6c 69 73 74 30 30  d4 01 02 03 04 05 06 15  |bplist00........|
                  ... data removed ...
                  000000e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 b6     |................|
  ... more data removed ...
}

Looking at that, you can see that it contains name and type and they're just strings, but that it also contains ANSIBlackColor. It's a bit hard to tell from here, but it uses a hex dump display format to show that it's just a []byte.

Looking at the contents of ANSIBlackColor further, you can see it starts with bplist00. That's a binary property list!

ply can help you look inside it, with the ! operator.

$ ply .\Chalkboard.terminal -k "ANSIBlackColor!"
{
  $archiver: NSKeyedArchiver
  $objects: (
              [0]: $null
              [1]: {
                     $class: #2
                     NSColorSpace: 2
                     NSRGB: 00000000  30 20 30 20 30 00                                 |0 0 0...........|
                   }
              [2]: {
                     $classes: (
                                 [0]: NSColor
                                 [1]: NSObject
                               )
                     $classname: NSColor
                   }
            )
  $top: {
          root: #1
        }
  $version: 100000
}

It turns out that it's an archived instance of NSColor. That's getting pretty deep into the weeds.

Unfortunately, these files aren't very good for the go-plist library. They work, and you can parse them, but they are serialized versions of objects from Apple's Objective-C frameworks. The internal layout of each one may be different, and I haven't yet written a library to "unarchive" them further than you can see above. :(

Hope that helps!