Hubbry Logo
Property listProperty listMain
Open search
Property list
Community hub
Property list
logo
7 pages, 0 posts
0 subscribers
Be the first to start a discussion here.
Be the first to start a discussion here.
Property list
Property list
from Wikipedia

Property List
Filename extension
.plist
Internet media type
application/x-plist
Uniform Type Identifier (UTI)com.apple.property-list
Developed byApple Computer and GNUstep,
formerly NeXT
Type of formatSerialization of dictionary objects.

In the macOS, iOS, NeXTSTEP, and GNUstep programming frameworks, property list files are files that store serialized objects. Property list files use the filename extension .plist, and thus are often referred to as p-list files.

Property list files are often used to store a user's settings. They are also used to store information about bundles and applications, a task served by the resource fork in the old Mac OS.

Property lists are also used for localization strings for development. These files use the .strings or .stringsdict extensions. The former is a "reduced" old-style plist containing only one dictionary without the braces (see propertyListFromStringsFileFormat),[1] while the latter is a fully fledged plist. Xcode also uses a .pbxproj extension for old-style plists used as project files.

Representations

[edit]

Since the data represented by property lists is somewhat abstract, the underlying file format can be implemented many ways. Namely, NeXTSTEP used one format to represent a property list, and the subsequent GNUstep and macOS frameworks introduced differing formats.

NeXTSTEP

[edit]

Under NeXTSTEP, property lists were designed to be human-readable and edited by hand, serialized to ASCII in a syntax somewhat like a programming language. This same format was used by OPENSTEP.

  • Strings are represented in C literal style: "This is a plist string\n"; simpler, unquoted strings are allowed as long as they consist of alphanumericals and one of _$+/:.-.
  • Binary data are represented as: < [hexadecimal codes in ASCII] >. Spaces and comments between paired hex-codes are ignored.
  • Arrays are represented as: ( "1", "2", "3" ). Trailing commas are tolerated.
  • Dictionaries are represented as: { "key" = "value"; ... }. The left-hand side must be a string, but it can be unquoted.
  • Comments are allowed as: /* This is a comment */ and // This is a line comment.
  • As in C, whitespace are generally insignificant to syntax. Value statements terminate by a semicolon.

One limitation of the original NeXT property list format is that it could not represent an NSValue (number, Boolean, etc.) object. As a result, these values would have to be converted to string, and "fuzzily" recovered by the application.[2] Another limitation is that there is no official 8-bit encoding defined.[3]

The defaults utility, introduced in OPENSTEP (1996), can be used to manipulate plist files used for storage of preferences (known as defaults in NeXTSTEP, hence the name) on the command line via their preferences domain, and this utility can be used to edit arbitrary plist files. This utility superseded three older commands (dread, dwrite, and dremove).[4]

GNUstep

[edit]

GNUstep adopts the NeXTSTEP format, with additions for representing NSValue and NSDate data types. The new typed entries have the form <*T...>, where T is a one-letter type code. For example, an NSValue of Boolean YES is represented as <*BY> and NSDate objects are represented as <*DYYYY-MM-DD HH:MM:SS +ZZZZ>.[5][6] Binary data can also use the more efficient base64 format as <[ b64... ]>. The 8-bit problem is implicitly solved as well, as most deployments use UTF-8.

GNUstep also has its own binary format, NSPropertyListGNUstepBinaryFormat, implemented in NSSerialization. This format is defined recursively like the textual formats, with a single-byte type marker preceding some data. A form of string interning is supported via a GS-extension shouldBeCompact switch.[7]

Two relative independent plist handlers are found in GNUstep: the CFPropertyList in libs-core-base (CoreFoundation), and the NSPropertyList in libs-base (Foundation Kit). Both support the binary and XML forms used by macOS to some degree, but the latter is a lot more complete. For example, the two GNUstep-specific formats are only handled in the latter.[8]

GNUstep provides a set of plist command-line tools based on NSPropertyList, including a version of pl[9] and defaults.[4]

macOS

[edit]

While macOS can also read the NeXTSTEP format, Apple sets it aside in favor of two new formats of its own, one XML-based and the other binary. Apple also has a partially-compatible JSON format (NSJSONSerialization).

History

[edit]

In Mac OS X 10.0, the NeXTSTEP format was deprecated, and a new XML format was introduced, with a public DTD defined by Apple. The XML format supports non-ASCII characters and storing NSValue objects (which, unlike GNUstep's ASCII property list format, Apple's ASCII property list format does not support).[10]

Since XML files, however, are not the most space-efficient means of storage, Mac OS X 10.2 introduced a new format where property list files are stored as binary files. Starting with Mac OS X 10.4, this is the default format for preference files. In Mac OS X 10.7, support for reading and writing files in JSON format was introduced. JSON and property lists are not fully compatible with each other, though. For example, property lists have native date and data types, which the JSON format does not support. Conversely, JSON permits null values while property lists do not support explicit nulls.

Tooling

[edit]

The old defaults tool from NeXTSTEP remains available. The /usr/libexec/PlistBuddy command provides an interactive plist editor. It can also be scripted.[11]

The plutil utility (introduced in Mac OS X 10.2) can be used to check the syntax of property lists, or convert a property list file from one format to another. It also supports converting plists to Objective-C or Swift object literals.[12] Like the Cocoa NSPropertyListSerialization it is built on, it takes "old-style" inputs, but does not convert to this type. (The Cocoa NSSerializer from before Mac OS X 10.2 emits old-styled output.)

The pl utility is introduced in Mac OS X v10.5. It takes any input and tries to generate "old-style" plists.[13][a] Like the GNUstep version, it appears to use the description property of Foundation types found in plists, which Apple has specified to produce valid old-style plists.[b]

In terms of the internals, Apple provides an open source parser for old style, XML, and binary formats in their C Core Foundation code as CFPropertyList. However, all the utilities and most parts of the system use the closed-source NSPropertyList parser from the Obj-C Foundation Kit. The Swift reimplementation is open source, but is not guaranteed to be identical.

Format

[edit]

XML and JSON property lists are hand-editable in any text editor. Additionally, Apple provides support in Xcode for editing property lists in a hierarchical viewer/editor that can handle plists formatted in binary or XML, but not JSON. As of Mac OS X 10.4, Apple provides an AppleScript interface for reading property list files through the System Events application. As of Mac OS X 10.5, Apple provides an AppleScript interface for editing, creating and writing property list files as well.[14]

For the XML format, the tags, related Foundation classes and CoreFoundation types, and data storage formats are as follows:

Foundation class CoreFoundation type XML Tag Storage format
NSString CFString <string> UTF-8 encoded string
NSNumber CFNumber <real>, <integer> Decimal string; reals can have exponents, or be Infinity (inf) or NaN (nan).
NSNumber CFBoolean <true/>, <false/> No data (tag only)
NSDate CFDate <date> ISO 8601 formatted string
NSData CFData <data> Base64 encoded data
NSArray CFArray <array> Can contain any number of child elements. Can be empty.
NSDictionary CFDictionary <dict> Alternating <key> tags and plist element tags. Can be empty.

The binary file format is documented in a comment block in the Core Foundation C code source file (CF/CFBinaryPList.c) for Apple's open sourced implementation of binary plists in its Foundation library.[15] Apple describes the implementation as opaque in its plist(5) manual page documentation,[16] which means that reliance on the format is discouraged. In the binary file format the magic number (the first few bytes of the file which indicate that it's a valid plist file) is the text bplist, followed by two bytes indicating the version of the format.

The binary file can store some information that cannot be captured in the XML or JSON file formats. The array, set and dictionary binary types are made up of pointers - the objref and keyref entries - that index into an object table in the file. This means that binary plists can capture the fact that - for example - a separate array and dictionary serialized into a file both have the same data element stored in them. This cannot be captured in an XML file. Converting such a binary file will result in a copy of the data element being placed into the XML file. Additionally the binary file has a UID type that is used to identify data items when serialized. The complete list of data that can be stored taken from the C code source file is as follows:

Binary plist object formats (as of CoreFoundation 1153)[15]
Foundation class CoreFoundation type Object type Marker byte Encoded data
nil nil null (v"1?"+) 0000 0000
NSNumber CFBoolean bool 0000 1000 (false)
0000 1001 (true)
NSURL CFURL url (v"1?"+) 0000 1100 (base string)
0000 1101 (string)
string: URL string in recursive encoding (as in "string object format?"); base string: the same, but with a base URL encoded first.
NSUUID CFUUID uuid (v"1?"+) 0000 1110 16 bytes of UUID
fill 0000 1111 nothing - just a padding
NSNumber CFNumber int 0001 nnnn # of bytes is 2^nnnn, big-endian bytes (1, 2, 4, or 8)
NSNumber CFNumber real 0010 nnnn # of bytes is 2^nnnn, big-endian bytes (4 or 8)
NSDate CFDate date 0011 0011 8 byte float follows, big-endian bytes; seconds from 1/1/2001 (Core Data epoch)
NSData CFData data 0100 nnnn [int] nnnn is number of bytes unless 1111 then int count follows, followed by bytes
NSString CFString string 0101 nnnn [int] ASCII string, nnnn is # of chars, else 1111 then int count, then bytes
NSString CFString string 0110 nnnn [int] Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t
NSString CFString string (v"1?"+) 0111 nnnn [int] UTF-8 string, nnnn is # of chars, else 1111 then int count, then bytes
UID 1000 nnnn nnnn+1 is # of big-endian bytes (1, 2, 4, or 8). Unsigned int, only produced by NSKeyedArchiver (see below).[17]
NSArray CFArray array 1010 nnnn [int] objref* nnnn is count, unless '1111', then int count follows
NSOrderedSet ordset (v"1?"+) 1011 nnnn [int] objref* nnnn is count, unless '1111', then int count follows
NSSet CFSet set (v"1?"+) 1100 nnnn [int] objref* nnnn is count, unless '1111', then int count follows
NSDictionary CFDictionary dict 1101 nnnn [int] keyref* objref* nnnn is count, unless '1111', then int count follo

Note the v"1?"+ note in many types. This means that the marker byte is only found in files with a format version no lower than the "1?" magic number. The precise way to parse them is more nebulous than the way to parse legacy types, since the CFBinaryPlist implementation only handles version "0?". In practice, these types are never encountered, since NSKeyedArchiver is already capable of capturing these information.

A table of offsets follow the object table, which is then followed by a trailer containing information on the size and location of the two tables.

Serializing to plist

[edit]

Since property lists do not capture all the information and data types required to describe an arbitrary object, an extra layer of encoding and decoding is often done. The OpenStep specification abstracts the operation of serializing any NSObject under the NSCoding protocol. Any class implementing this protocol can have its instances serialized by a NSCoder subclass to some other format.[18] Two main coders exist for the purpose of serializing objects to plists:

  • NSArchiver, which converts an object into a block of binary data somewhat like a tagged struct. This class is part of OpenStep, although no concrete format has been defined. In practice, one can use it to serialize an object to a file (skipping the plist), or to embed the data in a plist. It must be read and written in the same order as written. The introduction of NSKeyedArchiver deprecates its use.
  • NSKeyedArchiver, introduced in Mac OS X 10.2, transforms the object into an NSDictionary. The main improvement of this format for programmers is that it accesses members not by a fixed order, but by string keys. Internally, it somewhat recapitulates the binary plist format by storing an object table array called $objects in the dictionary. Everything else, including class information, is referenced by a UID pointer. A $top entry under the dict points to the top-level object the programmer was meaning to encode.[17]

Among other things, using an archiver allows for new datatypes to be encoded without changing the plist format itself and it is the preferred way for Apple to encode things like NSSets and null values. Parsing the formats do prove a bit harder, since one more layer must be followed even for some classes plists were supposed to support. Like the binary format which also has an object table, it is possible to create circular references in NSKeyedArchiver. Since there is not a UID data type in XML, the integers are stored in a dictionary under the key "CF$UID".[19]

Apple publishes an open-source NSKeyedArchiver in Swift Corelibs Foundation; like the closed-source Apple Foundation, it restricts output formats to binary and XML only. It also has some test cases showing the results of serialization.[20] GNUstep also has a compatible implementation, which does not limit output formats.[21]

Path language

[edit]

There is not a single, standardized path language for property lists like XPath does for XML, but informal conventions used by various programs exist.

  • A dot syntax version is found in the keypath argument of Apple's plutil. It appears to derive from (id) -[NSObject(NSKeyValueCoding) valueForKeyPath:].[12]
  • A different format is used by PlistBuddy, with a colon syntax for indexing.[11]

Neither format is able to express a key with the separator character in it.

Other platforms

[edit]

Windows

[edit]

Although best known on Apple or Darwin systems, including iOS and macOS, plist files are also present on Windows computers when Apple software, such as iTunes[22] or Safari[23] are installed. On Windows, the files are typically binary files,[24] although some applications may generate PLIST files in the other formats.

On Windows the Apple plist files are stored in the user's home directory under %USERPROFILE%\AppData\Roaming\Apple Computer. These plist files on Windows typically store preferences and other information, rather than using the Windows registry.

Options for editing PLIST files on Windows are not as extensive as on macOS. If the file is in the XML or JSON format with care a text editor such as Notepad++ can be used. Apple ships a plutil.exe within its "Apple Application Support" package (which is part of iTunes), and it is identical to its macOS counterpart.

NetBSD

[edit]

Introduced in 2006 and first released with NetBSD#4.0 (2007) is a proplib library, which can be used for serialising data between the kernel and userland. It implements part of the XML plist language.[25]

One of the sample users of proplib is the second revision of the sysmon envsys framework for system monitoring.

NetBSD's proplib library has also been ported to DragonFly in 2010, and is available since DragonFly BSD#2.8.[26]

Cross-platform

[edit]
  • Facebook's open-source reimplementation of the Xcode build tool, xcbuild, contains a plist library as well as plutil and PlistBuddy. These cross-platform utilities are written in C++.[27]
  • Python has a builtin plistlib module to read and write plist files, in Apple's XML or in binary (since Python 3.4).[28] ProperTree is a cross-platform editor that makes use of this library.[29]
    • A third-party library called ccl-bplist has the additional ability to handle NSKeyedArchiver UIDs.[19]
  • Go has a plist package that supports four types of plists: OpenStep text, GNUStep text, Apple XML, and Apple Binary. It also handles UIDs in XML and binary formats.[2]
  • Dart has a third party library called propertylistserialization[30] which also handles NSKeyedArchiver UIDs.

See also

[edit]

Notes

[edit]

References

[edit]
[edit]
Revisions and contributorsEdit on WikipediaRead on Wikipedia
from Grokipedia
A property list, often abbreviated as plist, is a standardized originating from the operating system and widely used in Apple ecosystems such as macOS and for serializing structured data in a hierarchical manner. It supports basic data types including strings, numbers, booleans, dates, , arrays, and , with the root element typically being a dictionary. Property lists serve as a versatile serialization mechanism for configuration settings, application metadata, and preferences, enabling efficient storage and exchange of information between applications and the operating system. They can be represented in multiple formats: an XML-based textual form for human readability, a compact binary format for performance, or occasionally , with the .plist file extension. In Apple development, the most prominent example is the Info.plist file, which provides essential bundle information like version numbers, permissions, and supported orientations for apps, frameworks, and plug-ins. This format's design emphasizes simplicity and portability, allowing tools like to generate and edit them automatically while supporting localization and platform-specific customizations. Beyond Apple platforms, property lists have influenced similar structured data formats in other systems, underscoring their role in modern software configuration.

Overview

Definition and Purpose

A property list, often abbreviated as plist, is a standardized data serialization format in Apple's operating systems that represents a hierarchy of simple objects, enabling easy storage, transmission, and reconstruction of structured data. It serves as a lightweight mechanism for persisting small amounts of data—typically under a few hundred kilobytes—in a platform-independent manner, integrated natively with Core Foundation and Foundation frameworks. At its core, a property list comprises basic object types including strings (NSString/CFString), numbers (NSNumber/CFNumber, encompassing integers, floats, and booleans), dates (NSDate/CFDate), binary data blobs (NSData/CFData), (NSArray/CFArray of property list objects), and (NSDictionary/CFDictionary mapping keys to property list values). These elements can be nested arbitrarily to create complex structures, such as a dictionary containing an array of date-number pairs, ensuring the entire remains serializable without loss of type information. In the , property lists are predominantly used for application preferences, where user settings are saved in files like com.example.app.plist; bundle metadata in Info.plist files, which detail executable configurations such as version numbers and permissions; launch configurations for daemons and agents via .plist; and serializing transient objects for or caching. This format's simplicity and efficiency make it ideal for these roles, supporting quick reads and writes without requiring a full database. Compared to or , property lists provide enhanced through native support for dates and —avoiding the need to encode them as strings, which can lead to parsing ambiguities—while offering tighter integration with Apple's APIs via classes like NSPropertyListSerialization, unlike the more generic handling required for . Property lists can be serialized in human-readable XML or efficient binary formats. For illustration, a basic XML property list with a simple key-value pair appears as:

xml

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>UserName</key> <string>Alice</string> </dict> </plist>

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>UserName</key> <string>Alice</string> </dict> </plist>

A nested structure, such as a dictionary containing an array of numbers, is:

xml

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Scores</key> <array> <real>95.5</real> <integer>88</integer> </array> </dict> </plist>

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Scores</key> <array> <real>95.5</real> <integer>88</integer> </array> </dict> </plist>

These examples use standard XML tags like <dict>, <key>, <string>, <array>, <real>, and <integer> to denote structure and types.

Historical Development

Property lists were first introduced as a foundational data structure in NeXTSTEP, the object-oriented operating system developed by NeXT and released in 1988, where they served as a mechanism for serializing and persisting hierarchical objects such as arrays and dictionaries. Designed initially for human-readable ASCII serialization, they enabled developers to store application settings and bundle information in a lightweight, portable format compatible with the system's Foundation framework. In 1994, property lists evolved through the specification, a collaborative standard between NeXT and that standardized the Application Kit and Foundation Kit APIs for cross-platform portability. This transition emphasized architecture-independent using classes like NSSerializer and NSDeserializer, restricting supported types to NSData, NSString, NSArray, and NSDictionary to ensure consistency in archiving and data transfer across environments. The format, an ASCII-based property list inherited by later systems, became a core element for user defaults management via NSUserDefaults and inter-application data exchange. Following Apple's acquisition of NeXT in 1997, property lists were integrated into Mac OS X (later renamed macOS) with its debut in 2001, building directly on the and OPENSTEP heritage to form the basis of Cocoa's data persistence layer. A significant efficiency enhancement came in 2002 with Mac OS X 10.2 (), which introduced the binary property list format alongside the existing XML and ASCII options, allowing for more compact storage and faster read/write operations while maintaining lossless conversion between formats. Property lists expanded into mobile development with the launch of in 2007, where they became essential for app configuration through files like Info.plist, which describe bundle metadata, permissions, and supported features to the system. This adoption ensured consistency between macOS and iOS ecosystems, leveraging the same APIs for preferences and runtime data. Key milestones in the 2010s included the deprecation of the legacy ASCII OPENSTEP format for writing—retained only for reading older files—and deeper integration with Swift, introduced in 2014, via the PropertyListSerialization class in the Foundation framework. This allowed Swift developers to encode and decode property lists natively, supporting modern type-safe handling of arrays, dictionaries, and primitive values without relying on Objective-C bridges.

Data Formats

XML Representation

The XML representation of a property list is a human-readable, structured format based on the Extensible Markup Language (XML), designed for storing serialized collections of key-value pairs and arrays in Apple ecosystems. It adheres to a specific (DTD) that defines the allowable elements and their hierarchies, ensuring consistency and parseability. The root element is always <plist>, which encapsulates either a <dict> () or <array> as the top-level object, with all content encoded in for support. The DTD schema specifies the following core elements: <dict> for dictionaries, which contain zero or more pairs consisting of a <key> element (containing parsed character data for the key ) followed immediately by a value object; <array> for ordered lists, containing zero or more value objects; <string> for text strings (parsed character data); <integer> for signed base-10 integers (parsed character data); <real> for floating-point numbers (parsed character data); <date> for dates in format (YYYY-MM-DDTHH:MM:SSZ, parsed character data); <data> for binary encoded in (parsed character data); and <true/> or <false/> for values (empty elements). All tags are self-closing where empty and contain no attributes except the version attribute on <plist> (fixed to "1.0"). Dictionaries preserve the order of keys as they appear in the XML, facilitating . Property lists in XML format can be validated against Apple's official DTD using standard XML parsers or tools, with the DOCTYPE declaration <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> ensuring compliance. This validation checks for proper nesting, element sequencing (e.g., keys must precede values in dictionaries), and constraints, preventing malformed structures that could lead to parsing errors in applications. For instance, a nested representing application preferences might appear as follows:

xml

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>AppName</key> <string>MyApp</string> <key>Preferences</key> <dict> <key>Theme</key> <string>Dark</string> <key>Volume</key> <integer>80</integer> <key>NotificationsEnabled</key> <true/> </dict> </dict> </plist>

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>AppName</key> <string>MyApp</string> <key>Preferences</key> <dict> <key>Theme</key> <string>Dark</string> <key>Volume</key> <integer>80</integer> <key>NotificationsEnabled</key> <true/> </dict> </dict> </plist>

This example demonstrates a top-level with a key-value, a nested for preferences containing a , an , and a boolean. While the XML format's verbosity results in larger file sizes compared to the binary alternative, it excels in and editability, allowing direct modification in text editors without specialized tools.

Binary Representation

The binary property list (bplist) format is a compact method for structured data, optimized for machine processing in Apple's operating systems. It replaces the human-readable XML representation with a dense byte stream, enabling smaller file sizes and quicker load times, making it the preferred choice for production system files such as Info.plist in macOS and applications. This format adheres to version 1.0, as defined in Apple's Core Foundation implementation. The file structure begins with an 8-byte header: the magic bytes bplist (0x62706c697374) followed by the version 00 (indicating format version 1.0). This is succeeded by the serialized objects section, where data is stored contiguously. An offset table follows, consisting of variable-sized (typically 1-8 byte) entries pointing to the start of each object. The file concludes with a fixed 32-byte trailer containing metadata, including five unused bytes, a sort version (usually 0), offset integer size (e.g., 1 byte), object reference size (e.g., 1 byte), the total number of objects (as a 64-bit integer), the UID of the top-level object, and the offset to the table itself. These elements allow efficient random access to objects during parsing. Objects are referenced via unique identifiers (UIDs), which are indices into the offset table, promoting deduplication and for repeated values. Each object begins with a type specifier byte, where the high 4 bits denote the and the low 4 bits handle inline sizes for small s. Simple types include: 0x00 for null; 0x08 (false) and 0x09 (true) for booleans; 0x10 to 0x1F for (signed, big-endian, payload size 2^{low 4 bits} bytes if low 4 bits < 15, or length-prefixed if 0x1F); 0x80 to 0x8F for UIDs (size ( + 1) bytes). For larger or variable-sized data, the low 4 bits are set to 0xF, followed by a separate (1-8 bytes) preceding the payload. Strings use 0x50-0x5F for ASCII (0-15 bytes inline) or 0x60-0x6F for UTF-16; real numbers (doubles) are 0x20-0x23 (4- or 8-byte ); dates are 0x33 (8-byte double offset from 2001-01-01T00:00:00Z). Collections like arrays (0xA0-0xAF), sets (0xC0-0xCF), and dictionaries (0xD0-0xDF) specify count inline or via length integer, followed by reference UIDs to constituent objects (for arrays/sets) or key-value pairs (for dictionaries, with keys first). Data blobs (0x40-0x4F) follow similar length-prefixed patterns. This packing ensures small primitives are embedded directly, while larger or shared elements are referenced to minimize redundancy. The format's design yields significant efficiency gains: binary plists are much more compact than XML equivalents—often up to 50% smaller for complex structures—reducing storage needs and network transfer overhead, while parsing is faster due to the lack of text decoding and direct byte access. These benefits are evident in system usage, where binary plists power critical components like application bundles and preferences without the overhead of XML verbosity. Unlike XML plists, the binary variant avoids vulnerabilities inherent to XML processing, such as XML External Entity (XXE) attacks, through its rigid, non-parsable structure and strict byte-level validation. For illustration, consider a simple dictionary {"Disabled": true} from a launch daemon configuration (e.g., similar to telnet.plist). A valid binary structure (simplified; actual varies with padding and table entries) based on the format specification is as follows:
  • Header: 62 70 6c 69 73 74 00 00 (bplist00)
  • Objects section (offsets via table at end):
    • Dictionary object (UID 0, e.g., at offset 8): D1 01 09 (dict with 1 pair; key ref 0x01 to UID 1 string; value 0x09 true, assuming true as simple object UID 0 shared or adjusted)
    • String object (UID 1, e.g., at offset 11): 58 44 69 73 61 62 6c 65 64 (ASCII string, 8 chars: "Disabled")
  • Offset table (e.g., 1-byte offsets): 08 0B (offsets to dict at 8 and string at 11)
  • Trailer (32 bytes, simplified): 00 00 00 00 00 00 01 01 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 (metadata for 2 objects, top UID 0, table offset 19 decimal; exact bytes depend on positions)
This breakdown highlights how references (e.g., 0x01 for the key) and inline encoding keep the total size minimal compared to the XML equivalent (<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>Disabled</key><true/></dict></plist>).

System Integrations

NeXTSTEP Implementation

In , the operating system developed by from 1988 to 1997, property lists served as a core mechanism for archiving and persisting objects through the NSArchiver class, which serialized compatible objects into human-readable .plist files. This approach enabled developers to store structured data such as user preferences and application states in a lightweight, editable format, integral to the Foundation framework's object management. Property lists provided native support in for key development tools, forming the basis for archives that saved designs as .nib files—essentially archived collections of objects like windows, menus, and controls. They also handled application resources, allowing seamless integration of configuration data within bundles. Central to this were property list-compatible classes such as NSDictionary for key-value storage and NSArray for ordered collections, which supported direct via the writeToFile:atomically: method to output ASCII-formatted .plist files. A distinctive feature of property lists in early implementations was their use on the original black-and-white NeXT hardware, such as the (1988) and (1990), for system configuration files in a simple, text-based structure. NSArchiver facilitated this by encoding objects into portable archives, ensuring compatibility across the platform's object-oriented environment. The property list design laid the groundwork for the standard released in 1994, providing a standardized that influenced later evolutions in systems like macOS.

GNUstep Implementation

GNUstep, initiated in 1994 as an open-source implementation of the OpenStep specification, provides a faithful recreation of NeXTSTEP's APIs, including comprehensive support for property lists within its Foundation framework (also known as the Base library). This support enables developers to serialize and deserialize objects such as strings, numbers, dates, data, arrays, and dictionaries into human-readable formats (ASCII and XML), mirroring the original NeXTSTEP behavior while extending it for cross-platform use on Unix-like systems. The core functionality is handled by the NSPropertyListSerialization class, which facilitates reading and writing property lists in multiple formats, including XML (conforming to Apple's plist DTD) and the legacy ASCII format for backward compatibility. ensures legal XML output by using standard XML escaping (e.g., entity references), prioritizing standards compliance over exact replication in edge cases. This class supports validation to confirm that conforms to property list before , preventing errors in application configuration or data storage. Distinct from proprietary NeXT implementations, GNUstep leverages open-source tooling such as GNUstep-make, the project's build system, to automate the generation of property list files like Info-gnustep.plist for application bundles, which define metadata such as names, resource paths, and document types. These tools integrate seamlessly with GNUstep applications deployed on platforms including and , allowing property lists to manage preferences, bundle information, and without platform-specific adjustments. Community-driven enhancements have expanded property list capabilities to include additional object types, such as NSURL for handling uniform resource identifiers as serializable strings or data. Furthermore, integration with tools like GORM (GNUstep Object Relationship Modeler) utilizes property lists to archive user interface designs and object relationships, enabling developers to map graphical elements to application logic stored in plist-based files.

macOS and iOS Implementation

In macOS and iOS, property lists serve as a core component of application bundles, with the Info.plist file being mandatory for all runnable code bundles to specify essential metadata such as the bundle identifier, version number, supported orientations, and document types. This file is stored at the of iOS app bundles and within the Contents directory of macOS app bundles, enabling the operating system to interpret and launch applications correctly. Entitlements, implemented as separate property list files (typically named entitlements.plist), grant specific capabilities to apps, such as access to the camera, location services, or , and are embedded during the process to enforce runtime permissions. User defaults, managed through the NSUserDefaults class, store application preferences and settings in property list format, allowing persistent, key-value data storage within the app's sandboxed Library/Preferences directory on both platforms. On , property lists extend to sandboxed app environments, where entitlements property lists define the boundaries of access, network permissions, and to maintain app isolation. System-level configurations, including those for —the iOS home screen manager—rely on property lists to store user customizations like icon arrangements and wallpaper settings, typically in binary format for efficiency. Privacy manifests, introduced as property lists in , require developers to document data collection practices for apps and embedded third-party SDKs, including reasons for accessing sensitive APIs and whether data is used for tracking, enhancing transparency in the review process. Security features in macOS and integrate property lists with mechanisms, where provisioning profiles—a type of signed property list wrapped in (CMS)—validate app authenticity and embedded entitlements during installation and launch. The hardened runtime, enabled by default in signed apps since macOS 10.12 and , employs hashes to protect bundle resources and metadata, including property lists, from unauthorized tampering by verifying integrity against runtime modifications. These protections extend to dynamic library validation, ensuring that linked components adhere to the signed property list declarations. Evolving from their roots in , property lists in modern Apple operating systems continue to favor binary and XML formats via the PropertyListSerialization class for serialization and deserialization, though JSON alternatives exist through JSONSerialization for simpler data exchange; binary property lists remain preferred for their compactness and legacy compatibility in system and app configurations. Mac Catalyst, Apple's framework for porting apps to macOS, leverages unified property list structures to bridge the platforms, allowing shared Info.plist and entitlements files to handle cross-platform bundle identification and permissions seamlessly.

Tools and Manipulation

Command-Line Utilities

The primary command-line utility for managing property lists on macOS and is plutil, which supports operations such as syntax validation, format conversion between XML, binary, and , expansion of macros, and merging of multiple files. For instance, the -lint option checks a plist for validity and reports errors like "Unexpected character < at line 1" for malformed XML, while -convert xml1 or -convert binary1 transforms files between formats, preserving data integrity. Additional subcommands include -expand to resolve variable substitutions and -merge to combine plists, with detailed error reporting aiding debugging of structural issues such as invalid keys or type mismatches. Another essential tool is the defaults command, designed specifically for reading, writing, and deleting keys in user defaults databases, which are stored as property lists in ~/Library/Preferences. Common syntax includes defaults write com.example.app key value to set a value (e.g., defaults write com.apple.finder AppleShowAllFiles true to toggle hidden files) and defaults read domain to output the entire plist or defaults read domain key for a specific entry. This utility automatically handles serialization to binary format upon writing, making it suitable for configuring application preferences without direct file manipulation. PlistBuddy is an Apple-provided command-line tool for directly editing property list files, supporting operations like adding, setting, deleting, and querying keys and values using a simple syntax. For example, /usr/libexec/PlistBuddy -c "Add :key string value" file.plist adds a new string entry, while -c "Print :key" retrieves a value, making it useful for scripted modifications without full conversion. It operates on XML or binary plists and provides error messages for invalid paths or types. Open-source alternatives extend plist handling to non-Apple platforms. In GNUstep environments, a port of plutil provides similar functionality for editing, verifying, and converting property lists, integrated into the GNUstep Base library for cross-platform Objective-C development. Best practices for these utilities emphasize their use in shell scripts for automated batch processing, such as validating multiple app configuration plists before deployment: for file in *.plist; do plutil -lint "$file" || echo "Error in $file"; done. For defaults, scripts can standardize user settings across systems, like defaults write -g NSWindowShouldDragOnGesture -bool true piped into deployment tools, ensuring consistency without overwriting unrelated keys. Validation errors from plutil should be logged for auditing, as in plutil -lint config.plist > validation.log 2>&1, to catch issues like duplicate keys early in pipelines. As of macOS 12 Monterey (2021), plutil gained enhanced support, allowing direct conversion with -convert json and extraction of values via -p or -extract, which simplifies integration with modern web APIs and scripting languages. These command-line tools serve as lightweight alternatives to programming interfaces for shell-based automation.

Programming Interfaces

In and the Cocoa frameworks, the NSPropertyListSerialization class in Foundation provides core methods for serializing and deserializing property lists. The +dataWithPropertyList:format:options:error: method converts a property list object—such as an NSArray, NSDictionary, NSString, NSNumber, NSData, or NSDate—into an NSData instance in either XML (NSPropertyListXMLFormat_v1_0) or binary (NSPropertyListBinaryFormat_v1_0) format, with options for controlling mutability (e.g., immutable or mutable containers) and an NSError pointer for detailed error reporting on invalid objects or format issues. Conversely, the +propertyListWithData:options:format:error: method parses NSData to reconstruct the original property list, validating the format and returning nil with an error if the data is malformed or contains unsupported types. In Swift, Foundation introduces PropertyListEncoder and PropertyListDecoder classes starting from iOS 12.0, macOS 10.14, 12.0, and 5.0, enabling integration with the Codable protocol for encoding and decoding custom types as property lists. PropertyListEncoder serializes Encodable objects to in XML or binary formats via the .xml or .binary outputFormatting options, while PropertyListDecoder deserializes into Decodable types, throwing errors for type mismatches or invalid structures. This approach supports complex hierarchies by automatically handling conformance for standard types and allowing custom implementations for user-defined classes. GNUstep's NSPropertyListSerialization class offers equivalent functionality to its Cocoa counterpart, supporting and deserialization in XML and binary formats through similar class methods. It extends compatibility by permitting non-standard types like NSValue and NSURL in property lists, which are converted to NSData or NSString representations during , enabling broader use in open-source environments. For C-based applications, Core Foundation exposes property list handling via functions like CFPropertyListCreateWithData, which constructs a CFPropertyListRef from CFData in specified formats (kCFPropertyListXMLFormat_v1_0 or kCFPropertyListBinaryFormat_v1_0), returning NULL and populating a CFError on parsing failures such as invalid or unknown object types. Companion functions like CFPropertyListCreateXMLData and CFPropertyListCreateData handle writing, with options for mutability to optimize memory usage in performance-critical scenarios. When processing large property lists, is crucial, as deserialization can create deep object graphs that consume substantial heap space; developers should use autorelease pools in or monitor allocations in Swift to avoid excessive footprint. The serialization methods in NSPropertyListSerialization and Core Foundation are inherently thread-safe due to their stateless class-based design, but applications must synchronize access to shared mutable property list instances in multi-threaded contexts to prevent data races.

Advanced Features

Serialization Process

The serialization process for property lists involves converting an object graph composed of supported Foundation types into a serialized byte stream, typically in XML or binary format, while ensuring the graph adheres to strict validity rules. Before serialization, the input object must be validated to confirm it forms a valid property list graph: this includes verifying that the graph is acyclic (no circular references), contains only supported types such as NSString, NSNumber, NSData, NSDate, NSArray, and NSDictionary, and that all dictionary keys are strings. If validation fails, methods return nil and provide an error description, such as for unsupported custom objects, which cannot be directly serialized and instead require archiving via NSKeyedArchiver to preserve class identity and additional state. Once validated, the developer selects a format—XML for human-readable output or binary for compactness—and invokes the appropriate method on NSPropertyListSerialization or its Core Foundation equivalent to write the data to a stream or file. The process recursively traverses the object graph, encoding each element according to the chosen format's structure; for instance, binary serialization uses a compact, length-prefixed representation to minimize size. To mitigate risks like stack overflows from deeply nested structures, implementations impose practical recursion depth limits, though no fixed universal limit is enforced—excessive depth may trigger runtime errors depending on the system's stack size. Deserialization reverses this by the byte stream back into native objects, with options for mutability (immutable for or mutable for editing). includes basic error recovery, such as halting on malformed and returning partial results if possible, but plists maintain strict typing without automatic between types like strings and numbers—mismatched types result in nil or exceptions. Developers must handle errors explicitly, checking return values and error pointers to ensure integrity. For optimization, binary format is recommended for large datasets due to its smaller footprint and faster read/write speeds compared to XML; additionally, large NSData blobs within plists can be compressed externally using methods like NSData compression before serialization. A typical workflow in Objective-C for serializing a dictionary might proceed as follows:

objective

NSDictionary *dict = @{@"key": @"value"}; NSError *error = nil; NSData *serializedData = [NSPropertyListSerialization dataWithPropertyList:dict format:NSPropertyListBinaryFormat_v1_0 options:0 error:&error]; if (serializedData && !error) { // Write to file or stream [serializedData writeToFile:@"example.plist" atomically:YES]; } else { NSLog(@"Serialization failed: %@", error.localizedDescription); }

NSDictionary *dict = @{@"key": @"value"}; NSError *error = nil; NSData *serializedData = [NSPropertyListSerialization dataWithPropertyList:dict format:NSPropertyListBinaryFormat_v1_0 options:0 error:&error]; if (serializedData && !error) { // Write to file or stream [serializedData writeToFile:@"example.plist" atomically:YES]; } else { NSLog(@"Serialization failed: %@", error.localizedDescription); }

Deserialization would then use propertyListWithData:options:format:error: to reconstruct the dictionary, specifying the expected format if known.

Path Expression Language

The path expression language for property lists leverages Key-Value Coding (KVC) key paths, enabling navigation through nested structures in dictionaries and arrays using string-based expressions. This syntax allows developers to access, query, and perform operations on property list data via APIs such as valueForKeyPath: on NSDictionary and NSArray objects, which are the foundational types for property lists in Apple's frameworks. Basic navigation employs dot notation to traverse dictionary keys, such as root.key.subkey, where each segment specifies a successive dictionary key. For arrays, access to specific elements uses indexed notation like array[0] in supported contexts, though in command-line tools like plutil, this may appear as array.0 to denote the zero-based index of the element. Advanced expressions incorporate collection operators prefixed with @ to aggregate or transform data across array elements, providing functionality beyond simple traversal. For instance, @count returns the number of items in a collection (e.g., children.@count yields the count of child objects), while @sum computes the total of numeric values for a specified property (e.g., [email protected] sums all amount values in the transactions array). Other operators include @avg for averages, @min and @max for extrema, @distinctUnionOfObjects for unique values, and @unionOfObjects for all values including duplicates; these require a right key path following the operator to specify the target property. Wildcards (*) can be used in some API contexts to match multiple keys or elements, and ranges (e.g., [0:5]) may denote subsets of arrays, though support varies by implementation. These operators apply directly to property list structures, as NSDictionary and NSArray conform to KVC protocols. In usage contexts, path expressions are integral to command-line tools and scripting. The defaults command supports basic key paths for reading user defaults (e.g., defaults read com.example.app root.key.subkey), which query property lists stored in the defaults system. For more complex extraction from arbitrary plist files, plutil -extract path raw file.plist uses KVC-style paths to output values, such as plutil -extract preferences.[window](/page/Window).[size](/page/Size) file.plist to retrieve a nested size value. In programming interfaces like Foundation's NSUserDefaults or Core Foundation's CFPreferences, paths enable scripted queries, for example, retrieving aggregated app preferences: let sum = dictionary.value(forKeyPath: "[email protected]") as? Double. These tools facilitate automation in shell scripts or apps without loading entire plists into memory. Limitations of this language include its read-only nature in many contexts, as KVC paths via valueForKeyPath: do not support creation or modification—use setValue:forKeyPath: separately for writes. It lacks full support for complex filters like [?value>10] seen in or JSONPath, relying instead on separate NSPredicate objects for conditional queries (e.g., filtering arrays before applying paths). Invalid paths typically return nil or raise an NSUndefinedKeyException, requiring error handling via try-catch blocks in code or exit codes in tools (e.g., plutil returns non-zero on failure). Compared to or JSONPath, KVC paths prioritize /Swift integration over standalone querying, omitting advanced recursion or regex but excelling in collection aggregations for plist data. For example, to query nested app preferences in a plist representing user settings, a path like appPreferences.screens.@[count](/page/Count) could available screen configurations, while [email protected] extracts unique file names from a recent-files . If the path is invalid, such as referencing a non-existent subkey, APIs log an exception, and tools like plutil output an error message like "Unexpected character 0 at line 1," prompting verification of the plist structure.

Cross-Platform Support

Windows Compatibility

Microsoft Windows lacks native support for property lists, necessitating third-party libraries or tools for parsing and editing them, as the format is specific to Apple ecosystems. For instance, developers can use the PlistAPI NuGet package to serialize and deserialize property lists directly into .NET objects on Windows platforms. Additionally, environments like Cygwin enable handling of property lists in cross-compiled macOS applications by providing POSIX compatibility for building cross-compiled applications targeting macOS, though running requires macOS. Key tools for working with property lists on Windows include the integrated PList editor in for Xamarin projects, which allows editing of Info.plist files for apps developed on Windows machines. scripts can also parse XML-formatted property lists using built-in cmdlets like Select-Xml, treating them as standard XML documents for automation and configuration tasks. Interoperability between macOS property lists and Windows is common in enterprise (MDM) scenarios, where administrators export .plist configurations from macOS systems to manage Apple devices via Windows-based tools like . However, the binary property list format presents challenges on Windows due to its use of big-endian byte ordering, contrasting with Windows' little-endian , which requires specialized parsers to correctly interpret and date values. In case studies involving cross-platform development, applications leverage property lists for -specific configurations while bridging to Windows targets, allowing developers on Windows to edit -specific configurations in property lists, though building apps requires macOS or cloud-based services that incorporate .plist files for app metadata and permissions. File associations for .plist extensions in Windows Explorer can be configured through the Settings app to open with tools like Notepad++ or dedicated editors, facilitating direct manipulation without additional software. A significant limitation is the absence of a built-in defaults system analogous to macOS, where property lists store user preferences; Windows instead uses the Registry for such purposes, prompting reliance on as a more universally supported alternative for cross-platform configuration files. Cross-platform libraries, such as those in the libimobiledevice project, further aid compatibility by providing Windows builds for property list handling.

NetBSD and Unix Variants

In , support for Apple property lists is facilitated through the pkgsrc package collection, which provides libplist, a C library designed to parse and manipulate both binary and XML formats of property lists. This library enables developers to handle serialized data structures commonly used in Apple ecosystems, such as configuration files and application metadata, within NetBSD environments. Libplist was first imported into pkgsrc around 2011, allowing seamless integration for tools requiring compatibility with macOS or data formats. Other Unix-like systems, including , offer similar capabilities via ports collections that include libplist for full property list handling. In , the devel/libplist port installs the library to support binary and XML property list operations, often used in utilities for device management or cross-platform development. For XML-based property lists, and other variants leverage general-purpose XML parsers, but libplist provides specialized tools like plistutil for conversion between formats. Additionally, Linux distributions such as include libplist in their repositories, enabling property list processing in user-space applications. Property lists lack native support at the kernel level in and other Unix variants, as they are not integral to core operating system functionality; instead, they are processed entirely in user space through libraries and daemons. For instance, user-space daemons in environments like on may indirectly interact with property lists via for parsing XML configurations in desktop settings or Apple-compatible software, though primary configuration relies on other formats like INI or GSettings schemas. serves as a foundational XML parser for handling the structured data in XML property lists across these systems. Developments in Unix property list support emphasize portability, particularly in managing Apple's binary format, which uses big-endian encoding for multi-byte values. Libraries like libplist automatically handle byte-order conversions on little-endian architectures prevalent in modern Unix systems (e.g., x86-based or ), ensuring compatibility without manual intervention. This is crucial for tools processing binary plists from Apple devices on non-Apple hardware. An example of practical use includes build systems where RPM specifications are adapted for macOS ; utilities leveraging libplist can convert or generate property list equivalents for metadata during cross-compilation workflows on Unix platforms.

Third-Party Libraries

Several open-source libraries facilitate the handling of property lists across various programming languages and platforms, enabling developers to parse, generate, and manipulate these files without relying on Apple-specific APIs. One prominent example is libplist, a portable C library developed as part of the libimobiledevice project, which supports reading and writing property lists in binary, XML, , and formats. It is widely used in forensics and device management tools due to its lightweight design and cross-platform compatibility. In Python, plistlib serves as a built-in module since version 2.3, providing straightforward functions for serializing and deserializing property lists in both XML and binary formats. This module is particularly valued for its simplicity in scripting tasks involving macOS configuration files. For applications, especially in enterprise environments, options include dd-plist, an MIT-licensed library that parses and generates property lists in multiple formats, and Configuration's PropertyListConfiguration class, which handles ASCII plist files with support for date extensions. In ecosystems, the plist package offers robust parsing and building capabilities for property lists, making it suitable for server-side and browser-based applications interacting with macOS data. Commercial software also leverages property list handling through integrated libraries or custom implementations. The Unity game engine, for instance, manages property lists during iOS builds by generating and modifying Info.plist files via its Xcode project structure, supporting cross-platform asset configuration. Similarly, Adobe Creative Cloud applications utilize property lists for deployment and launch agent configurations, with tools like plist editors in their admin guides for customizing authentication and installation behaviors. These libraries typically offer comprehensive features such as full read/write operations, schema validation for structural integrity, and format conversions between binary and XML representations to ensure interoperability. Performance benchmarks indicate that implementations like the Rust crate plist-rs, released in 2016 and actively maintained since, achieve parsing speeds equivalent to Apple's native Foundation framework, making it efficient for high-throughput applications in modern Rust projects. As of 2025, libplist (version 2.5+) includes improved handling for Apple Silicon architectures and enhanced security features in binary plists. Community-driven updates have addressed security concerns, including patches for vulnerabilities akin to CVE-2023-27937, which involves integer overflows in plist parsing that could lead to app crashes or code execution; affected libraries like libplist have incorporated fixes to mitigate such risks in non-Apple environments.

References

Add your contribution
Related Hubs
User Avatar
No comments yet.