CFPropertyList 2.2.8 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a2c18e8671e6aa61b76ef1b99fff2850b2746c4d
4
- data.tar.gz: 153b07e4656885b5cd155af83555dad763a17e1a
3
+ metadata.gz: bc33e5b367dbce4a691398d57944021021aef03f
4
+ data.tar.gz: 67607311e62f42c8c7db8e41e318342fbb1188a0
5
5
  SHA512:
6
- metadata.gz: 75f4be2ff85f13c0309b7c7fe390b721a5ee98d454aa45a010ba03288381a0f9c6e90539f7c34921685c5ef92e8803ab7469ce826059bfa777a98d001974d3fe
7
- data.tar.gz: b7842bee8b9cb899b432880b16e675c78e4cb87ed64c473efb988c2dd4313266844b1f341f8b659e0baeaca9ad0bf7fa81fbc74f763ea53c8ecedafd149d59a3
6
+ metadata.gz: 22cfa79f7cde0aeaa04896c06dbbe866a9945853903abe3049fc462a60fa7fd031b384d8a1059338d5655a260091fced46909027321b02b0f012d773715b817b
7
+ data.tar.gz: 3951e013406ade3ef418b75f188e9c48a0ec49f1dda6eec74fa3f2b3aa722e4f9383ad0b98a4707c3a8f53b587d837a893288c4c74b8a81de563adaf907d3bb7
@@ -84,6 +84,7 @@ dirname = File.dirname(__FILE__)
84
84
  require dirname + '/rbCFPlistError.rb'
85
85
  require dirname + '/rbCFTypes.rb'
86
86
  require dirname + '/rbBinaryCFPropertyList.rb'
87
+ require dirname + '/rbPlainCFPropertyList.rb'
87
88
 
88
89
  require 'iconv' unless "".respond_to?("encode")
89
90
 
@@ -218,10 +219,13 @@ module CFPropertyList
218
219
  # Format constant for XML format
219
220
  FORMAT_XML = 2
220
221
 
222
+ # Format constant for the old plain format
223
+ FORMAT_PLAIN = 3
224
+
221
225
  # Format constant for automatic format recognizing
222
226
  FORMAT_AUTO = 0
223
227
 
224
- @@parsers = [Binary, CFPropertyList.xml_parser_interface]
228
+ @@parsers = [Binary, CFPropertyList.xml_parser_interface, PlainParser]
225
229
 
226
230
  # Path of PropertyList
227
231
  attr_accessor :filename
@@ -271,6 +275,12 @@ module CFPropertyList
271
275
  load(filename,List::FORMAT_BINARY)
272
276
  end
273
277
 
278
+ # read a plain plist file
279
+ # filename = nil:: The filename to read from; if nil, read from the file defined by instance variable +filename+
280
+ def load_plain(filename=nil)
281
+ load(filename,List::FORMAT_PLAIN)
282
+ end
283
+
274
284
  # load a plist from a XML string
275
285
  # str:: The string containing the plist
276
286
  def load_xml_str(str=nil)
@@ -283,6 +293,12 @@ module CFPropertyList
283
293
  load_str(str,List::FORMAT_BINARY)
284
294
  end
285
295
 
296
+ # load a plist from a plain string
297
+ # str:: The string containing the plist
298
+ def load_binary_str(str=nil)
299
+ load_str(str,List::FORMAT_PLAIN)
300
+ end
301
+
286
302
  # load a plist from a string
287
303
  # str = nil:: The string containing the plist
288
304
  # format = nil:: The format of the plist
@@ -292,7 +308,7 @@ module CFPropertyList
292
308
 
293
309
  @value = {}
294
310
  case format
295
- when List::FORMAT_BINARY, List::FORMAT_XML then
311
+ when List::FORMAT_BINARY, List::FORMAT_XML, List::FORMAT_PLAIN then
296
312
  prsr = @@parsers[format-1].new
297
313
  @value = prsr.load({:data => str})
298
314
 
@@ -301,13 +317,19 @@ module CFPropertyList
301
317
  version = str[6..7]
302
318
 
303
319
  prsr = nil
320
+
304
321
  if filetype == "bplist" then
305
322
  raise CFFormatError.new("Wrong file version #{version}") unless version == "00"
306
323
  prsr = Binary.new
307
324
  @format = List::FORMAT_BINARY
308
325
  else
309
- prsr = CFPropertyList.xml_parser_interface.new
310
- @format = List::FORMAT_XML
326
+ if str =~ /^<(\?xml|!DOCTYPE|plist)/
327
+ prsr = CFPropertyList.xml_parser_interface.new
328
+ @format = List::FORMAT_XML
329
+ else
330
+ prsr = PlainParser.new
331
+ @format = List::FORMAT_PLAIN
332
+ end
311
333
  end
312
334
 
313
335
  @value = prsr.load({:data => str})
@@ -325,12 +347,12 @@ module CFPropertyList
325
347
  raise IOError.new("File #{file} not readable!") unless File.readable? file
326
348
 
327
349
  case format
328
- when List::FORMAT_BINARY, List::FORMAT_XML then
350
+ when List::FORMAT_BINARY, List::FORMAT_XML, List::FORMAT_PLAIN then
329
351
  prsr = @@parsers[format-1].new
330
352
  @value = prsr.load({:file => file})
331
353
 
332
354
  when List::FORMAT_AUTO then # what we now do is ugly, but neccessary to recognize the file format
333
- magic_number = IO.read(file,8)
355
+ magic_number = IO.read(file,12)
334
356
  raise IOError.new("File #{file} is empty.") unless magic_number
335
357
  filetype = magic_number[0..5]
336
358
  version = magic_number[6..7]
@@ -341,8 +363,13 @@ module CFPropertyList
341
363
  prsr = Binary.new
342
364
  @format = List::FORMAT_BINARY
343
365
  else
344
- prsr = CFPropertyList.xml_parser_interface.new
345
- @format = List::FORMAT_XML
366
+ if magic_number =~ /^<(\?xml|!DOCTYPE|plist)/
367
+ prsr = CFPropertyList.xml_parser_interface.new
368
+ @format = List::FORMAT_XML
369
+ else
370
+ prsr = PlainParser.new
371
+ @format = List::FORMAT_PLAIN
372
+ end
346
373
  end
347
374
 
348
375
  @value = prsr.load({:file => file})
@@ -358,7 +385,9 @@ module CFPropertyList
358
385
  format = @format if format.nil?
359
386
  file = @filename if file.nil?
360
387
 
361
- raise CFFormatError.new("Format #{format} not supported, use List::FORMAT_BINARY or List::FORMAT_XML") if format != FORMAT_BINARY && format != FORMAT_XML
388
+ if format != FORMAT_BINARY && format != FORMAT_XML && format != FORMAT_PLAIN
389
+ raise CFFormatError.new("Format #{format} not supported, use List::FORMAT_BINARY or List::FORMAT_XML")
390
+ end
362
391
 
363
392
  if(!File.exists?(file)) then
364
393
  raise IOError.new("File #{file} not writable!") unless File.writable?(File.dirname(file))
@@ -383,7 +412,9 @@ module CFPropertyList
383
412
  # format = List::FORMAT_BINARY:: The format to save the plist
384
413
  # opts={}:: Pass parser options
385
414
  def to_str(format=List::FORMAT_BINARY,opts={})
386
- raise CFFormatError.new("Format #{format} not supported, use List::FORMAT_BINARY or List::FORMAT_XML") if format != FORMAT_BINARY && format != FORMAT_XML
415
+ if format != FORMAT_BINARY && format != FORMAT_XML && format != FORMAT_PLAIN
416
+ raise CFFormatError.new("Format #{format} not supported, use List::FORMAT_BINARY or List::FORMAT_XML")
417
+ end
387
418
 
388
419
  prsr = @@parsers[format-1].new
389
420
 
@@ -37,7 +37,11 @@ module CFPropertyList
37
37
  def to_xml(parser)
38
38
  end
39
39
 
40
- def to_binary(bplist) end
40
+ def to_binary(bplist)
41
+ end
42
+
43
+ def to_plain(plist)
44
+ end
41
45
  end
42
46
 
43
47
  # This class holds string values, both, UTF-8 and UTF-16BE
@@ -54,6 +58,44 @@ module CFPropertyList
54
58
  def to_binary(bplist)
55
59
  bplist.string_to_binary(@value);
56
60
  end
61
+
62
+ def to_plain(plist)
63
+ if @value =~ /^\w+$/
64
+ @value
65
+ else
66
+ quoted
67
+ end
68
+ end
69
+
70
+ def quoted
71
+ str = '"'
72
+ @value.each_char do |c|
73
+ str << case c
74
+ when '"'
75
+ '\\"'
76
+ when '\\'
77
+ '\\'
78
+ when "\a"
79
+ "\\a"
80
+ when "\b"
81
+ "\\b"
82
+ when "\f"
83
+ "\\f"
84
+ when "\n"
85
+ "\n"
86
+ when "\v"
87
+ "\\v"
88
+ when "\r"
89
+ "\\r"
90
+ when "\t"
91
+ "\\t"
92
+ else
93
+ c
94
+ end
95
+ end
96
+
97
+ str << '"'
98
+ end
57
99
  end
58
100
 
59
101
  # This class holds integer/fixnum values
@@ -69,6 +111,10 @@ module CFPropertyList
69
111
  def to_binary(bplist)
70
112
  bplist.num_to_binary(self)
71
113
  end
114
+
115
+ def to_plain(plist)
116
+ @value.to_s
117
+ end
72
118
  end
73
119
 
74
120
  # This class holds float values
@@ -84,6 +130,10 @@ module CFPropertyList
84
130
  def to_binary(bplist)
85
131
  bplist.num_to_binary(self)
86
132
  end
133
+
134
+ def to_plain(plist)
135
+ @value.to_s
136
+ end
87
137
  end
88
138
 
89
139
  # This class holds Time values. While Apple uses seconds since 2001,
@@ -92,7 +142,7 @@ module CFPropertyList
92
142
  # geht the timestamp or the Apple timestamp
93
143
  class CFDate < CFType
94
144
  TIMESTAMP_APPLE = 0
95
- TIMESTAMP_UNIX = 1;
145
+ TIMESTAMP_UNIX = 1
96
146
  DATE_DIFF_APPLE_UNIX = 978307200
97
147
 
98
148
  # create a XML date strimg from a time object
@@ -151,6 +201,10 @@ module CFPropertyList
151
201
  def to_binary(bplist)
152
202
  bplist.date_to_binary(@value)
153
203
  end
204
+
205
+ def to_plain(plist)
206
+ @value.strftime("%Y-%m-%d %H:%M:%S %z")
207
+ end
154
208
  end
155
209
 
156
210
  # This class contains a boolean value
@@ -164,6 +218,10 @@ module CFPropertyList
164
218
  def to_binary(bplist)
165
219
  bplist.bool_to_binary(@value);
166
220
  end
221
+
222
+ def to_plain(plist)
223
+ @value ? "true" : "false"
224
+ end
167
225
  end
168
226
 
169
227
  # This class contains binary data values
@@ -203,6 +261,10 @@ module CFPropertyList
203
261
  def to_binary(bplist)
204
262
  bplist.data_to_binary(decoded_value())
205
263
  end
264
+
265
+ def to_plain(plist)
266
+ "<" + decoded_value.unpack("H*").join("") + ">"
267
+ end
206
268
  end
207
269
 
208
270
  # This class contains an array of values
@@ -225,6 +287,11 @@ module CFPropertyList
225
287
  def to_binary(bplist)
226
288
  bplist.array_to_binary(self)
227
289
  end
290
+
291
+ def to_plain(plist)
292
+ ary = @value.map { |v| v.to_plain(plist) }
293
+ "( " + ary.join(", ") + " )"
294
+ end
228
295
  end
229
296
 
230
297
  # this class contains a hash of values
@@ -249,6 +316,18 @@ module CFPropertyList
249
316
  def to_binary(bplist)
250
317
  bplist.dict_to_binary(self)
251
318
  end
319
+
320
+ def to_plain(plist)
321
+ str = "{ "
322
+ cfstr = CFString.new()
323
+
324
+ @value.each do |k,v|
325
+ cfstr.value = k
326
+ str << cfstr.to_plain(plist) + " = " + v.to_plain(plist) + "; "
327
+ end
328
+
329
+ str << "}"
330
+ end
252
331
  end
253
332
 
254
333
  class CFUid < CFType
@@ -260,6 +339,10 @@ module CFPropertyList
260
339
  def to_binary(bplist)
261
340
  bplist.uid_to_binary(@value)
262
341
  end
342
+
343
+ def to_plain(plist)
344
+ CFDictionary.new({'CF$UID' => CFInteger.new(@value)}).to_plain(plist)
345
+ end
263
346
  end
264
347
  end
265
348
 
@@ -0,0 +1,197 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'strscan'
4
+
5
+ module CFPropertyList
6
+ # XML parser
7
+ class PlainParser < XMLParserInterface
8
+ # read a XML file
9
+ # opts::
10
+ # * :file - The filename of the file to load
11
+ # * :data - The data to parse
12
+ def load(opts)
13
+ @doc = nil
14
+
15
+ if(opts.has_key?(:file)) then
16
+ File.open(opts[:file], :external_encoding => "ASCII") do |fd|
17
+ @doc = StringScanner.new(fd.read)
18
+ end
19
+ else
20
+ @doc = StringScanner.new(opts[:data])
21
+ end
22
+
23
+ if @doc
24
+ root = import_plain
25
+ raise CFFormatError.new('content after root object') unless @doc.eos?
26
+
27
+ return root
28
+ end
29
+
30
+ raise CFFormatError.new('invalid plist string or file not found')
31
+ end
32
+
33
+ SPACES_AND_COMMENTS = %r{((?:/\*.*?\*/)|(?://.*?$\n?)|(?:\s*))+}x
34
+
35
+ # serialize CFPropertyList object to XML
36
+ # opts = {}:: Specify options: :formatted - Use indention and line breaks
37
+ def to_str(opts={})
38
+ opts[:root].to_plain(self)
39
+ end
40
+
41
+ protected
42
+ def skip_whitespaces
43
+ @doc.skip SPACES_AND_COMMENTS
44
+ end
45
+
46
+ def read_dict
47
+ skip_whitespaces
48
+ hsh = {}
49
+
50
+ while not @doc.scan(/\}/)
51
+ key = import_plain
52
+ raise CFFormatError.new("invalid dictionary format") if !key
53
+
54
+ if key.is_a?(CFString)
55
+ key = key.value
56
+ elsif key.is_a?(CFInteger) or key.is_a?(CFReal)
57
+ key = key.value.to_s
58
+ else
59
+ raise CFFormatError.new("invalid key format")
60
+ end
61
+
62
+ skip_whitespaces
63
+
64
+ raise CFFormatError.new("invalid dictionary format") unless @doc.scan(/=/)
65
+
66
+ skip_whitespaces
67
+ val = import_plain
68
+
69
+ skip_whitespaces
70
+ raise CFFormatError.new("invalid dictionary format") unless @doc.scan(/;/)
71
+ skip_whitespaces
72
+
73
+ hsh[key] = val
74
+ raise CFFormatError.new("invalid dictionary format") if @doc.eos?
75
+ end
76
+
77
+ CFDictionary.new(hsh)
78
+ end
79
+
80
+ def read_array
81
+ skip_whitespaces
82
+ ary = []
83
+
84
+ while not @doc.scan(/\)/)
85
+ val = import_plain
86
+
87
+ return nil if not val or not val.value
88
+ skip_whitespaces
89
+
90
+ if not @doc.skip(/,\s*/)
91
+ if @doc.scan(/\)/)
92
+ ary << val
93
+ return CFArray.new(ary)
94
+ end
95
+
96
+ raise CFFormatError.new("invalid array format")
97
+ end
98
+
99
+ ary << val
100
+ raise CFFormatError.new("invalid array format") if @doc.eos?
101
+ end
102
+
103
+ CFArray.new(ary)
104
+ end
105
+
106
+ def escape_char
107
+ case @doc.matched
108
+ when '"'
109
+ '"'
110
+ when '\\'
111
+ '\\'
112
+ when 'a'
113
+ "\a"
114
+ when 'b'
115
+ "\b"
116
+ when 'f'
117
+ "\f"
118
+ when 'n'
119
+ "\n"
120
+ when 'v'
121
+ "\v"
122
+ when 'r'
123
+ "\r"
124
+ when 't'
125
+ "\t"
126
+ end
127
+ end
128
+
129
+ def read_quoted
130
+ str = ''
131
+
132
+ while not @doc.scan(/"/)
133
+ if @doc.scan(/\\/)
134
+ @doc.scan(/./)
135
+ str << escape_char
136
+
137
+ elsif @doc.eos?
138
+ raise CFFormatError.new("unterminated string")
139
+
140
+ else @doc.scan(/./)
141
+ str << @doc.matched
142
+ end
143
+ end
144
+
145
+ CFString.new(str)
146
+ end
147
+
148
+ def read_unquoted
149
+ raise CFFormatError.new("unexpected end of file") if @doc.eos?
150
+
151
+ if @doc.scan(/(\d\d\d\d)-(\d\d)-(\d\d)\s+(\d\d):(\d\d):(\d\d)(?:\s+(\+|-)(\d\d)(\d\d))?/)
152
+ year,month,day,hour,min,sec,pl_min,tz_hour, tz_min = @doc[1], @doc[2], @doc[3], @doc[4], @doc[5], @doc[6], @doc[7], @doc[8], @doc[9]
153
+ CFDate.new(Time.new(year, month, day, hour, min, sec, pl_min ? sprintf("%s%s:%s", pl_min, tz_hour, tz_min) : nil))
154
+
155
+ elsif @doc.scan(/-?\d+?\.\d+\b/)
156
+ CFReal.new(@doc.matched.to_f)
157
+
158
+ elsif @doc.scan(/-?\d+\b/)
159
+ CFInteger.new(@doc.matched.to_i)
160
+
161
+ elsif @doc.scan(/\b(true|false)\b/)
162
+ CFBoolean.new(@doc.matched == 'true')
163
+ else
164
+ CFString.new(@doc.scan(/\w+/))
165
+ end
166
+ end
167
+
168
+ def read_binary
169
+ @doc.scan(/(.*?)>/)
170
+
171
+ hex_str = @doc[1].gsub(/ /, '')
172
+ CFData.new([hex_str].pack("H*"), CFData::DATA_RAW)
173
+ end
174
+
175
+ # import the XML values
176
+ def import_plain
177
+ skip_whitespaces
178
+ ret = nil
179
+
180
+ if @doc.scan(/\{/) # dict
181
+ ret = read_dict
182
+ elsif @doc.scan(/\(/) # array
183
+ ret = read_array
184
+ elsif @doc.scan(/"/) # string
185
+ ret = read_quoted
186
+ elsif @doc.scan(/</) # binary
187
+ ret = read_binary
188
+ else # string w/o quotes
189
+ ret = read_unquoted
190
+ end
191
+
192
+ return ret
193
+ end
194
+ end
195
+ end
196
+
197
+ # eof
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: CFPropertyList
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.8
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Kruse
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-10 00:00:00.000000000 Z
11
+ date: 2015-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -40,6 +40,7 @@ files:
40
40
  - lib/cfpropertylist/rbCFTypes.rb
41
41
  - lib/cfpropertylist/rbLibXMLParser.rb
42
42
  - lib/cfpropertylist/rbNokogiriParser.rb
43
+ - lib/cfpropertylist/rbPlainCFPropertyList.rb
43
44
  - lib/cfpropertylist/rbREXMLParser.rb
44
45
  homepage: http://github.com/ckruse/CFPropertyList
45
46
  licenses:
@@ -61,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
62
  version: '0'
62
63
  requirements: []
63
64
  rubyforge_project:
64
- rubygems_version: 2.2.2
65
+ rubygems_version: 2.4.5
65
66
  signing_key:
66
67
  specification_version: 4
67
68
  summary: Read, write and manipulate both binary and XML property lists as defined