reading XCode plist

Hello,
while I can read without any problem the plists of several apps, when I try to read Xcode’s plist I get garbage. For instance:

dim f as FolderItem = GetOpenFolderItem("")
if f <> nil then
dim b as BinaryStream = BinaryStream.Open(f,false)
//b.Position = 200
dim s as String = DefineEncoding(b.Read(b.Length), Encodings.utf8)
b = nil
end if

In the debugger, the first lines of s look like this:
bplist00?“a

e !”#$%&&’(#??????????^?_#a#c

I tried setting b.position to 3, 4 ,5 and so on, but I still get garbage.
Removing the encoding and changing lineEndings do not make things better.
Opening the file as textInputStream still results in garbage.
I removed BOM with Kem’s M_string utility, still garbage.
I tried opening the file as xml, but the file is not recognized as valid xml.

Yet, opening the file in TextWrangler, everything looks all right:

<?xml version="1.0" encoding="UTF-8"?>

Suggestions welcome. Thank you.

Plist files are normally stored in a compressed binary format (which is what you are seeing), there are programs such as Apples Plist Editor, XCode, TextWrangler(it seems) and UltraEdit, the can open them and translate to XML format

So PLIST basically have TWO acceptable formats it seems

I see. Therefore, opening them in Xojo, can lead to unpredictable results, as in this particular case.
Thank you, Dave.

Sam Rowlands probably could shed more light on this, but I noticed that, when a program has been signed, the plist is no longer in pure text format.

There are functions in the Cocoa framework to read plist keys.

See http://stackoverflow.com/questions/15213220/how-to-read-and-write-data-on-a-plist-in-objective-c-not-ios-regular-cocoa-fo

You can probably build declares around that.

you could use declares to read the plist using the proper API’s

or use a shell to convert it to the xml format the read the xml format
BUT DON’T CONVERT IT IN PLACE AS YOU MAY BREAK A CODE SIGNATURE

/usr/bin/plutil -o (TEMPORARY FILE path here) (plist file path here)

if its already XML this will do nothing but put it in a temporary location
if its binary it will convert it to xml so you can read it

Thank you all for your suggestions.
I’ll try and see what I can do.

You can direct the output of plutil to stdout by using a - as the output file
/usr/bin/plutil -convert xml1 -o -

or for JSON format
/usr/bin/plutil -convert json -o -

either way you can feed the result of the shell to create a JSONItem or XML object to work with. (I think JSON would be simpler to deal with than xml for plists as they’re all key-value based)

heh … missed the -o - option in the man page
thats handy

On further experimentation, I would avoid using the JSON functionality. It will choke on any plist with a Date field… there seem to be other (undocumented) things it doesn’t like so I would just stick to XML…

Well, the OS X functions in the frameworks will read binary plist automatically as well as xml.

e.g. NewCFObjectMBSFromXML will do it
http://www.monkeybreadsoftware.net/corefoundation-corefoundation-new-method.shtml#15

I use MBS plugins in my app «List My Apps» to read plist files and it works perfect.

Thank you all for the new suggestions.
I’ll see which one works best in my project.

There’s 3 possible formats for a plist file, the current favorite by Apple is the binary format.

I never ever recommend using a third party or extra step involved in the process, unless you control that step. The reason being is that in the early days of OS X, I was using a third party object to handle plists. As the format migrated and the tool didn’t I was left having to spend the time learning how to do it properly, when I didn’t have the time.

Reading a dictionary based plist is easy.

declare function dictionaryWithContentsOfURL lib "Foundation" selector "dictionaryWithContentsOfURL:" ( classRef as Ptr, inURL as Ptr ) as Ptr return dictionaryWithContentsOfURL( NSClassFromString( "NSDictionary" ), inURL )

Similar for creating a plist from a NSDictionary or NSArray.

declare function writeToURL lib "Foundation" selector "writeToURL:atomically:" ( ref as Ptr, urlRef as Ptr, atomically as boolean ) as Boolean return writeToURL( NSObjectRef, inURL, atomically )

However, there are objects that the standard plist format doesn’t handle (I forget which), so it’s better to use “NSKeyedUnarchiver” and “NSKeyedArchiver”.

All of these functions require a good converter between Xojo and NS.

There’s also macoslib, which contains wrappers for all of the property list-related APIs.

@Joe Ranieri [quote]There’s also macoslib , which contains wrappers for all of the property list-related APIs.[/quote]

I had looked into it, but alas, it is beyond my expertise…

Since it’s not clear whether you read a prefs plist or maybe the info.plist, here’s little warning:

It’s not safe to read the plist file directly of any app’s preferences. If it’s some other plist that not’s in the Preferences folder, the above is okay. That’s because, since 10.8 (or something around that time) Apple started using a background process called “cdprefsd” that caches the app’s prefs. So, when an app changes its prefs, it won’t be immediately updated in the plist file.

To read those prefs properly, on all OSX versions, use the CFPreferences functions instead, supplying the the bundle ID of the app whose prefs you want to access.

Do see how this works in a Xojo app, you can download the source code of my Prefs Editor, see http://apps.tempel.org/PrefsEditor/

I read apps’ info.plists.
Thank you for making things clearer.