CFPropertyList 2.2.8 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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