CFPropertyList 2.0.14 → 3.0.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.
@@ -0,0 +1,199 @@
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
+ when 'U'
127
+ @doc.scan(/.{4}/).hex.chr('utf-8')
128
+ end
129
+ end
130
+
131
+ def read_quoted
132
+ str = ''
133
+
134
+ while not @doc.scan(/"/)
135
+ if @doc.scan(/\\/)
136
+ @doc.scan(/./)
137
+ str << escape_char
138
+
139
+ elsif @doc.eos?
140
+ raise CFFormatError.new("unterminated string")
141
+
142
+ else @doc.scan(/./)
143
+ str << @doc.matched
144
+ end
145
+ end
146
+
147
+ CFString.new(str)
148
+ end
149
+
150
+ def read_unquoted
151
+ raise CFFormatError.new("unexpected end of file") if @doc.eos?
152
+
153
+ if @doc.scan(/(\d\d\d\d)-(\d\d)-(\d\d)\s+(\d\d):(\d\d):(\d\d)(?:\s+(\+|-)(\d\d)(\d\d))?/)
154
+ 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]
155
+ CFDate.new(Time.new(year, month, day, hour, min, sec, pl_min ? sprintf("%s%s:%s", pl_min, tz_hour, tz_min) : nil))
156
+
157
+ elsif @doc.scan(/-?\d+?\.\d+\b/)
158
+ CFReal.new(@doc.matched.to_f)
159
+
160
+ elsif @doc.scan(/-?\d+\b/)
161
+ CFInteger.new(@doc.matched.to_i)
162
+
163
+ elsif @doc.scan(/\b(true|false)\b/)
164
+ CFBoolean.new(@doc.matched == 'true')
165
+ else
166
+ CFString.new(@doc.scan(/\w+/))
167
+ end
168
+ end
169
+
170
+ def read_binary
171
+ @doc.scan(/(.*?)>/)
172
+
173
+ hex_str = @doc[1].gsub(/ /, '')
174
+ CFData.new([hex_str].pack("H*"), CFData::DATA_RAW)
175
+ end
176
+
177
+ # import the XML values
178
+ def import_plain
179
+ skip_whitespaces
180
+ ret = nil
181
+
182
+ if @doc.scan(/\{/) # dict
183
+ ret = read_dict
184
+ elsif @doc.scan(/\(/) # array
185
+ ret = read_array
186
+ elsif @doc.scan(/"/) # string
187
+ ret = read_quoted
188
+ elsif @doc.scan(/</) # binary
189
+ ret = read_binary
190
+ else # string w/o quotes
191
+ ret = read_unquoted
192
+ end
193
+
194
+ return ret
195
+ end
196
+ end
197
+ end
198
+
199
+ # eof
@@ -0,0 +1,148 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'rexml/document'
4
+
5
+ module CFPropertyList
6
+ # XML parser
7
+ class ReXMLParser < ParserInterface
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
+
14
+ doc = nil
15
+ if(opts.has_key?(:file)) then
16
+ File.open(opts[:file], "rb") { |fd| doc = REXML::Document.new(fd) }
17
+ else
18
+ doc = REXML::Document.new(opts[:data])
19
+ end
20
+
21
+ if doc
22
+ root = doc.root.elements[1]
23
+ return import_xml(root)
24
+ end
25
+ rescue REXML::ParseException => e
26
+ raise CFFormatError.new('invalid XML: ' + e.message)
27
+ end
28
+
29
+ # serialize CFPropertyList object to XML
30
+ # opts = {}:: Specify options: :formatted - Use indention and line breaks
31
+ def to_str(opts={})
32
+ doc = REXML::Document.new
33
+ @doc = doc
34
+
35
+ doc.context[:attribute_quote] = :quote
36
+
37
+ doc.add_element 'plist', {'version' => '1.0'}
38
+ doc.root << opts[:root].to_xml(self)
39
+
40
+ formatter = if opts[:formatted] then
41
+ f = REXML::Formatters::Pretty.new(2)
42
+ f.compact = true
43
+ f.width = Float::INFINITY
44
+ f
45
+ else
46
+ REXML::Formatters::Default.new
47
+ end
48
+
49
+ str = formatter.write(doc.root, "")
50
+ str1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + str + "\n"
51
+ str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding)
52
+
53
+ return str1
54
+ end
55
+
56
+ def new_node(name)
57
+ REXML::Element.new(name)
58
+ end
59
+
60
+ def new_text(val)
61
+ val
62
+ end
63
+
64
+ def append_node(parent, child)
65
+ if child.is_a?(String) then
66
+ parent.add_text child
67
+ else
68
+ parent.elements << child
69
+ end
70
+ parent
71
+ end
72
+
73
+ protected
74
+
75
+ # get the value of a DOM node
76
+ def get_value(n)
77
+ content = n.text
78
+
79
+ content.force_encoding('UTF-8') if content.respond_to?(:force_encoding)
80
+ content
81
+ end
82
+
83
+ # import the XML values
84
+ def import_xml(node)
85
+ ret = nil
86
+
87
+ case node.name
88
+ when 'dict'
89
+ hsh = Hash.new
90
+ key = nil
91
+
92
+ if node.has_elements? then
93
+ node.elements.each do |n|
94
+ next if n.name == '#text' # avoid a bug of libxml
95
+ next if n.name == '#comment'
96
+
97
+ if n.name == "key" then
98
+ key = get_value(n)
99
+ key = '' if key.nil? # REXML returns nil if key is empty
100
+ else
101
+ raise CFFormatError.new("Format error!") if key.nil?
102
+ hsh[key] = import_xml(n)
103
+ key = nil
104
+ end
105
+ end
106
+ end
107
+
108
+ if hsh['CF$UID'] and hsh.keys.length == 1
109
+ ret = CFUid.new(hsh['CF$UID'].value)
110
+ else
111
+ ret = CFDictionary.new(hsh)
112
+ end
113
+
114
+ when 'array'
115
+ ary = Array.new
116
+
117
+ if node.has_elements? then
118
+ node.elements.each do |n|
119
+ next if n.name == '#text' # avoid a bug of libxml
120
+ ary.push import_xml(n)
121
+ end
122
+ end
123
+
124
+ ret = CFArray.new(ary)
125
+
126
+ when 'true'
127
+ ret = CFBoolean.new(true)
128
+ when 'false'
129
+ ret = CFBoolean.new(false)
130
+ when 'real'
131
+ ret = CFReal.new(get_value(node).to_f)
132
+ when 'integer'
133
+ ret = CFInteger.new(get_value(node).to_i)
134
+ when 'string'
135
+ ret = CFString.new(get_value(node))
136
+ ret.value = '' if ret.value.nil? # REXML returns nil for empty elements' .text attribute
137
+ when 'data'
138
+ ret = CFData.new(get_value(node))
139
+ when 'date'
140
+ ret = CFDate.new(CFDate.parse_date(get_value(node)))
141
+ end
142
+
143
+ return ret
144
+ end
145
+ end
146
+ end
147
+
148
+ # eof
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- require File.dirname(__FILE__) + '/rbCFPropertyList.rb'
3
+ require 'cfpropertylist/rbCFPropertyList'
4
4
 
5
5
 
6
- # eof
6
+ # eof
metadata CHANGED
@@ -1,80 +1,73 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: CFPropertyList
3
- version: !ruby/object:Gem::Version
4
- version: 2.0.14
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.0
5
5
  platform: ruby
6
- authors:
6
+ authors:
7
7
  - Christian Kruse
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
-
12
- date: 2010-09-27 00:00:00 +02:00
13
- default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: libxml-ruby
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 1.1.0
24
- version:
25
- - !ruby/object:Gem::Dependency
11
+ date: 2018-01-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
26
14
  name: rake
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.7.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
31
24
  - - ">="
32
- - !ruby/object:Gem::Version
25
+ - !ruby/object:Gem::Version
33
26
  version: 0.7.0
34
- version:
35
- description: This is a module to read, write and manipulate both binary and XML property lists as defined by apple.
36
- email: cjk@wwwtech.de
27
+ description: This is a module to read, write and manipulate both binary and XML property
28
+ lists as defined by apple.
29
+ email: cjk@defunct.ch
37
30
  executables: []
38
-
39
31
  extensions: []
40
-
41
- extra_rdoc_files:
42
- - README
43
- files:
32
+ extra_rdoc_files:
33
+ - README.rdoc
34
+ files:
35
+ - LICENSE
36
+ - README.md
37
+ - README.rdoc
38
+ - THANKS
44
39
  - lib/cfpropertylist.rb
45
- - lib/rbBinaryCFPropertyList.rb
46
- - lib/rbCFPlistError.rb
47
- - lib/rbCFPropertyList.rb
48
- - lib/rbCFTypes.rb
49
- - lib/rbXMLCFPropertyList.rb
50
- - README
51
- has_rdoc: true
40
+ - lib/cfpropertylist/rbBinaryCFPropertyList.rb
41
+ - lib/cfpropertylist/rbCFPlistError.rb
42
+ - lib/cfpropertylist/rbCFPropertyList.rb
43
+ - lib/cfpropertylist/rbCFTypes.rb
44
+ - lib/cfpropertylist/rbLibXMLParser.rb
45
+ - lib/cfpropertylist/rbNokogiriParser.rb
46
+ - lib/cfpropertylist/rbPlainCFPropertyList.rb
47
+ - lib/cfpropertylist/rbREXMLParser.rb
52
48
  homepage: http://github.com/ckruse/CFPropertyList
53
- licenses: []
54
-
49
+ licenses:
50
+ - MIT
51
+ metadata: {}
55
52
  post_install_message:
56
53
  rdoc_options: []
57
-
58
- require_paths:
54
+ require_paths:
59
55
  - lib
60
- required_ruby_version: !ruby/object:Gem::Requirement
61
- requirements:
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
62
58
  - - ">="
63
- - !ruby/object:Gem::Version
64
- version: "0"
65
- version:
66
- required_rubygems_version: !ruby/object:Gem::Requirement
67
- requirements:
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
68
63
  - - ">="
69
- - !ruby/object:Gem::Version
70
- version: "0"
71
- version:
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
72
66
  requirements: []
73
-
74
- rubyforge_project: cfpropertylist
75
- rubygems_version: 1.3.5
67
+ rubyforge_project:
68
+ rubygems_version: 2.7.3
76
69
  signing_key:
77
- specification_version: 3
78
- summary: Read, write and manipulate both binary and XML property lists as defined by apple
70
+ specification_version: 4
71
+ summary: Read, write and manipulate both binary and XML property lists as defined
72
+ by apple
79
73
  test_files: []
80
-