nixenvironment 0.0.118 → 0.0.119

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,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