CFPropertyList 2.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README +34 -0
- data/lib/rbBinaryCFPropertyList.rb +669 -0
- data/lib/rbCFPlistError.rb +19 -0
- data/lib/rbCFPropertyList.rb +316 -0
- data/lib/rbCFTypes.rb +233 -0
- data/lib/rbXMLCFPropertyList.rb +122 -0
- metadata +79 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# CFFormatError implementation
|
4
|
+
#
|
5
|
+
# Author:: Christian Kruse (mailto:cjk@wwwtech.de)
|
6
|
+
# Copyright:: Copyright (c) 2010
|
7
|
+
# License:: MIT License
|
8
|
+
|
9
|
+
class CFPlistError < Exception
|
10
|
+
end
|
11
|
+
|
12
|
+
# Exception thrown when format errors occur
|
13
|
+
class CFFormatError < CFPlistError
|
14
|
+
end
|
15
|
+
|
16
|
+
class CFTypeError < CFPlistError
|
17
|
+
end
|
18
|
+
|
19
|
+
# eof
|
@@ -0,0 +1,316 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# CFPropertyList implementation
|
4
|
+
# class to read, manipulate and write both XML and binary property list
|
5
|
+
# files (plist(5)) as defined by Apple
|
6
|
+
#
|
7
|
+
# == Example
|
8
|
+
#
|
9
|
+
# # create a arbitrary data structure of basic data types
|
10
|
+
# data = {
|
11
|
+
# 'name' => 'John Doe',
|
12
|
+
# 'missing' => true,
|
13
|
+
# 'last_seen' => Time.now,
|
14
|
+
# 'friends' => ['Jane Doe','Julian Doe'],
|
15
|
+
# 'likes' => {
|
16
|
+
# 'me' => false
|
17
|
+
# }
|
18
|
+
# }
|
19
|
+
#
|
20
|
+
# # create CFPropertyList::List object
|
21
|
+
# plist = CFPropertyList::List.new
|
22
|
+
#
|
23
|
+
# # call CFPropertyList.guess() to create corresponding CFType values
|
24
|
+
# # pass in optional :convert_unknown_to_string => true to convert things like symbols into strings.
|
25
|
+
# plist.value = CFPropertyList.guess(data)
|
26
|
+
#
|
27
|
+
# # write plist to file
|
28
|
+
# plist.save("example.plist", CFPropertyList::List::FORMAT_BINARY)
|
29
|
+
#
|
30
|
+
# # … later, read it again
|
31
|
+
# plist = CFPropertyList::List.new({:file => "example.plist"})
|
32
|
+
# data = CFPropertyList.native_types(plist.value)
|
33
|
+
#
|
34
|
+
# Author:: Christian Kruse (mailto:cjk@wwwtech.de)
|
35
|
+
# Copyright:: Copyright (c) 2010
|
36
|
+
# License:: Distributes under the same terms as Ruby
|
37
|
+
|
38
|
+
require 'libxml'
|
39
|
+
require 'kconv'
|
40
|
+
require 'date'
|
41
|
+
|
42
|
+
module CFPropertyList
|
43
|
+
# interface class for PList parsers
|
44
|
+
class ParserInterface
|
45
|
+
# load a plist
|
46
|
+
def load(opts={})
|
47
|
+
return ""
|
48
|
+
end
|
49
|
+
|
50
|
+
# convert a plist to string
|
51
|
+
def to_str(opts={})
|
52
|
+
return true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
dirname = File.dirname(__FILE__)
|
58
|
+
require dirname + '/rbCFPlistError.rb'
|
59
|
+
require dirname + '/rbCFTypes.rb'
|
60
|
+
require dirname + '/rbXMLCFPropertyList.rb'
|
61
|
+
require dirname + '/rbBinaryCFPropertyList.rb'
|
62
|
+
|
63
|
+
require 'iconv' unless "".respond_to?("encode")
|
64
|
+
|
65
|
+
module CFPropertyList
|
66
|
+
# Create CFType hierarchy by guessing the correct CFType, e.g.
|
67
|
+
#
|
68
|
+
# x = {
|
69
|
+
# 'a' => ['b','c','d']
|
70
|
+
# }
|
71
|
+
# cftypes = CFPropertyList.guess(x)
|
72
|
+
#
|
73
|
+
# pass optional options hash. Only possible value actually:
|
74
|
+
# +convert_unknown_to_string+:: Convert unknown objects to string calling to_str()
|
75
|
+
# +converter_method+:: Convert unknown objects to known objects calling +method_name+
|
76
|
+
#
|
77
|
+
# cftypes = CFPropertyList.guess(x,:convert_unknown_to_string => true,:converter_method => :to_hash)
|
78
|
+
def guess(object, options = {})
|
79
|
+
if(object.is_a?(Fixnum) || object.is_a?(Integer)) then
|
80
|
+
return CFInteger.new(object)
|
81
|
+
elsif(object.is_a?(Float) || (Object.const_defined?('BigDecimal') and object.is_a?(BigDecimal))) then
|
82
|
+
return CFReal.new(object)
|
83
|
+
elsif(object.is_a?(TrueClass) || object.is_a?(FalseClass)) then
|
84
|
+
return CFBoolean.new(object)
|
85
|
+
elsif(object.is_a?(String)) then
|
86
|
+
return CFString.new(object)
|
87
|
+
elsif(object.is_a?(Time) || object.is_a?(DateTime)) then
|
88
|
+
return CFDate.new(object)
|
89
|
+
elsif(object.is_a?(IO)) then
|
90
|
+
return CFData.new(object.read, CFData::DATA_RAW)
|
91
|
+
elsif(object.is_a?(Array)) then
|
92
|
+
ary = Array.new
|
93
|
+
object.each do
|
94
|
+
|o|
|
95
|
+
ary.push CFPropertyList.guess(o, options)
|
96
|
+
end
|
97
|
+
|
98
|
+
return CFArray.new(ary)
|
99
|
+
elsif(object.is_a?(Hash)) then
|
100
|
+
hsh = Hash.new
|
101
|
+
object.each_pair do
|
102
|
+
|k,v|
|
103
|
+
k = k.to_s if k.is_a?(Symbol)
|
104
|
+
hsh[k] = CFPropertyList.guess(v, options)
|
105
|
+
end
|
106
|
+
|
107
|
+
return CFDictionary.new(hsh)
|
108
|
+
elsif options[:converter_method] and object.respond_to?(options[:converter_method]) then
|
109
|
+
return CFPropertyList.guess(object.send(options[:converter_method]))
|
110
|
+
elsif options[:convert_unknown_to_string] then
|
111
|
+
return CFString.new(object.to_s)
|
112
|
+
else
|
113
|
+
raise CFTypeError.new("Unknown class #{object.class.to_s}! Try using :convert_unknown_to_string if you want to use unknown object types!")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Converts a CFType hiercharchy to native Ruby types
|
118
|
+
def native_types(object,keys_as_symbols=false)
|
119
|
+
return if object.nil?
|
120
|
+
|
121
|
+
if(object.is_a?(CFDate) || object.is_a?(CFString) || object.is_a?(CFInteger) || object.is_a?(CFReal) || object.is_a?(CFBoolean)) then
|
122
|
+
return object.value
|
123
|
+
elsif(object.is_a?(CFData)) then
|
124
|
+
return object.decoded_value
|
125
|
+
elsif(object.is_a?(CFArray)) then
|
126
|
+
ary = []
|
127
|
+
object.value.each do
|
128
|
+
|v|
|
129
|
+
ary.push CFPropertyList.native_types(v)
|
130
|
+
end
|
131
|
+
|
132
|
+
return ary
|
133
|
+
elsif(object.is_a?(CFDictionary)) then
|
134
|
+
hsh = {}
|
135
|
+
object.value.each_pair do
|
136
|
+
|k,v|
|
137
|
+
k = k.to_sym if keys_as_symbols
|
138
|
+
hsh[k] = CFPropertyList.native_types(v)
|
139
|
+
end
|
140
|
+
|
141
|
+
return hsh
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
module_function :guess, :native_types
|
146
|
+
|
147
|
+
class List
|
148
|
+
# Format constant for binary format
|
149
|
+
FORMAT_BINARY = 1
|
150
|
+
|
151
|
+
# Format constant for XML format
|
152
|
+
FORMAT_XML = 2
|
153
|
+
|
154
|
+
# Format constant for automatic format recognizing
|
155
|
+
FORMAT_AUTO = 0
|
156
|
+
|
157
|
+
@@parsers = [Binary,XML]
|
158
|
+
|
159
|
+
# Path of PropertyList
|
160
|
+
attr_accessor :filename
|
161
|
+
# Path of PropertyList
|
162
|
+
attr_accessor :format
|
163
|
+
# the root value in the plist file
|
164
|
+
attr_accessor :value
|
165
|
+
|
166
|
+
def initialize(opts={})
|
167
|
+
@filename = opts[:file]
|
168
|
+
@format = opts[:format] || FORMAT_AUTO
|
169
|
+
@data = opts[:data]
|
170
|
+
|
171
|
+
load(@filename) unless @filename.nil?
|
172
|
+
load_str(@data) unless @data.nil?
|
173
|
+
end
|
174
|
+
|
175
|
+
# Load an XML PropertyList
|
176
|
+
# filename = nil:: The filename to read from; if nil, read from the file defined by instance variable +filename+
|
177
|
+
def load_xml(filename=nil)
|
178
|
+
load(filename,List::FORMAT_XML)
|
179
|
+
end
|
180
|
+
|
181
|
+
# read a binary plist file
|
182
|
+
# filename = nil:: The filename to read from; if nil, read from the file defined by instance variable +filename+
|
183
|
+
def load_binary(filename=nil)
|
184
|
+
load(filename,List::FORMAT_BINARY)
|
185
|
+
end
|
186
|
+
|
187
|
+
# load a plist from a XML string
|
188
|
+
# str:: The string containing the plist
|
189
|
+
def load_xml_str(str=nil)
|
190
|
+
load_str(str,List::FORMAT_XML)
|
191
|
+
end
|
192
|
+
|
193
|
+
# load a plist from a binary string
|
194
|
+
# str:: The string containing the plist
|
195
|
+
def load_binary_str(str=nil)
|
196
|
+
load_str(str,List::FORMAT_BINARY)
|
197
|
+
end
|
198
|
+
|
199
|
+
# load a plist from a string
|
200
|
+
# str = nil:: The string containing the plist
|
201
|
+
# format = nil:: The format of the plist
|
202
|
+
def load_str(str=nil,format=nil)
|
203
|
+
str = @data if str.nil?
|
204
|
+
format = @format if format.nil?
|
205
|
+
|
206
|
+
@value = {}
|
207
|
+
case format
|
208
|
+
when List::FORMAT_BINARY, List::FORMAT_XML then
|
209
|
+
prsr = @@parsers[format-1].new
|
210
|
+
@value = prsr.load({:data => str})
|
211
|
+
|
212
|
+
when List::FORMAT_AUTO then # what we now do is ugly, but neccessary to recognize the file format
|
213
|
+
filetype = str[0..5]
|
214
|
+
version = str[6..7]
|
215
|
+
|
216
|
+
prsr = nil
|
217
|
+
if filetype == "bplist" then
|
218
|
+
raise CFFormatError.new("Wong file version #{version}") unless version == "00"
|
219
|
+
prsr = Binary.new
|
220
|
+
else
|
221
|
+
prsr = XML.new
|
222
|
+
end
|
223
|
+
|
224
|
+
@value = prsr.load({:data => str})
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Read a plist file
|
229
|
+
# file = nil:: The filename of the file to read. If nil, use +filename+ instance variable
|
230
|
+
# format = nil:: The format of the plist file. Auto-detect if nil
|
231
|
+
def load(file=nil,format=nil)
|
232
|
+
file = @filename if file.nil?
|
233
|
+
format = @format if format.nil?
|
234
|
+
@value = {}
|
235
|
+
|
236
|
+
raise IOError.new("File #{file} not readable!") unless File.readable? file
|
237
|
+
|
238
|
+
case format
|
239
|
+
when List::FORMAT_BINARY, List::FORMAT_XML then
|
240
|
+
prsr = @@parsers[format-1].new
|
241
|
+
@value = prsr.load({:file => file})
|
242
|
+
|
243
|
+
when List::FORMAT_AUTO then # what we now do is ugly, but neccessary to recognize the file format
|
244
|
+
magic_number = IO.read(file,8)
|
245
|
+
filetype = magic_number[0..5]
|
246
|
+
version = magic_number[6..7]
|
247
|
+
|
248
|
+
prsr = nil
|
249
|
+
if filetype == "bplist" then
|
250
|
+
raise CFFormatError.new("Wong file version #{version}") unless version == "00"
|
251
|
+
prsr = Binary.new
|
252
|
+
else
|
253
|
+
prsr = XML.new
|
254
|
+
end
|
255
|
+
|
256
|
+
@value = prsr.load({:file => file})
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# Serialize CFPropertyList object to specified format and write it to file
|
261
|
+
# file = nil:: The filename of the file to write to. Uses +filename+ instance variable if nil
|
262
|
+
# format = nil:: The format to save in. Uses +format+ instance variable if nil
|
263
|
+
def save(file=nil,format=nil,opts={})
|
264
|
+
format = @format if format.nil?
|
265
|
+
file = @filename if file.nil?
|
266
|
+
|
267
|
+
raise CFFormatError.new("Format #{format} not supported, use List::FORMAT_BINARY or List::FORMAT_XML") if format != FORMAT_BINARY && format != FORMAT_XML
|
268
|
+
|
269
|
+
if(!File.exists?(file)) then
|
270
|
+
raise IOError.new("File #{file} not writable!") unless File.writable?(File.dirname(file))
|
271
|
+
elsif(!File.writable?(file)) then
|
272
|
+
raise IOError.new("File #{file} not writable!")
|
273
|
+
end
|
274
|
+
|
275
|
+
opts[:root] = @value
|
276
|
+
prsr = @@parsers[format-1].new
|
277
|
+
content = prsr.to_str(opts)
|
278
|
+
|
279
|
+
File.open(file, 'wb') {
|
280
|
+
|fd|
|
281
|
+
fd.write content
|
282
|
+
}
|
283
|
+
end
|
284
|
+
|
285
|
+
# convert plist to string
|
286
|
+
# format = List::FORMAT_BINARY:: The format to save the plist
|
287
|
+
# opts={}:: Pass parser options
|
288
|
+
def to_str(format=List::FORMAT_BINARY,opts={})
|
289
|
+
prsr = @@parsers[format-1].new
|
290
|
+
opts[:root] = @value
|
291
|
+
return prsr.to_str(opts)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
class Array
|
297
|
+
def to_plist(options={})
|
298
|
+
options[:plist_format] ||= CFPropertyList::List::FORMAT_BINARY
|
299
|
+
|
300
|
+
plist = CFPropertyList::List.new
|
301
|
+
plist.value = CFPropertyList.guess(self, options)
|
302
|
+
plist.to_str(options[:plist_format])
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
class Hash
|
307
|
+
def to_plist(options={})
|
308
|
+
options[:plist_format] ||= CFPropertyList::List::FORMAT_BINARY
|
309
|
+
|
310
|
+
plist = CFPropertyList::List.new
|
311
|
+
plist.value = CFPropertyList.guess(self, options)
|
312
|
+
plist.to_str(options[:plist_format])
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
# eof
|
data/lib/rbCFTypes.rb
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# CFTypes, e.g. CFString, CFInteger
|
4
|
+
# needed to create unambiguous plists
|
5
|
+
#
|
6
|
+
# Author:: Christian Kruse (mailto:cjk@wwwtech.de)
|
7
|
+
# Copyright:: Copyright (c) 2009
|
8
|
+
# License:: Distributes under the same terms as Ruby
|
9
|
+
|
10
|
+
require 'base64'
|
11
|
+
|
12
|
+
module CFPropertyList
|
13
|
+
# This class defines the base class for all CFType classes
|
14
|
+
#
|
15
|
+
class CFType
|
16
|
+
# value of the type
|
17
|
+
attr_accessor :value
|
18
|
+
|
19
|
+
|
20
|
+
# set internal value to parameter value by default
|
21
|
+
def initialize(value=nil)
|
22
|
+
@value = value
|
23
|
+
end
|
24
|
+
|
25
|
+
# convert type to XML
|
26
|
+
def to_xml
|
27
|
+
end
|
28
|
+
|
29
|
+
# convert type to binary
|
30
|
+
def to_binary(bplist)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# This class holds string values, both, UTF-8 and UTF-16BE
|
35
|
+
# It will convert the value to UTF-16BE if necessary (i.e. if non-ascii char contained)
|
36
|
+
class CFString < CFType
|
37
|
+
# convert to XML
|
38
|
+
def to_xml
|
39
|
+
n = LibXML::XML::Node.new('string')
|
40
|
+
n << LibXML::XML::Node.new_text(@value) unless @value.nil?
|
41
|
+
return n
|
42
|
+
end
|
43
|
+
|
44
|
+
# convert to binary
|
45
|
+
def to_binary(bplist)
|
46
|
+
return bplist.string_to_binary(@value);
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# This class holds integer/fixnum values
|
51
|
+
class CFInteger < CFType
|
52
|
+
# convert to XML
|
53
|
+
def to_xml
|
54
|
+
return LibXML::XML::Node.new('integer') << LibXML::XML::Node.new_text(@value.to_s)
|
55
|
+
end
|
56
|
+
|
57
|
+
# convert to binary
|
58
|
+
def to_binary(bplist)
|
59
|
+
return bplist.num_to_binary(self)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# This class holds float values
|
64
|
+
class CFReal < CFType
|
65
|
+
# convert to XML
|
66
|
+
def to_xml
|
67
|
+
return LibXML::XML::Node.new('real') << LibXML::XML::Node.new_text(@value.to_s)
|
68
|
+
end
|
69
|
+
|
70
|
+
# convert to binary
|
71
|
+
def to_binary(bplist)
|
72
|
+
return bplist.num_to_binary(self)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# This class holds Time values. While Apple uses seconds since 2001,
|
77
|
+
# the rest of the world uses seconds since 1970. So if you access value
|
78
|
+
# directly, you get the Time class. If you access via get_value you either
|
79
|
+
# geht the timestamp or the Apple timestamp
|
80
|
+
class CFDate < CFType
|
81
|
+
TIMESTAMP_APPLE = 0
|
82
|
+
TIMESTAMP_UNIX = 1;
|
83
|
+
DATE_DIFF_APPLE_UNIX = 978307200
|
84
|
+
|
85
|
+
# create a XML date strimg from a time object
|
86
|
+
def CFDate.date_string(val)
|
87
|
+
# 2009-05-13T20:23:43Z
|
88
|
+
val.getutc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
89
|
+
end
|
90
|
+
|
91
|
+
# parse a XML date string
|
92
|
+
def CFDate.parse_date(val)
|
93
|
+
# 2009-05-13T20:23:43Z
|
94
|
+
val =~ %r{^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$}
|
95
|
+
year,month,day,hour,min,sec = $1, $2, $3, $4, $5, $6
|
96
|
+
return Time.utc(year,month,day,hour,min,sec).getlocal
|
97
|
+
end
|
98
|
+
|
99
|
+
# set value to defined state
|
100
|
+
def initialize(value = nil,format=CFDate::TIMESTAMP_UNIX)
|
101
|
+
if(value.is_a?(Time) || value.nil?) then
|
102
|
+
@value = value.nil? ? Time.now : value
|
103
|
+
else
|
104
|
+
set_value(value,format)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# set value with timestamp, either Apple or UNIX
|
109
|
+
def set_value(value,format=CFDate::TIMESTAMP_UNIX)
|
110
|
+
if(format == CFDate::TIMESTAMP_UNIX) then
|
111
|
+
@value = Time.at(value)
|
112
|
+
else
|
113
|
+
@value = Time.at(value + CFDate::DATE_DIFF_APPLE_UNIX)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# get timestamp, either UNIX or Apple timestamp
|
118
|
+
def get_value(format=CFDate::TIMESTAMP_UNIX)
|
119
|
+
if(format == CFDate::TIMESTAMP_UNIX) then
|
120
|
+
return @value.to_i
|
121
|
+
else
|
122
|
+
return @value.to_f - CFDate::DATE_DIFF_APPLE_UNIX
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# convert to XML
|
127
|
+
def to_xml
|
128
|
+
return LibXML::XML::Node.new('date') << LibXML::XML::Node.new_text(CFDate::date_string(@value))
|
129
|
+
end
|
130
|
+
|
131
|
+
# convert to binary
|
132
|
+
def to_binary(bplist)
|
133
|
+
return bplist.date_to_binary(@value)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# This class contains a boolean value
|
138
|
+
class CFBoolean < CFType
|
139
|
+
# convert to XML
|
140
|
+
def to_xml
|
141
|
+
return LibXML::XML::Node.new(@value ? 'true' : 'false')
|
142
|
+
end
|
143
|
+
|
144
|
+
# convert to binary
|
145
|
+
def to_binary(bplist)
|
146
|
+
return bplist.bool_to_binary(@value);
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# This class contains binary data values
|
151
|
+
class CFData < CFType
|
152
|
+
# Base64 encoded data
|
153
|
+
DATA_BASE64 = 0
|
154
|
+
# Raw data
|
155
|
+
DATA_RAW = 1
|
156
|
+
|
157
|
+
# set value to defined state, either base64 encoded or raw
|
158
|
+
def initialize(value=nil,format=DATA_BASE64)
|
159
|
+
if(format == DATA_RAW) then
|
160
|
+
@value = Base64.encode64(value)
|
161
|
+
else
|
162
|
+
@value = value
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# get base64 decoded value
|
167
|
+
def decoded_value
|
168
|
+
return Base64.decode64(@value)
|
169
|
+
end
|
170
|
+
|
171
|
+
# convert to XML
|
172
|
+
def to_xml
|
173
|
+
return LibXML::XML::Node.new('data') << LibXML::XML::Node.new_text(@value)
|
174
|
+
end
|
175
|
+
|
176
|
+
# convert to binary
|
177
|
+
def to_binary(bplist)
|
178
|
+
return bplist.data_to_binary(decoded_value())
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# This class contains an array of values
|
183
|
+
class CFArray < CFType
|
184
|
+
# create a new array CFType
|
185
|
+
def initialize(val=[])
|
186
|
+
@value = val
|
187
|
+
end
|
188
|
+
|
189
|
+
# convert to XML
|
190
|
+
def to_xml
|
191
|
+
n = LibXML::XML::Node.new('array')
|
192
|
+
@value.each do
|
193
|
+
|v|
|
194
|
+
n << v.to_xml
|
195
|
+
end
|
196
|
+
|
197
|
+
return n
|
198
|
+
end
|
199
|
+
|
200
|
+
# convert to binary
|
201
|
+
def to_binary(bplist)
|
202
|
+
return bplist.array_to_binary(self)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# this class contains a hash of values
|
207
|
+
class CFDictionary < CFType
|
208
|
+
# Create new CFDictonary type.
|
209
|
+
def initialize(value={})
|
210
|
+
@value = value
|
211
|
+
end
|
212
|
+
|
213
|
+
# convert to XML
|
214
|
+
def to_xml
|
215
|
+
n = LibXML::XML::Node.new('dict')
|
216
|
+
@value.each_pair do
|
217
|
+
|key,value|
|
218
|
+
k = LibXML::XML::Node.new('key') << LibXML::XML::Node.new_text(key)
|
219
|
+
n << k
|
220
|
+
n << value.to_xml
|
221
|
+
end
|
222
|
+
|
223
|
+
return n
|
224
|
+
end
|
225
|
+
|
226
|
+
# convert to binary
|
227
|
+
def to_binary(bplist)
|
228
|
+
return bplist.dict_to_binary(self)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# eof
|