plist4r 0.2.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.yardopts +11 -0
- data/LICENSE +3 -1
- data/README.rdoc +25 -122
- data/Rakefile +14 -0
- data/VERSION +1 -1
- data/bin/plist4r +2 -0
- data/ext/osx_plist/Makefile +157 -0
- data/ext/osx_plist/extconf.rb +9 -0
- data/ext/osx_plist/plist.c +606 -0
- data/ext/osx_plist/plist.o +0 -0
- data/lib/plist4r.rb +6 -3
- data/lib/plist4r/application.rb +1 -2
- data/lib/plist4r/backend.rb +102 -34
- data/lib/plist4r/backend/c_f_property_list.rb +65 -0
- data/lib/plist4r/backend/c_f_property_list/LICENSE +19 -0
- data/lib/plist4r/backend/c_f_property_list/README +34 -0
- data/lib/plist4r/backend/c_f_property_list/cfpropertylist.rb +6 -0
- data/lib/plist4r/backend/c_f_property_list/rbBinaryCFPropertyList.rb +663 -0
- data/lib/plist4r/backend/c_f_property_list/rbCFPlistError.rb +26 -0
- data/lib/plist4r/backend/c_f_property_list/rbCFPropertyList.rb +348 -0
- data/lib/plist4r/backend/c_f_property_list/rbCFTypes.rb +241 -0
- data/lib/plist4r/backend/c_f_property_list/rbXMLCFPropertyList.rb +116 -0
- data/lib/plist4r/backend/example.rb +37 -52
- data/lib/plist4r/backend/haml.rb +47 -36
- data/lib/plist4r/backend/libxml4r.rb +24 -20
- data/lib/plist4r/backend/osx_plist.rb +82 -0
- data/lib/plist4r/backend/ruby_cocoa.rb +172 -54
- data/lib/plist4r/backend/test/data_types.rb +163 -0
- data/lib/plist4r/backend/test/harness.rb +255 -0
- data/lib/plist4r/backend/test/output.rb +47 -0
- data/lib/plist4r/backend_base.rb +4 -2
- data/lib/plist4r/{options.rb → cli.rb} +2 -1
- data/lib/plist4r/commands.rb +13 -8
- data/lib/plist4r/config.rb +36 -9
- data/lib/plist4r/docs/Backends.html +59 -0
- data/lib/plist4r/docs/DeveloperGuide.rdoc +53 -0
- data/lib/plist4r/docs/EditingPlistFiles.rdoc +88 -0
- data/lib/plist4r/docs/InfoPlistExample.rdoc +33 -0
- data/lib/plist4r/docs/LaunchdPlistExample.rdoc +33 -0
- data/lib/plist4r/docs/PlistKeyNames.rdoc +47 -0
- data/lib/plist4r/mixin/array_dict.rb +61 -0
- data/lib/plist4r/mixin/data_methods.rb +178 -54
- data/lib/plist4r/mixin/haml4r.rb +4 -0
- data/lib/plist4r/mixin/haml4r/css_attributes.rb +19 -0
- data/lib/plist4r/mixin/haml4r/examples.rb +261 -0
- data/lib/plist4r/mixin/haml4r/haml_table_example.rb +79 -0
- data/lib/plist4r/mixin/haml4r/table.rb +157 -0
- data/lib/plist4r/mixin/haml4r/table_cell.rb +160 -0
- data/lib/plist4r/mixin/haml4r/table_cells.rb +485 -0
- data/lib/plist4r/mixin/haml4r/table_section.rb +101 -0
- data/lib/plist4r/mixin/ordered_hash.rb +9 -1
- data/lib/plist4r/mixin/popen4.rb +1 -1
- data/lib/plist4r/mixin/ruby_stdlib.rb +154 -1
- data/lib/plist4r/mixin/script.rb +133 -0
- data/lib/plist4r/mixin/table.rb +435 -0
- data/lib/plist4r/plist.rb +272 -94
- data/lib/plist4r/plist_cache.rb +42 -43
- data/lib/plist4r/plist_type.rb +31 -74
- data/lib/plist4r/plist_type/info.rb +157 -3
- data/lib/plist4r/plist_type/launchd.rb +54 -48
- data/lib/plist4r/plist_type/plist.rb +1 -3
- data/plist4r.gemspec +74 -14
- data/spec/{examples.rb → launchd_examples.rb} +131 -139
- data/spec/plist4r/application_spec.rb +37 -0
- data/spec/plist4r/backend_spec.rb +256 -0
- data/spec/plist4r/cli_spec.rb +25 -0
- data/spec/plist4r/commands_spec.rb +20 -0
- data/spec/plist4r/config_spec.rb +38 -0
- data/spec/plist4r/mixin/array_dict_spec.rb +120 -0
- data/spec/plist4r/mixin/data_methods_spec.rb +96 -0
- data/spec/plist4r/mixin/haml4r/examples.rb +261 -0
- data/spec/plist4r/mixin/ruby_stdlib_spec.rb +228 -0
- data/spec/plist4r/plist_cache_spec.rb +261 -0
- data/spec/plist4r/plist_spec.rb +841 -23
- data/spec/plist4r/plist_type_spec.rb +126 -0
- data/spec/plist4r_spec.rb +53 -27
- data/spec/scratchpad.rb +226 -0
- data/spec/spec_helper.rb +5 -1
- metadata +109 -23
- data/lib/plist4r/backend/plutil.rb +0 -25
- data/lib/plist4r/mixin.rb +0 -7
- data/plists/array_mini.xml +0 -14
- data/plists/example_big_binary.plist +0 -0
- data/plists/example_medium_binary_launchd.plist +0 -0
- data/plists/example_medium_launchd.xml +0 -53
- data/plists/mini.xml +0 -12
- data/test.rb +0 -40
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Exceptions used:
|
4
|
+
# CFPlistError:: General base exception
|
5
|
+
# CFFormatError:: Format error
|
6
|
+
# CFTypeError:: Type error
|
7
|
+
#
|
8
|
+
# Easy and simple :-)
|
9
|
+
#
|
10
|
+
# Author:: Christian Kruse (mailto:cjk@wwwtech.de)
|
11
|
+
# Copyright:: Copyright (c) 2010
|
12
|
+
# License:: MIT License
|
13
|
+
|
14
|
+
# general plist error. All exceptions thrown are derived from this class.
|
15
|
+
class CFPlistError < Exception
|
16
|
+
end
|
17
|
+
|
18
|
+
# Exception thrown when format errors occur
|
19
|
+
class CFFormatError < CFPlistError
|
20
|
+
end
|
21
|
+
|
22
|
+
# Exception thrown when type errors occur
|
23
|
+
class CFTypeError < CFPlistError
|
24
|
+
end
|
25
|
+
|
26
|
+
# eof
|
@@ -0,0 +1,348 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'libxml'
|
4
|
+
require 'kconv'
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
#
|
8
|
+
# CFPropertyList implementation
|
9
|
+
#
|
10
|
+
# class to read, manipulate and write both XML and binary property list
|
11
|
+
# files (plist(5)) as defined by Apple. Have a look at CFPropertyList::List
|
12
|
+
# for more documentation.
|
13
|
+
#
|
14
|
+
# == Example
|
15
|
+
# require 'cfpropertylist'
|
16
|
+
#
|
17
|
+
# # create a arbitrary data structure of basic data types
|
18
|
+
# data = {
|
19
|
+
# 'name' => 'John Doe',
|
20
|
+
# 'missing' => true,
|
21
|
+
# 'last_seen' => Time.now,
|
22
|
+
# 'friends' => ['Jane Doe','Julian Doe'],
|
23
|
+
# 'likes' => {
|
24
|
+
# 'me' => false
|
25
|
+
# }
|
26
|
+
# }
|
27
|
+
#
|
28
|
+
# # create CFPropertyList::List object
|
29
|
+
# plist = CFPropertyList::List.new
|
30
|
+
#
|
31
|
+
# # call CFPropertyList.guess() to create corresponding CFType values
|
32
|
+
# # pass in optional :convert_unknown_to_string => true to convert things like symbols into strings.
|
33
|
+
# plist.value = CFPropertyList.guess(data)
|
34
|
+
#
|
35
|
+
# # write plist to file
|
36
|
+
# plist.save("example.plist", CFPropertyList::List::FORMAT_BINARY)
|
37
|
+
#
|
38
|
+
# # … later, read it again
|
39
|
+
# plist = CFPropertyList::List.new(:file => "example.plist")
|
40
|
+
# data = CFPropertyList.native_types(plist.value)
|
41
|
+
#
|
42
|
+
# Author:: Christian Kruse (mailto:cjk@wwwtech.de)
|
43
|
+
# Copyright:: Copyright (c) 2010
|
44
|
+
# License:: MIT License
|
45
|
+
module CFPropertyList
|
46
|
+
# interface class for PList parsers
|
47
|
+
class ParserInterface
|
48
|
+
# load a plist
|
49
|
+
def load(opts={})
|
50
|
+
return ""
|
51
|
+
end
|
52
|
+
|
53
|
+
# convert a plist to string
|
54
|
+
def to_str(opts={})
|
55
|
+
return true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class String
|
61
|
+
unless("".respond_to?(:blob) && "".respond_to?(:blob=)) then
|
62
|
+
# The blob status of this string (to set to true if a binary string)
|
63
|
+
attr_accessor :blob
|
64
|
+
end
|
65
|
+
|
66
|
+
unless("".respond_to?(:blob?)) then
|
67
|
+
# Returns whether or not +str+ is a blob.
|
68
|
+
# @return [true,false] If true, this string contains binary data. If false, its a regular string
|
69
|
+
def blob?
|
70
|
+
@blob
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
unless("".respond_to?(:bytesize)) then
|
75
|
+
def bytesize
|
76
|
+
self.length
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
dirname = File.dirname(__FILE__)
|
82
|
+
require dirname + '/rbCFPlistError.rb'
|
83
|
+
require dirname + '/rbCFTypes.rb'
|
84
|
+
require dirname + '/rbXMLCFPropertyList.rb'
|
85
|
+
require dirname + '/rbBinaryCFPropertyList.rb'
|
86
|
+
|
87
|
+
require 'iconv' unless "".respond_to?("encode")
|
88
|
+
|
89
|
+
module CFPropertyList
|
90
|
+
# Create CFType hierarchy by guessing the correct CFType, e.g.
|
91
|
+
#
|
92
|
+
# x = {
|
93
|
+
# 'a' => ['b','c','d']
|
94
|
+
# }
|
95
|
+
# cftypes = CFPropertyList.guess(x)
|
96
|
+
#
|
97
|
+
# pass optional options hash. Only possible value actually:
|
98
|
+
# +convert_unknown_to_string+:: Convert unknown objects to string calling to_str()
|
99
|
+
# +converter_method+:: Convert unknown objects to known objects calling +method_name+
|
100
|
+
#
|
101
|
+
# cftypes = CFPropertyList.guess(x,:convert_unknown_to_string => true,:converter_method => :to_hash)
|
102
|
+
def guess(object, options = {})
|
103
|
+
if(object.is_a?(Fixnum) || object.is_a?(Integer)) then
|
104
|
+
return CFInteger.new(object)
|
105
|
+
elsif(object.is_a?(Float) || (Object.const_defined?('BigDecimal') and object.is_a?(BigDecimal))) then
|
106
|
+
return CFReal.new(object)
|
107
|
+
elsif(object.is_a?(TrueClass) || object.is_a?(FalseClass)) then
|
108
|
+
return CFBoolean.new(object)
|
109
|
+
elsif(object.is_a?(String)) then
|
110
|
+
return object.blob? ? CFData.new(object, CFData::DATA_RAW) : CFString.new(object)
|
111
|
+
elsif(object.is_a?(Time) || object.is_a?(DateTime) || object.is_a?(Date)) then
|
112
|
+
return CFDate.new(object)
|
113
|
+
elsif(object.is_a?(Array)) then
|
114
|
+
ary = Array.new
|
115
|
+
object.each do
|
116
|
+
|o|
|
117
|
+
ary.push CFPropertyList.guess(o, options)
|
118
|
+
end
|
119
|
+
|
120
|
+
return CFArray.new(ary)
|
121
|
+
elsif(object.is_a?(Hash)) then
|
122
|
+
hsh = Hash.new
|
123
|
+
object.each_pair do
|
124
|
+
|k,v|
|
125
|
+
k = k.to_s if k.is_a?(Symbol)
|
126
|
+
hsh[k] = CFPropertyList.guess(v, options)
|
127
|
+
end
|
128
|
+
|
129
|
+
return CFDictionary.new(hsh)
|
130
|
+
elsif options[:converter_method] and object.respond_to?(options[:converter_method]) then
|
131
|
+
return CFPropertyList.guess(object.send(options[:converter_method]))
|
132
|
+
elsif options[:convert_unknown_to_string] then
|
133
|
+
return CFString.new(object.to_s)
|
134
|
+
else
|
135
|
+
raise CFTypeError.new("Unknown class #{object.class.to_s}! Try using :convert_unknown_to_string if you want to use unknown object types!")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Converts a CFType hiercharchy to native Ruby types
|
140
|
+
def native_types(object,keys_as_symbols=false)
|
141
|
+
return if object.nil?
|
142
|
+
|
143
|
+
if(object.is_a?(CFDate) || object.is_a?(CFString) || object.is_a?(CFInteger) || object.is_a?(CFReal) || object.is_a?(CFBoolean)) then
|
144
|
+
return object.value
|
145
|
+
elsif(object.is_a?(CFData)) then
|
146
|
+
return object.decoded_value
|
147
|
+
elsif(object.is_a?(CFArray)) then
|
148
|
+
ary = []
|
149
|
+
object.value.each do
|
150
|
+
|v|
|
151
|
+
ary.push CFPropertyList.native_types(v)
|
152
|
+
end
|
153
|
+
|
154
|
+
return ary
|
155
|
+
elsif(object.is_a?(CFDictionary)) then
|
156
|
+
hsh = {}
|
157
|
+
object.value.each_pair do
|
158
|
+
|k,v|
|
159
|
+
k = k.to_sym if keys_as_symbols
|
160
|
+
hsh[k] = CFPropertyList.native_types(v)
|
161
|
+
end
|
162
|
+
|
163
|
+
return hsh
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
module_function :guess, :native_types
|
168
|
+
|
169
|
+
# Class representing a CFPropertyList. Instanciate with #new
|
170
|
+
class List
|
171
|
+
# Format constant for binary format
|
172
|
+
FORMAT_BINARY = 1
|
173
|
+
|
174
|
+
# Format constant for XML format
|
175
|
+
FORMAT_XML = 2
|
176
|
+
|
177
|
+
# Format constant for automatic format recognizing
|
178
|
+
FORMAT_AUTO = 0
|
179
|
+
|
180
|
+
@@parsers = [Binary,XML]
|
181
|
+
|
182
|
+
# Path of PropertyList
|
183
|
+
attr_accessor :filename
|
184
|
+
# Path of PropertyList
|
185
|
+
attr_accessor :format
|
186
|
+
# the root value in the plist file
|
187
|
+
attr_accessor :value
|
188
|
+
|
189
|
+
# initialize a new CFPropertyList, arguments are:
|
190
|
+
#
|
191
|
+
# :file:: Parse a file
|
192
|
+
# :format:: Format is one of FORMAT_BINARY or FORMAT_XML. Defaults to FORMAT_AUTO
|
193
|
+
# :data:: Parse a string
|
194
|
+
#
|
195
|
+
# All arguments are optional
|
196
|
+
def initialize(opts={})
|
197
|
+
@filename = opts[:file]
|
198
|
+
@format = opts[:format] || FORMAT_AUTO
|
199
|
+
@data = opts[:data]
|
200
|
+
|
201
|
+
load(@filename) unless @filename.nil?
|
202
|
+
load_str(@data) unless @data.nil?
|
203
|
+
end
|
204
|
+
|
205
|
+
# Load an XML PropertyList
|
206
|
+
# filename = nil:: The filename to read from; if nil, read from the file defined by instance variable +filename+
|
207
|
+
def load_xml(filename=nil)
|
208
|
+
load(filename,List::FORMAT_XML)
|
209
|
+
end
|
210
|
+
|
211
|
+
# read a binary plist file
|
212
|
+
# filename = nil:: The filename to read from; if nil, read from the file defined by instance variable +filename+
|
213
|
+
def load_binary(filename=nil)
|
214
|
+
load(filename,List::FORMAT_BINARY)
|
215
|
+
end
|
216
|
+
|
217
|
+
# load a plist from a XML string
|
218
|
+
# str:: The string containing the plist
|
219
|
+
def load_xml_str(str=nil)
|
220
|
+
load_str(str,List::FORMAT_XML)
|
221
|
+
end
|
222
|
+
|
223
|
+
# load a plist from a binary string
|
224
|
+
# str:: The string containing the plist
|
225
|
+
def load_binary_str(str=nil)
|
226
|
+
load_str(str,List::FORMAT_BINARY)
|
227
|
+
end
|
228
|
+
|
229
|
+
# load a plist from a string
|
230
|
+
# str = nil:: The string containing the plist
|
231
|
+
# format = nil:: The format of the plist
|
232
|
+
def load_str(str=nil,format=nil)
|
233
|
+
str = @data if str.nil?
|
234
|
+
format = @format if format.nil?
|
235
|
+
|
236
|
+
@value = {}
|
237
|
+
case format
|
238
|
+
when List::FORMAT_BINARY, List::FORMAT_XML then
|
239
|
+
prsr = @@parsers[format-1].new
|
240
|
+
@value = prsr.load({:data => str})
|
241
|
+
|
242
|
+
when List::FORMAT_AUTO then # what we now do is ugly, but neccessary to recognize the file format
|
243
|
+
filetype = str[0..5]
|
244
|
+
version = str[6..7]
|
245
|
+
|
246
|
+
prsr = nil
|
247
|
+
if filetype == "bplist" then
|
248
|
+
raise CFFormatError.new("Wong file version #{version}") unless version == "00"
|
249
|
+
prsr = Binary.new
|
250
|
+
else
|
251
|
+
prsr = XML.new
|
252
|
+
end
|
253
|
+
|
254
|
+
@value = prsr.load({:data => str})
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
# Read a plist file
|
259
|
+
# file = nil:: The filename of the file to read. If nil, use +filename+ instance variable
|
260
|
+
# format = nil:: The format of the plist file. Auto-detect if nil
|
261
|
+
def load(file=nil,format=nil)
|
262
|
+
file = @filename if file.nil?
|
263
|
+
format = @format if format.nil?
|
264
|
+
@value = {}
|
265
|
+
|
266
|
+
raise IOError.new("File #{file} not readable!") unless File.readable? file
|
267
|
+
|
268
|
+
case format
|
269
|
+
when List::FORMAT_BINARY, List::FORMAT_XML then
|
270
|
+
prsr = @@parsers[format-1].new
|
271
|
+
@value = prsr.load({:file => file})
|
272
|
+
|
273
|
+
when List::FORMAT_AUTO then # what we now do is ugly, but neccessary to recognize the file format
|
274
|
+
magic_number = IO.read(file,8)
|
275
|
+
filetype = magic_number[0..5]
|
276
|
+
version = magic_number[6..7]
|
277
|
+
|
278
|
+
prsr = nil
|
279
|
+
if filetype == "bplist" then
|
280
|
+
raise CFFormatError.new("Wong file version #{version}") unless version == "00"
|
281
|
+
prsr = Binary.new
|
282
|
+
else
|
283
|
+
prsr = XML.new
|
284
|
+
end
|
285
|
+
|
286
|
+
@value = prsr.load({:file => file})
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# Serialize CFPropertyList object to specified format and write it to file
|
291
|
+
# file = nil:: The filename of the file to write to. Uses +filename+ instance variable if nil
|
292
|
+
# format = nil:: The format to save in. Uses +format+ instance variable if nil
|
293
|
+
def save(file=nil,format=nil,opts={})
|
294
|
+
format = @format if format.nil?
|
295
|
+
file = @filename if file.nil?
|
296
|
+
|
297
|
+
raise CFFormatError.new("Format #{format} not supported, use List::FORMAT_BINARY or List::FORMAT_XML") if format != FORMAT_BINARY && format != FORMAT_XML
|
298
|
+
|
299
|
+
if(!File.exists?(file)) then
|
300
|
+
raise IOError.new("File #{file} not writable!") unless File.writable?(File.dirname(file))
|
301
|
+
elsif(!File.writable?(file)) then
|
302
|
+
raise IOError.new("File #{file} not writable!")
|
303
|
+
end
|
304
|
+
|
305
|
+
opts[:root] = @value
|
306
|
+
prsr = @@parsers[format-1].new
|
307
|
+
content = prsr.to_str(opts)
|
308
|
+
|
309
|
+
File.open(file, 'wb') {
|
310
|
+
|fd|
|
311
|
+
fd.write content
|
312
|
+
}
|
313
|
+
end
|
314
|
+
|
315
|
+
# convert plist to string
|
316
|
+
# format = List::FORMAT_BINARY:: The format to save the plist
|
317
|
+
# opts={}:: Pass parser options
|
318
|
+
def to_str(format=List::FORMAT_BINARY,opts={})
|
319
|
+
prsr = @@parsers[format-1].new
|
320
|
+
opts[:root] = @value
|
321
|
+
return prsr.to_str(opts)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
class Array
|
327
|
+
# convert an array to plist format
|
328
|
+
def to_plist(options={})
|
329
|
+
options[:plist_format] ||= CFPropertyList::List::FORMAT_BINARY
|
330
|
+
|
331
|
+
plist = CFPropertyList::List.new
|
332
|
+
plist.value = CFPropertyList.guess(self, options)
|
333
|
+
plist.to_str(options[:plist_format])
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
class Hash
|
338
|
+
# convert a hash to plist format
|
339
|
+
def to_plist(options={})
|
340
|
+
options[:plist_format] ||= CFPropertyList::List::FORMAT_BINARY
|
341
|
+
|
342
|
+
plist = CFPropertyList::List.new
|
343
|
+
plist.value = CFPropertyList.guess(self, options)
|
344
|
+
plist.to_str(options[:plist_format])
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
# eof
|
@@ -0,0 +1,241 @@
|
|
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:: MIT License
|
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
|
+
@raw_value = value
|
161
|
+
@raw_value.blob = true
|
162
|
+
else
|
163
|
+
@value = value
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# get base64 encoded value
|
168
|
+
def encoded_value
|
169
|
+
@value ||= Base64.encode64(@raw_value)
|
170
|
+
end
|
171
|
+
|
172
|
+
# get base64 decoded value
|
173
|
+
def decoded_value
|
174
|
+
@raw_value ||= String.new(Base64.decode64(@value))
|
175
|
+
@raw_value.blob = true
|
176
|
+
@raw_value
|
177
|
+
end
|
178
|
+
|
179
|
+
# convert to XML
|
180
|
+
def to_xml
|
181
|
+
return LibXML::XML::Node.new('data') << LibXML::XML::Node.new_text(encoded_value())
|
182
|
+
end
|
183
|
+
|
184
|
+
# convert to binary
|
185
|
+
def to_binary(bplist)
|
186
|
+
return bplist.data_to_binary(decoded_value())
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# This class contains an array of values
|
191
|
+
class CFArray < CFType
|
192
|
+
# create a new array CFType
|
193
|
+
def initialize(val=[])
|
194
|
+
@value = val
|
195
|
+
end
|
196
|
+
|
197
|
+
# convert to XML
|
198
|
+
def to_xml
|
199
|
+
n = LibXML::XML::Node.new('array')
|
200
|
+
@value.each do
|
201
|
+
|v|
|
202
|
+
n << v.to_xml
|
203
|
+
end
|
204
|
+
|
205
|
+
return n
|
206
|
+
end
|
207
|
+
|
208
|
+
# convert to binary
|
209
|
+
def to_binary(bplist)
|
210
|
+
return bplist.array_to_binary(self)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# this class contains a hash of values
|
215
|
+
class CFDictionary < CFType
|
216
|
+
# Create new CFDictonary type.
|
217
|
+
def initialize(value={})
|
218
|
+
@value = value
|
219
|
+
end
|
220
|
+
|
221
|
+
# convert to XML
|
222
|
+
def to_xml
|
223
|
+
n = LibXML::XML::Node.new('dict')
|
224
|
+
@value.each_pair do
|
225
|
+
|key,value|
|
226
|
+
k = LibXML::XML::Node.new('key') << LibXML::XML::Node.new_text(key)
|
227
|
+
n << k
|
228
|
+
n << value.to_xml
|
229
|
+
end
|
230
|
+
|
231
|
+
return n
|
232
|
+
end
|
233
|
+
|
234
|
+
# convert to binary
|
235
|
+
def to_binary(bplist)
|
236
|
+
return bplist.dict_to_binary(self)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# eof
|