nixenvironment 0.0.118 → 0.0.119

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,266 @@
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 CFPropertyList228
13
+ ##
14
+ # Blob is intended to distinguish between a Ruby String instance that should
15
+ # be converted to a CFString type and a Ruby String instance that should be
16
+ # converted to a CFData type
17
+ class Blob < String
18
+ end
19
+
20
+ ##
21
+ # UidFixnum is intended to distinguish between a Ruby Fixnum
22
+ # instance that should be converted to a CFInteger/CFReal type and a
23
+ # Ruby Fixnum instance that should be converted to a CFUid type.
24
+ class UidFixnum < Fixnum
25
+ end
26
+
27
+ # This class defines the base class for all CFType classes
28
+ #
29
+ class CFType
30
+ # value of the type
31
+ attr_accessor :value
32
+
33
+ def initialize(value=nil)
34
+ @value = value
35
+ end
36
+
37
+ def to_xml(parser)
38
+ end
39
+
40
+ def to_binary(bplist) end
41
+ end
42
+
43
+ # This class holds string values, both, UTF-8 and UTF-16BE
44
+ # It will convert the value to UTF-16BE if necessary (i.e. if non-ascii char contained)
45
+ class CFString < CFType
46
+ # convert to XML
47
+ def to_xml(parser)
48
+ n = parser.new_node('string')
49
+ n = parser.append_node(n, parser.new_text(@value)) unless @value.nil?
50
+ n
51
+ end
52
+
53
+ # convert to binary
54
+ def to_binary(bplist)
55
+ bplist.string_to_binary(@value);
56
+ end
57
+ end
58
+
59
+ # This class holds integer/fixnum values
60
+ class CFInteger < CFType
61
+ # convert to XML
62
+ def to_xml(parser)
63
+ n = parser.new_node('integer')
64
+ n = parser.append_node(n, parser.new_text(@value.to_s))
65
+ n
66
+ end
67
+
68
+ # convert to binary
69
+ def to_binary(bplist)
70
+ bplist.num_to_binary(self)
71
+ end
72
+ end
73
+
74
+ # This class holds float values
75
+ class CFReal < CFType
76
+ # convert to XML
77
+ def to_xml(parser)
78
+ n = parser.new_node('real')
79
+ n = parser.append_node(n, parser.new_text(@value.to_s))
80
+ n
81
+ end
82
+
83
+ # convert to binary
84
+ def to_binary(bplist)
85
+ bplist.num_to_binary(self)
86
+ end
87
+ end
88
+
89
+ # This class holds Time values. While Apple uses seconds since 2001,
90
+ # the rest of the world uses seconds since 1970. So if you access value
91
+ # directly, you get the Time class. If you access via get_value you either
92
+ # geht the timestamp or the Apple timestamp
93
+ class CFDate < CFType
94
+ TIMESTAMP_APPLE = 0
95
+ TIMESTAMP_UNIX = 1;
96
+ DATE_DIFF_APPLE_UNIX = 978307200
97
+
98
+ # create a XML date strimg from a time object
99
+ def CFDate.date_string(val)
100
+ # 2009-05-13T20:23:43Z
101
+ val.getutc.strftime("%Y-%m-%dT%H:%M:%SZ")
102
+ end
103
+
104
+ # parse a XML date string
105
+ def CFDate.parse_date(val)
106
+ # 2009-05-13T20:23:43Z
107
+ val =~ %r{^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$}
108
+ year,month,day,hour,min,sec = $1, $2, $3, $4, $5, $6
109
+ return Time.utc(year,month,day,hour,min,sec).getlocal
110
+ end
111
+
112
+ # set value to defined state
113
+ def initialize(value = nil,format=CFDate::TIMESTAMP_UNIX)
114
+ if(value.is_a?(Time) || value.nil?) then
115
+ @value = value.nil? ? Time.now : value
116
+ elsif value.instance_of? Date
117
+ @value = Time.utc(value.year, value.month, value.day, 0, 0, 0)
118
+ elsif value.instance_of? DateTime
119
+ @value = value.to_time.utc
120
+ else
121
+ set_value(value,format)
122
+ end
123
+ end
124
+
125
+ # set value with timestamp, either Apple or UNIX
126
+ def set_value(value,format=CFDate::TIMESTAMP_UNIX)
127
+ if(format == CFDate::TIMESTAMP_UNIX) then
128
+ @value = Time.at(value)
129
+ else
130
+ @value = Time.at(value + CFDate::DATE_DIFF_APPLE_UNIX)
131
+ end
132
+ end
133
+
134
+ # get timestamp, either UNIX or Apple timestamp
135
+ def get_value(format=CFDate::TIMESTAMP_UNIX)
136
+ if(format == CFDate::TIMESTAMP_UNIX) then
137
+ @value.to_i
138
+ else
139
+ @value.to_f - CFDate::DATE_DIFF_APPLE_UNIX
140
+ end
141
+ end
142
+
143
+ # convert to XML
144
+ def to_xml(parser)
145
+ n = parser.new_node('date')
146
+ n = parser.append_node(n, parser.new_text(CFDate::date_string(@value)))
147
+ n
148
+ end
149
+
150
+ # convert to binary
151
+ def to_binary(bplist)
152
+ bplist.date_to_binary(@value)
153
+ end
154
+ end
155
+
156
+ # This class contains a boolean value
157
+ class CFBoolean < CFType
158
+ # convert to XML
159
+ def to_xml(parser)
160
+ parser.new_node(@value ? 'true' : 'false')
161
+ end
162
+
163
+ # convert to binary
164
+ def to_binary(bplist)
165
+ bplist.bool_to_binary(@value);
166
+ end
167
+ end
168
+
169
+ # This class contains binary data values
170
+ class CFData < CFType
171
+ # Base64 encoded data
172
+ DATA_BASE64 = 0
173
+ # Raw data
174
+ DATA_RAW = 1
175
+
176
+ # set value to defined state, either base64 encoded or raw
177
+ def initialize(value=nil,format=DATA_BASE64)
178
+ if(format == DATA_RAW)
179
+ @raw_value = value
180
+ else
181
+ @value = value
182
+ end
183
+ end
184
+
185
+ # get base64 encoded value
186
+ def encoded_value
187
+ @value ||= "\n#{Base64.encode64(@raw_value).gsub("\n", '').scan(/.{1,76}/).join("\n")}\n"
188
+ end
189
+
190
+ # get base64 decoded value
191
+ def decoded_value
192
+ @raw_value ||= Blob.new(Base64.decode64(@value))
193
+ end
194
+
195
+ # convert to XML
196
+ def to_xml(parser)
197
+ n = parser.new_node('data')
198
+ n = parser.append_node(n, parser.new_text(encoded_value()))
199
+ n
200
+ end
201
+
202
+ # convert to binary
203
+ def to_binary(bplist)
204
+ bplist.data_to_binary(decoded_value())
205
+ end
206
+ end
207
+
208
+ # This class contains an array of values
209
+ class CFArray < CFType
210
+ # create a new array CFType
211
+ def initialize(val=[])
212
+ @value = val
213
+ end
214
+
215
+ # convert to XML
216
+ def to_xml(parser)
217
+ n = parser.new_node('array')
218
+ @value.each do |v|
219
+ n = parser.append_node(n, v.to_xml(parser))
220
+ end
221
+ n
222
+ end
223
+
224
+ # convert to binary
225
+ def to_binary(bplist)
226
+ bplist.array_to_binary(self)
227
+ end
228
+ end
229
+
230
+ # this class contains a hash of values
231
+ class CFDictionary < CFType
232
+ # Create new CFDictonary type.
233
+ def initialize(value={})
234
+ @value = value
235
+ end
236
+
237
+ # convert to XML
238
+ def to_xml(parser)
239
+ n = parser.new_node('dict')
240
+ @value.each_pair do |key, value|
241
+ k = parser.append_node(parser.new_node('key'), parser.new_text(key.to_s))
242
+ n = parser.append_node(n, k)
243
+ n = parser.append_node(n, value.to_xml(parser))
244
+ end
245
+ n
246
+ end
247
+
248
+ # convert to binary
249
+ def to_binary(bplist)
250
+ bplist.dict_to_binary(self)
251
+ end
252
+ end
253
+
254
+ class CFUid < CFType
255
+ def to_xml(parser)
256
+ CFDictionary.new({'CF$UID' => CFInteger.new(@value)}).to_xml(parser)
257
+ end
258
+
259
+ # convert to binary
260
+ def to_binary(bplist)
261
+ bplist.uid_to_binary(@value)
262
+ end
263
+ end
264
+ end
265
+
266
+ # eof
@@ -0,0 +1,147 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'libxml'
4
+
5
+ module CFPropertyList228
6
+ # XML parser
7
+ class LibXMLParser < 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
+ doc = LibXML::XML::Document.file(opts[:file],:options => LibXML::XML::Parser::Options::NOBLANKS|LibXML::XML::Parser::Options::NOENT)
17
+ else
18
+ doc = LibXML::XML::Document.string(opts[:data],:options => LibXML::XML::Parser::Options::NOBLANKS|LibXML::XML::Parser::Options::NOENT)
19
+ end
20
+
21
+ if doc
22
+ root = doc.root.first
23
+ return import_xml(root)
24
+ end
25
+ rescue LibXML::XML::Error => e
26
+ raise CFFormatError.new('invalid XML: ' + e.message)
27
+ end
28
+
29
+ # serialize CFPropertyList228 object to XML
30
+ # opts = {}:: Specify options: :formatted - Use indention and line breaks
31
+ def to_str(opts={})
32
+ doc = LibXML::XML::Document.new
33
+
34
+ doc.root = LibXML::XML::Node.new('plist')
35
+ doc.encoding = LibXML::XML::Encoding::UTF_8
36
+
37
+ doc.root['version'] = '1.0'
38
+ doc.root << opts[:root].to_xml(self)
39
+
40
+ # ugly hack, but there's no other possibility I know
41
+ str = doc.to_s(:indent => opts[:formatted])
42
+ str1 = String.new
43
+ first = false
44
+ str.each_line do |line|
45
+ str1 << line
46
+ unless(first) then
47
+ str1 << "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" if line =~ /^\s*<\?xml/
48
+ end
49
+
50
+ first = true
51
+ end
52
+
53
+ str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding)
54
+ return str1
55
+ end
56
+
57
+ def new_node(name)
58
+ LibXML::XML::Node.new(name)
59
+ end
60
+
61
+ def new_text(val)
62
+ LibXML::XML::Node.new_text(val)
63
+ end
64
+
65
+ def append_node(parent, child)
66
+ parent << child
67
+ end
68
+
69
+ protected
70
+
71
+ # get the value of a DOM node
72
+ def get_value(n)
73
+ content = if n.children?
74
+ n.first.content
75
+ else
76
+ n.content
77
+ end
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.children? then
93
+ node.children.each do |n|
94
+ next if n.text? # avoid a bug of libxml
95
+ next if n.comment?
96
+
97
+ if n.name == "key" then
98
+ key = get_value(n)
99
+ else
100
+ raise CFFormatError.new("Format error!") if key.nil?
101
+ hsh[key] = import_xml(n)
102
+ key = nil
103
+ end
104
+ end
105
+ end
106
+
107
+ if hsh['CF$UID'] and hsh.keys.length == 1
108
+ ret = CFUid.new(hsh['CF$UID'].value)
109
+ else
110
+ ret = CFDictionary.new(hsh)
111
+ end
112
+
113
+ when 'array'
114
+ ary = Array.new
115
+
116
+ if node.children? then
117
+ node.children.each do |n|
118
+ next if n.text? # avoid a bug of libxml
119
+ next if n.comment?
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
+ when 'data'
137
+ ret = CFData.new(get_value(node))
138
+ when 'date'
139
+ ret = CFDate.new(CFDate.parse_date(get_value(node)))
140
+ end
141
+
142
+ return ret
143
+ end
144
+ end
145
+ end
146
+
147
+ # eof
@@ -0,0 +1,151 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'nokogiri'
4
+
5
+ module CFPropertyList228
6
+ # XML parser
7
+ class NokogiriXMLParser < 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
+ doc = nil
14
+ if(opts.has_key?(:file)) then
15
+ File.open(opts[:file], "rb") { |fd| doc = Nokogiri::XML::Document.parse(fd, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS|Nokogiri::XML::ParseOptions::NOENT) }
16
+ else
17
+ doc = Nokogiri::XML::Document.parse(opts[:data], nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS|Nokogiri::XML::ParseOptions::NOENT)
18
+ end
19
+
20
+ if doc
21
+ root = doc.root.children.first
22
+ return import_xml(root)
23
+ end
24
+ rescue Nokogiri::XML::SyntaxError => e
25
+ raise CFFormatError.new('invalid XML: ' + e.message)
26
+ end
27
+
28
+ # serialize CFPropertyList228 object to XML
29
+ # opts = {}:: Specify options: :formatted - Use indention and line breaks
30
+ def to_str(opts={})
31
+ doc = Nokogiri::XML::Document.new
32
+ @doc = doc
33
+
34
+ doc.root = doc.create_element 'plist', :version => '1.0'
35
+ doc.encoding = 'UTF-8'
36
+
37
+ doc.root << opts[:root].to_xml(self)
38
+
39
+ # ugly hack, but there's no other possibility I know
40
+ s_opts = Nokogiri::XML::Node::SaveOptions::AS_XML
41
+ s_opts |= Nokogiri::XML::Node::SaveOptions::FORMAT if opts[:formatted]
42
+
43
+ str = doc.serialize(:save_with => s_opts)
44
+ str1 = String.new
45
+ first = false
46
+ str.each_line do |line|
47
+ str1 << line
48
+ unless(first) then
49
+ str1 << "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" if line =~ /^\s*<\?xml/
50
+ end
51
+
52
+ first = true
53
+ end
54
+
55
+ str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding)
56
+ return str1
57
+ end
58
+
59
+ def new_node(name)
60
+ @doc.create_element name
61
+ end
62
+
63
+ def new_text(val)
64
+ @doc.create_text_node val
65
+ end
66
+
67
+ def append_node(parent, child)
68
+ parent << child
69
+ end
70
+
71
+ protected
72
+
73
+ # get the value of a DOM node
74
+ def get_value(n)
75
+ content = if n.children.empty?
76
+ n.content
77
+ else
78
+ n.children.first.content
79
+ end
80
+
81
+ content.force_encoding('UTF-8') if content.respond_to?(:force_encoding)
82
+ content
83
+ end
84
+
85
+ # import the XML values
86
+ def import_xml(node)
87
+ ret = nil
88
+
89
+ case node.name
90
+ when 'dict'
91
+ hsh = Hash.new
92
+ key = nil
93
+ children = node.children
94
+
95
+ unless children.empty? then
96
+ children.each do |n|
97
+ next if n.text? # avoid a bug of libxml
98
+ next if n.comment?
99
+
100
+ if n.name == "key" then
101
+ key = get_value(n)
102
+ else
103
+ raise CFFormatError.new("Format error!") if key.nil?
104
+ hsh[key] = import_xml(n)
105
+ key = nil
106
+ end
107
+ end
108
+ end
109
+
110
+ if hsh['CF$UID'] and hsh.keys.length == 1
111
+ ret = CFUid.new(hsh['CF$UID'].value)
112
+ else
113
+ ret = CFDictionary.new(hsh)
114
+ end
115
+
116
+ when 'array'
117
+ ary = Array.new
118
+ children = node.children
119
+
120
+ unless children.empty? then
121
+ children.each do |n|
122
+ next if n.text? # avoid a bug of libxml
123
+ next if n.comment?
124
+ ary.push import_xml(n)
125
+ end
126
+ end
127
+
128
+ ret = CFArray.new(ary)
129
+
130
+ when 'true'
131
+ ret = CFBoolean.new(true)
132
+ when 'false'
133
+ ret = CFBoolean.new(false)
134
+ when 'real'
135
+ ret = CFReal.new(get_value(node).to_f)
136
+ when 'integer'
137
+ ret = CFInteger.new(get_value(node).to_i)
138
+ when 'string'
139
+ ret = CFString.new(get_value(node))
140
+ when 'data'
141
+ ret = CFData.new(get_value(node))
142
+ when 'date'
143
+ ret = CFDate.new(CFDate.parse_date(get_value(node)))
144
+ end
145
+
146
+ return ret
147
+ end
148
+ end
149
+ end
150
+
151
+ # eof