Apple's binary property list format implementation in Crystal.
Bplist module provides an interface for reading and writing the “property list” files used by Apple, primarily on macOS and iOS.
This module supports only binary plist files.
Values can be nil, booleans, integers (Int8, Int16, Int32, Int64, Int128), floats (Float32, Float64), strings, Time objects, Bytes (Slice(UInt8)), arrays, or hashes (with string keys only).
-
Add the dependency to your
shard.yml:dependencies: bplist: github: mamantoha/crystal-bplist
-
Run
shards install
Transform a Crystal hash into bplist format:
require "bplist"
hash = {
"ExampleDictionary" => {
"ExampleDate" => Time.parse("2023-04-01 12:00:00 +00:00", "%Y-%m-%d %H:%M:%S %z", Time::Location::UTC),
"ExampleArray" => [
"Item 1",
"Item 2",
"Item 3",
],
},
"ExampleString" => "Hello, world!",
"ExampleInteger" => 42,
"ExampleBoolean" => true,
}
writer = Bplist::Writer.new(hash)
writer.write_to_file("#{__DIR__}/../assets/example_mod.plist")crystal ./samples/write.crRewrite the property list file in XML format:
plutil -convert xml1 assets/example_mod.plist -o assets/example_mod.xml
cat assets/example_mod.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>ExampleBoolean</key>
<true/>
<key>ExampleDictionary</key>
<dict>
<key>ExampleArray</key>
<array>
<string>Item 1</string>
<string>Item 2</string>
<string>Item 3</string>
</array>
<key>ExampleDate</key>
<date>2023-04-01T12:00:00Z</date>
</dict>
<key>ExampleInteger</key>
<integer>42</integer>
<key>ExampleString</key>
<string>Hello, world!</string>
</dict>
</plist>Parse a binary plist file and retrieve a Bplist::Any object:
require "bplist"
bplist = Bplist::Parser.new("#{__DIR__}/../assets/example.plist")
result = bplist.parse
pp result{"ExampleDictionary" =>
{"ExampleDate" => 2023-04-01 12:00:00.0 UTC,
"ExampleArray" => ["Item 1", "Item 2", "Item 3"]},
"ExampleString" => "Hello, world!",
"ExampleInteger" => 42,
"ExampleBoolean" => true}The Bplist::Any object returned by the parser is immutable. To modify plist data, you need to convert it to native Crystal types first.
require "bplist"
# Read the plist file
bplist = Bplist::Parser.new("config.plist")
result = bplist.parse # Bplist::Any (immutable)
# Convert to modifiable Hash
data = result.to_h # Hash(String, Bplist::Any::NativeType) - mutable
# Modify the data
data["last_modified"] = Time.utc
data["version"] = (data["version"]?.as(Int32) || 0) + 1
data["new_key"] = "new_value"
# Access and modify nested structures
if data["settings"]?.is_a?(Hash)
settings = data["settings"].as(Hash)
settings["theme"] = "dark"
settings["notifications"] = true
else
# Create new nested structure
data["settings"] = {
"theme" => "dark",
"notifications" => true,
"auto_save" => false
}
end
# Write the modified data back to file
writer = Bplist::Writer.new(data)
writer.write_to_file("config.plist")- https://medium.com/@karaiskc/understanding-apples-binary-property-list-format-281e6da00dbd
- https://github.com/opensource-apple/CF/blob/master/CFBinaryPList.c
- https://docs.python.org/3/library/plistlib.html
- https://github.com/python/cpython/blob/main/Lib/plistlib.py
- http://fileformats.archiveteam.org/wiki/Property_List/Binary
- Fork it (https://github.com/mamantoha/crystal-bplist/fork)
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request
- Anton Maminov - creator and maintainer
