property-list 1.0.2 → 1.0.3

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: 6a77c93353f4ae1b3e24f38e0976a133a68251ec
4
- data.tar.gz: 2c68650d8755fc85dd1752951e930f153624a372
3
+ metadata.gz: 3c5d4e0a084175a1ea51a31be189467896203dc9
4
+ data.tar.gz: 796a23fede74ba3c0bcf9bd767963c3d7630123e
5
5
  SHA512:
6
- metadata.gz: 786bb0eaba6ebf83dee461f951ce9966b51c649e945fd1a06ebb3d6a7176ebd886abb6c773172ae85455a310a23a9b93ed00b567b18d58b5bc74cc4696985e4d
7
- data.tar.gz: 4c64f96962192fa6cea63ceb476baaa9129996ec33f322465134b169b19b270ff136836419ca18ddd96fe5a804a35948fa89bdb6c0f8dc89dc4cc8fee4f10ed4
6
+ metadata.gz: 8dab686da733d62fc7dc66215b8f2df1d101fd12d73b82e385b4795ca83bdc1979e388cab4e94e2a6e88f7b73abe997cf0f7fdf0159c0e3522ace940a8f197b8
7
+ data.tar.gz: 1781700ecee2756062c5d45f6308e1bd7d90fc2f48172b9b03a52c6bf7b00b32b51e59fcb5442ce457cafb1859d624b836a83610a58fdcbd8d9f20d860858614
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.0.0-p648 # macOS
5
+ - 2.1.10
6
+ - 2.2.7
7
+ - 2.3.4
8
+ - 2.4.1
9
+ - ruby-head
10
+ - jruby-head
11
+ - rbx-3.72
12
+ before_install: gem install bundler -v '~> 1.15' --conservative
13
+ install: bundle install
14
+ script: CI_COVERAGE=1 bundle exec rake
data/README.md CHANGED
@@ -1,10 +1,14 @@
1
- Fully featured propertylist library.
2
- Can load and dump XML/ASCII/Binary plists and offer fine-grained formatting options.
1
+ [![Build Status](https://travis-ci.org/luikore/property-list.svg?branch=master)](https://travis-ci.org/luikore/property-list)
2
+ [![Gem Version](https://badge.fury.io/rb/property-list.svg)](https://badge.fury.io/rb/property-list)
3
+ [![Coverage Status](https://coveralls.io/repos/github/luikore/property-list/badge.svg?branch=master)](https://coveralls.io/github/luikore/property-list?branch=master)
4
+
5
+ Fully featured plist library.
6
+ Can load and dump XML/ASCII/Binary/SMIME propertylist and offer fine-grained formatting options.
3
7
  Cross platform, clean code, performance tuned, no dependency.
4
8
 
5
9
  ## Install
6
10
 
7
- Requires Ruby 1.9+
11
+ Requires Ruby 2.0+
8
12
 
9
13
  gem ins property-list
10
14
 
@@ -23,9 +27,9 @@ Generate a plist file data
23
27
  PropertyList.dump_binary obj
24
28
  PropertyList.dump_ascii obj
25
29
 
26
- XML formatting options for `PropertyList.dump_xml object, options`
30
+ **XML formatting** options for `PropertyList.dump_xml object, options`
27
31
 
28
- - `segment:` whether output an XML segment (not wrapped with `<?xml>`, `<DOCTYPE>`, `<plist>` tags), default is `false`.
32
+ - `segment:` whether output an XML segment (not wrapped with `<?xml>, <DOCTYPE>, <plist>` tags), default is `false`.
29
33
  - `xml_version:` you can also specify `"1.1"` for https://www.w3.org/TR/xml11/, default is `"1.0"`, no effect if `:segment` is set to `true`.
30
34
  - `gnu_dtd:` use GNUStep DTD instead (which is a bit different in string escaping), default is `false`.
31
35
  - `indent_unit:` the indent unit, default value is `"\t"`, set to or `''` if you don't need indent.
@@ -33,44 +37,78 @@ XML formatting options for `PropertyList.dump_xml object, options`
33
37
  - `base64_width:` the width of characters per line when serializing data with Base64, default value is `68`, must be multiple of `4`.
34
38
  - `base64_indent:` whether indent the Base64 encoded data, you can use `false` for compatibility to generate same output for other frameworks, default value is `true`.
35
39
 
36
- ASCII formatting options for `PropertyList.dump_ascii object, options`
40
+ **ASCII formatting** options for `PropertyList.dump_ascii object, options`
37
41
 
38
42
  - `indent_unit:` the indent unit, default value is `"\t"`, set to `''` if you don't need indent.
39
43
  - `initial_indent:` initial indent space, default is `''`, the indentation per line equals to `initial_indent + indent * current_indent_level`.
40
44
  - `wrap:` wrap the top level output with `{...}` when obj is a Hash, default is `true`.
41
45
  - `encoding_comment:` add encoding comment `// !$*UTF8*$!` on top of file, default is `false`.
42
46
  - `sort_keys:` sort dict keys, default is `true`.
43
- - `gnu_extension` whether allow GNUStep extensions for ASCII plist to support serializing more types, default is `true`.
47
+ - `gnu_extension:` whether allow GNUStep extensions for ASCII plist to support serializing more types, default is `true`.
44
48
 
45
49
  ## Data type mapping
46
50
 
47
- Data type mapping in `PropertyList.load`:
48
-
49
- real: Float
50
- string: String
51
- integer: Integer
52
- data: StringIO
53
- date: DateTime
54
- true: true
55
- false: false
56
- uid: PropertyList::UID # only in binary plist, obj.uid is the integer index
57
- array: Array
58
- dict: Hash
59
- set: Set # only in binary plist
60
-
61
- Reverse mapping in `PropertyList.dump_*`:
62
-
63
- Float: real
64
- String, Symbol: string
65
- Integer: integer
66
- StringIO, IO: data
67
- Time, DateTime, Date: date
68
- true: true
69
- false: false
70
- PropertyList::Uid: uid # only in binary plist
71
- Dict: dict
72
- Array: array
73
- Set: set # only in binary plist
51
+ When loading, plist data types will be mapped to native Ruby types:
52
+
53
+ Plist type Ruby type
54
+ ------------------------------
55
+ real Float
56
+ string String
57
+ unicode_string String
58
+ integer Integer
59
+ data StringIO
60
+ date DateTime
61
+ true TrueClass
62
+ false FalseClass
63
+ uid PropertyList::Uid [*1]
64
+ array Array
65
+ dict Hash
66
+
67
+ # binary plist v1x elements:
68
+
69
+ null NilClass
70
+ set Set
71
+ ordset PropertyList::OrdSet
72
+ uuid PropertyList::Uuid
73
+ url_base PropertyList::Url [*2]
74
+ url_no_base PropertyList::Url
75
+
76
+ Notes:
77
+
78
+ - \[\*1] **uid** is only available in binary plist, `PropertyList::Uid#uid` is the integer index.
79
+ - \[\*2] **url_base** means URL with base.
80
+
81
+ When dumping, native Ruby types will be mapped to plist data types:
82
+
83
+ Ruby type Plist type
84
+ -----------------------------------
85
+ Float real
86
+ String string, unicode_string
87
+ Symbol string, unicode_string
88
+ Integer integer
89
+ StringIO data
90
+ IO data
91
+ Time date
92
+ DateTime date
93
+ Date date
94
+ true true
95
+ false false
96
+ PropertyList::Uid uid
97
+ Dict dict
98
+ Array array
99
+ Set set
100
+
101
+ # binary plist v1x elements:
102
+
103
+ NilClass null
104
+ Set set
105
+ PropertyList::OrdSet ordset
106
+ PropertyList::Uuid uuid
107
+ PropertyList::Url url_base, url_no_base
108
+
109
+ Notes:
110
+
111
+ - `PropertyList::Uid` and `Set` can only be serialized in binary plist.
74
112
 
75
113
  Type mappings in ASCII plist depends on the DTD.
76
114
 
@@ -81,4 +119,4 @@ The binary generating code is modified from https://github.com/jarib/plist with
81
119
  ## Alternative plist libraries for Ruby
82
120
 
83
121
  - [plist](https://github.com/patsplat/plist): only deals with XML plist, and generates wrong plist when there is handle line endings in strings.
84
- - [CFPropertyList](https://github.com/ckruse/CFPropertyList): also deals with XML/Binary/ASCII plist files, more complex API and more thourough tests.
122
+ - [CFPropertyList](https://github.com/ckruse/CFPropertyList): also deals with XML/Binary/ASCII plist files, but not v1x binary plist, more hard-to-use API and more thourough tests.
data/Rakefile CHANGED
@@ -1,3 +1,6 @@
1
+ desc "default task"
2
+ task default: :test
3
+
1
4
  desc "run tests"
2
5
  task :test do
3
6
  Dir.glob './test/test_*.rb' do |f|
data/gems.locked CHANGED
@@ -1,12 +1,13 @@
1
- PATH
2
- remote: .
3
- specs:
4
- property-list (1.0)
5
-
6
1
  GEM
7
2
  remote: https://rubygems.org/
8
3
  specs:
9
4
  coderay (1.1.1)
5
+ coveralls (0.8.21)
6
+ json (>= 1.8, < 3)
7
+ simplecov (~> 0.14.1)
8
+ term-ansicolor (~> 1.3)
9
+ thor (~> 0.19.4)
10
+ tins (~> 1.6)
10
11
  docile (1.1.5)
11
12
  hoe (3.16.1)
12
13
  rake (>= 0.8, < 13.0)
@@ -23,19 +24,23 @@ GEM
23
24
  simplecov-html (~> 0.10.0)
24
25
  simplecov-html (0.10.2)
25
26
  slop (3.6.0)
27
+ term-ansicolor (1.6.0)
28
+ tins (~> 1.0)
26
29
  test-unit (1.2.3)
27
30
  hoe (>= 1.5.1)
31
+ thor (0.19.4)
32
+ tins (1.15.0)
28
33
 
29
34
  PLATFORMS
30
35
  ruby
31
36
 
32
37
  DEPENDENCIES
33
- bundler (~> 1.15.4)
34
- property-list!
35
- pry (~> 0.10.4)
36
- rake (~> 12.0.0)
37
- simplecov (~> 0.14.1)
38
- test-unit (~> 1.2.3)
38
+ bundler (~> 1.15)
39
+ coveralls
40
+ pry (~> 0.10)
41
+ rake (~> 12.0)
42
+ simplecov (~> 0.14)
43
+ test-unit (~> 1.2)
39
44
 
40
45
  BUNDLED WITH
41
46
  1.15.4
data/gems.rb CHANGED
@@ -1,3 +1,8 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gemspec
3
+ gem "bundler", "~> 1.15"
4
+ gem "rake", "~> 12.0"
5
+ gem "test-unit", "~> 1.2"
6
+ gem "pry", "~> 0.10"
7
+ gem "simplecov", "~> 0.14", require: false
8
+ gem 'coveralls', require: false
@@ -130,18 +130,21 @@ module PropertyList
130
130
  chars << "\r"
131
131
  when 't'
132
132
  chars << "\t"
133
- when 'U'
133
+ when 'U', 'u'
134
134
  if (hex = @lexer.scan /[0-9a-h]{4}/i)
135
- chars << [hex].pack('U')
135
+ chars << [hex.to_i(16)].pack('U')
136
136
  else
137
137
  syntax_error "Expect 4 digit hex code"
138
138
  end
139
- else
140
- if (oct = @lexer.scan /[0-7]{3}/)
141
- chars << [oct.to_i(8)].pack('U')
139
+ when /(\d)/
140
+ oct_init = $1
141
+ if (oct = @lexer.scan /[0-7]{2}/)
142
+ chars << [(oct_init + oct).to_i(8)].pack('U')
142
143
  else
143
144
  syntax_error "Expect 3 digit oct code"
144
145
  end
146
+ else
147
+ syntax_error "Bad escape"
145
148
  end
146
149
  else
147
150
  chars << ch
@@ -211,7 +214,7 @@ module PropertyList
211
214
  def syntax_error msg
212
215
  pre = @lexer.string[0...@lexer.pos]
213
216
  line = pre.count("\n") + 1
214
- col = pre.size - pre.rindex("\n")
217
+ col = pre.size - (pre.rindex("\n") || -1)
215
218
  raise SyntaxError, msg + " at line: #{line} col: #{col} #{@lexer.inspect}", caller
216
219
  end
217
220
  end
@@ -5,6 +5,7 @@ module PropertyList
5
5
  def self.dump_binary obj, options=nil
6
6
  generator = BinaryGenerator.new options
7
7
  generator.generate obj
8
+ binding.pry if $test
8
9
  generator.output.join
9
10
  end
10
11
 
@@ -15,109 +16,95 @@ module PropertyList
15
16
  class BinaryGenerator #:nodoc:
16
17
  include BinaryMarkers
17
18
 
19
+ Collection = Struct.new :marker, :size, :refs
20
+
21
+ V0_MAGIC = "bplist00".force_encoding('binary').freeze
22
+ V1_MAGIC = "bplist10".force_encoding('binary').freeze
23
+ TAIL_PADDING = "\0\0\0\0\0\0".force_encoding('binary').freeze
24
+
18
25
  def initialize opts
19
26
  @output = []
20
27
  @offset = 0
28
+ @objs = []
29
+ @ref_size = 0
21
30
  end
22
31
  attr_reader :output
23
32
 
24
- # Encodes +obj+ as a binary property list. If +obj+ is an Array, Hash, or
25
- # Set, the property list includes its contents.
26
- def generate object
27
- flatten_objects = flatten_collection object
28
- ref_byte_size = min_byte_size flatten_objects.size - 1
33
+ def generate obj
34
+ flatten obj
35
+ ref_byte_size = min_byte_size @ref_size - 1
29
36
 
30
- # Write header and encoded objects.
31
- # TODO use bplist10 when there are version 1x elements
32
- add_output "bplist00"
37
+ add_output V0_MAGIC
33
38
  offset_table = []
34
- flatten_objects.each do |o|
39
+ @objs.each do |o|
35
40
  offset_table << @offset
36
41
  binary_object o, ref_byte_size
37
42
  end
38
43
 
39
- # Write offset table.
44
+ if @v1
45
+ @output[0] = V1_MAGIC
46
+ end
47
+
40
48
  offset_table_addr = @offset
41
49
  offset_byte_size = min_byte_size @offset
42
50
  offset_table.each do |offset|
43
51
  binary_integer offset, offset_byte_size
44
52
  end
45
53
 
46
- # Write trailer. (6 + 2 + 24 = 32 bytes)
47
- add_output [
48
- "\0\0\0\0\0\0", # padding
54
+ add_output pack([
55
+ TAIL_PADDING,
49
56
  offset_byte_size, ref_byte_size,
50
- flatten_objects.size,
57
+ @ref_size,
51
58
  0, # index of root object
52
59
  offset_table_addr
53
- ].pack("a*C2Q>3")
60
+ ], "a*C2Q>3")
54
61
  end
55
62
 
56
- private
63
+ def flatten obj
64
+ @ref_size += 1
57
65
 
58
- # Takes an object (nominally a collection, like an Array, Set, or Hash, but
59
- # any object is acceptable) and flattens it into a one-dimensional array.
60
- # Non-collection objects appear in the array as-is, but the contents of
61
- # Arrays, Sets, and Hashes are modified like so: (1) The contents of the
62
- # collection are added, one-by-one, to the one-dimensional array. (2) The
63
- # collection itself is modified so that it contains indexes pointing to the
64
- # objects in the one-dimensional array. Here's an example with an Array:
65
- #
66
- # ary = [:a, :b, :c]
67
- # flatten_collection(ary) # => [[1, 2, 3], :a, :b, :c]
68
- #
69
- # In the case of a Hash, keys and values are both appended to the one-
70
- # dimensional array and then replaced with indexes.
71
- #
72
- # hsh = {:a => "blue", :b => "purple", :c => "green"}
73
- # flatten_collection(hsh)
74
- # # => [{1 => 2, 3 => 4, 5 => 6}, :a, "blue", :b, "purple", :c, "green"]
75
- #
76
- # An object will never be added to the one-dimensional array twice. If a
77
- # collection refers to an object more than once, the object will be added
78
- # to the one-dimensional array only once.
79
- #
80
- # ary = [:a, :a, :a]
81
- # flatten_collection(ary) # => [[1, 1, 1], :a]
82
- #
83
- # The +obj_list+ and +id_refs+ parameters are private; they're used for
84
- # descending into sub-collections recursively.
85
- def flatten_collection collection, obj_list=[], id_refs={}
86
- case collection
87
- when Array, Set
88
- if id_refs[collection.object_id]
89
- return obj_list[id_refs[collection.object_id]]
66
+ case obj
67
+ when Array
68
+ refs = []
69
+ @objs << Collection[MARKER_ARRAY, obj.size, refs]
70
+ obj.each do |e|
71
+ refs << @ref_size
72
+ flatten e
90
73
  end
91
- obj_refs = collection.class.new
92
- id_refs[collection.object_id] = obj_list.length
93
- obj_list << obj_refs
94
- collection.each do |obj|
95
- flatten_collection(obj, obj_list, id_refs)
96
- obj_refs << id_refs[obj.object_id]
74
+
75
+ when Set
76
+ @v1 = true
77
+ refs = []
78
+ @objs << Collection[MARKER_SET, obj.size, refs]
79
+ obj.each do |e|
80
+ refs << @ref_size
81
+ flatten e
97
82
  end
98
- return obj_list
99
83
 
100
84
  when Hash
101
- if id_refs[collection.object_id]
102
- return obj_list[id_refs[collection.object_id]]
85
+ refs = []
86
+ @objs << Collection[MARKER_DICT, obj.size, refs]
87
+ obj.each do |e, _|
88
+ refs << @ref_size
89
+ flatten e
103
90
  end
104
- obj_refs = {}
105
- id_refs[collection.object_id] = obj_list.length
106
- obj_list << obj_refs
107
- collection.keys.sort.each do |key|
108
- value = collection[key]
109
- key = key.to_s if key.is_a?(Symbol)
110
- flatten_collection(key, obj_list, id_refs)
111
- flatten_collection(value, obj_list, id_refs)
112
- obj_refs[id_refs[key.object_id]] = id_refs[value.object_id]
91
+ obj.each do |_, e|
92
+ refs << @ref_size
93
+ flatten e
113
94
  end
114
- return obj_list
115
- else
116
- unless id_refs[collection.object_id]
117
- id_refs[collection.object_id] = obj_list.length
118
- obj_list << collection
95
+
96
+ when OrdSet
97
+ @v1 = true
98
+ refs = []
99
+ elements = obj.elements
100
+ @objs << Collection[MARKER_ORD_SET, elements.size, refs]
101
+ elements.each do |e|
102
+ refs << @ref_size
103
+ flatten e
119
104
  end
120
- return obj_list
105
+
106
+ else
107
+ @objs << obj
121
108
  end
122
109
  end
123
110
 
@@ -126,92 +113,72 @@ module PropertyList
126
113
  @offset += data.bytesize
127
114
  end
128
115
 
129
- # Returns a binary property list fragment that represents +obj+. The
130
- # returned string is not a complete property list, just a fragment that
131
- # describes +obj+, and is not useful without a header, offset table, and
132
- # trailer.
133
- #
134
- # The following classes are recognized: String, Float, Integer, the Boolean
135
- # classes, Time, IO, StringIO, Array, Set, and Hash. IO and StringIO
136
- # objects are rewound, read, and the contents stored as data (i.e., Cocoa
137
- # applications will decode them as NSData). All other classes are dumped
138
- # with Marshal and stored as data.
139
- #
140
- # Note that subclasses of the supported classes will be encoded as though
141
- # they were the supported superclass. Thus, a subclass of (for example)
142
- # String will be encoded and decoded as a String, not as the subclass:
143
- #
144
- # class ExampleString < String
145
- # ...
146
- # end
147
- #
148
- # s = ExampleString.new("disquieting plantlike mystery")
149
- # encoded_s = binary_object(s)
150
- # decoded_s = decode_binary_object(encoded_s)
151
- # puts decoded_s.class # => String
152
- #
153
- # +ref_byte_size+ is the number of bytes to use for storing references to
154
- # other objects.
155
116
  def binary_object obj, ref_byte_size = 4
156
117
  case obj
157
118
  when Symbol
158
119
  binary_string obj.to_s
159
120
  when String
160
121
  binary_string obj
161
- when URL
162
- binary_url obj.url
163
122
  when Float
164
- add_output [(MARKER_REAL | 3), obj].pack("CG")
123
+ add_output pack([(MARKER_REAL | 3), obj], "CG")
165
124
  when Integer
166
125
  nbytes = min_byte_size obj
167
126
  size_bits = { 1 => 0, 2 => 1, 4 => 2, 8 => 3, 16 => 4 }[nbytes]
168
- add_output (MARKER_INT | size_bits).chr
127
+ add_output chr(MARKER_INT | size_bits)
169
128
  binary_integer obj, nbytes
170
129
  when TrueClass
171
- add_output MARKER_TRUE.chr
130
+ add_output chr(MARKER_TRUE)
172
131
  when FalseClass
173
- add_output MARKER_FALSE.chr
132
+ add_output chr(MARKER_FALSE)
174
133
  when Time
175
- add_output [MARKER_DATE, obj.to_f - TIME_INTERVAL_SINCE_1970].pack("CG")
134
+ add_output pack([MARKER_DATE, obj.to_f - TIME_INTERVAL_SINCE_1970], "CG")
176
135
  when Date # also covers DateTime
177
- add_output [MARKER_DATE, obj.to_time.to_f - TIME_INTERVAL_SINCE_1970].pack("CG")
178
- when IO, StringIO
136
+ add_output pack([MARKER_DATE, obj.to_time.to_f - TIME_INTERVAL_SINCE_1970], "CG")
137
+ when StringIO
138
+ data = obj.string.force_encoding('binary') # NOTE StringIO.binmode doesn't work in <2.0.0 & rbx
139
+ binary_marker MARKER_DATA, data.bytesize
140
+ add_output data
141
+ when IO
179
142
  obj.rewind
180
143
  obj.binmode
181
144
  data = obj.read
182
145
  binary_marker MARKER_DATA, data.bytesize
183
146
  add_output data
184
- when Array
185
- # Must be an array of object references as returned by flatten_collection.
186
- binary_marker MARKER_ARRAY, obj.size
187
- obj.each do |i|
188
- binary_integer i, ref_byte_size
189
- end
190
- when Set
191
- # Must be a set of object references as returned by flatten_collection.
192
- binary_marker MARKER_SET, obj.size
193
- obj.each do |i|
147
+ when Collection
148
+ binary_marker obj.marker, obj.size
149
+ obj.refs.each do |i|
194
150
  binary_integer i, ref_byte_size
195
151
  end
196
- when Hash
197
- # Must be a table of object references as returned by flatten_collection.
198
- binary_marker MARKER_DICT, obj.size
199
- obj.keys.each do |k|
200
- binary_integer k, ref_byte_size
201
- end
202
- obj.values.each do |v|
203
- binary_integer v, ref_byte_size
204
- end
152
+ when Uid
153
+ # Encoding is as integers, except values are unsigned.
154
+ nbytes = min_byte_size obj.uid
155
+ size_bits = { 1 => 0, 2 => 1, 4 => 2, 8 => 3, 16 => 4 }[nbytes]
156
+ add_output chr(MARKER_UID | size_bits)
157
+ binary_integer obj.uid, nbytes
158
+
159
+ ## the following are v1x data types ##
160
+
161
+ when Uuid
162
+ @v1 = true
163
+ data = pack([obj.uuid], 'H*')
164
+ add_output chr(MARKER_UUID)
165
+ add_output data
166
+ when Url
167
+ @v1 = true
168
+ binary_url obj
169
+ when NilClass
170
+ @v1 = true
171
+ add_output chr(MARKER_NULL)
205
172
  else
206
- raise "Unsupported class: #{obj.class}"
173
+ raise UnsupportedTypeError, obj.class.to_s
207
174
  end
208
175
  end
209
176
 
210
177
  def binary_marker marker, size
211
178
  if size < 15
212
- add_output (marker | size).chr
179
+ add_output chr(marker | size)
213
180
  else
214
- add_output (marker | 0xf).chr
181
+ add_output chr(marker | 0xf)
215
182
  binary_object size
216
183
  end
217
184
  end
@@ -233,22 +200,21 @@ module PropertyList
233
200
  end
234
201
 
235
202
  def binary_url obj
236
- @v1 = true
237
- if obj =~ /\A\w+:/
238
- add_output MARKER_WITH_BASE_URL.chr
203
+ if obj.url =~ /\A\w+:\/\//
204
+ add_output chr(MARKER_WITH_BASE_URL)
239
205
  else
240
- add_output MARKER_NO_BASE_URL.chr
206
+ add_output chr(MARKER_NO_BASE_URL)
241
207
  end
242
- binary_marker MARKER_ASCII_STRING, obj.bytesize
243
- add_output obj
208
+ binary_marker MARKER_ASCII_STRING, obj.url.bytesize
209
+ add_output obj.url
244
210
  end
245
211
 
246
- def binary_uuid obj
247
- # TODO
212
+ def chr c
213
+ c.chr.force_encoding 'binary'
248
214
  end
249
215
 
250
- def binary_ordered_set obj
251
- # TODO
216
+ def pack objs, format
217
+ objs.pack(format).force_encoding 'binary'
252
218
  end
253
219
 
254
220
  # Packs an integer +i+ into its binary representation in the specified
@@ -260,19 +226,19 @@ module PropertyList
260
226
  end
261
227
  case num_bytes
262
228
  when 1
263
- add_output [i].pack("C")
229
+ add_output pack([i], "C")
264
230
  when 2
265
- add_output [i].pack("n")
231
+ add_output pack([i], "n")
266
232
  when 4
267
- add_output [i].pack("N")
233
+ add_output pack([i], "N")
268
234
  when 8
269
- add_output [i].pack("q>")
235
+ add_output pack([i], "q>")
270
236
  when 16
271
237
  # TODO verify 128 bit integer encoding
272
238
  if i < 0
273
239
  i = 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff ^ i.abs + 1
274
240
  end
275
- add_output [i >> 64, i & 0xffff_ffff_ffff_ffff].pack("q>2")
241
+ add_output pack([i >> 64, i & 0xffff_ffff_ffff_ffff], "q>2")
276
242
  else
277
243
  raise ArgumentError, "num_bytes must be 1, 2, 4, 8, or 16"
278
244
  end
@@ -24,36 +24,26 @@ module PropertyList
24
24
  private
25
25
 
26
26
  def decode_object offset
27
- first_byte, = @src.unpack "@#{offset}C"
27
+ first_byte, _ = @src.unpack "@#{offset}C"
28
28
  marker = first_byte & 0xF0
29
29
  if marker == 0 or first_byte == MARKER_DATE
30
30
  marker = first_byte
31
31
  end
32
32
 
33
33
  case marker
34
- when MARKER_NULL
35
- nil
36
34
  when MARKER_FALSE
37
35
  false
38
36
  when MARKER_TRUE
39
37
  true
40
- when MARKER_NO_BASE_URL
41
- raise 'todo'
42
- when MARKER_WITH_BASE_URL
43
- raise 'todo'
44
- when MARKER_UUID
45
- raise 'todo'
46
- when MARKER_FILL
47
- decode_object offest + 1
48
38
  when MARKER_INT
49
39
  size_bits = first_byte & 0x0F
50
40
  num_bytes = 2 ** size_bits
51
41
  decode_integer offset + 1, num_bytes
52
42
  when MARKER_REAL
53
- r, = @src.unpack "@#{offset + 1}G"
43
+ r, _ = @src.unpack "@#{offset + 1}G"
54
44
  r
55
45
  when MARKER_DATE
56
- seconds_since_2001, = @src.unpack "@#{offset + 1}G"
46
+ seconds_since_2001, _ = @src.unpack "@#{offset + 1}G"
57
47
  Time.at(TIME_INTERVAL_SINCE_1970 + seconds_since_2001).to_datetime
58
48
  when MARKER_DATA
59
49
  data = @src.byteslice *(decode_vl_info offset)
@@ -64,13 +54,7 @@ module PropertyList
64
54
  str_offset, str_size = decode_vl_info offset
65
55
  s = @src.byteslice str_offset, str_size * 2
66
56
  s.force_encoding('utf-16be').encode 'utf-8'
67
- when MARKER_UTF8_STRING
68
- s = @src.byteslice *(decode_vl_info offset)
69
- s.force_encoding 'utf-8'
70
57
  when MARKER_UID
71
- # Encoding is as integers, except values are unsigned.
72
- # These are used extensively in files written using NSKeyedArchiver, a serializer for Objective-C objects.
73
- # The value is the index in parse_result["$objects"]
74
58
  size = (first_byte & 0xF) + 1
75
59
  bytes = @src.byteslice offset + 1, size
76
60
  res = 0
@@ -78,21 +62,13 @@ module PropertyList
78
62
  res *= 256
79
63
  res += byte
80
64
  end
81
- UID[res]
65
+ Uid.new res
82
66
  when MARKER_ARRAY
83
67
  offset, size = decode_vl_info offset
84
68
  size.times.map do |i|
85
69
  id = decode_ref_id offset + i * @ref_byte_size
86
70
  decode_id id
87
71
  end
88
- when MARKER_ORD_SET, MARKER_SET
89
- r = Set.new
90
- offset, size = decode_vl_info offset
91
- size.times do |i|
92
- id = decode_ref_id offset + i * @ref_byte_size
93
- r << (decode_id id)
94
- end
95
- r
96
72
  when MARKER_DICT
97
73
  offset, size = decode_vl_info offset
98
74
  keys_byte_size = @ref_byte_size * size
@@ -107,18 +83,52 @@ module PropertyList
107
83
  end
108
84
  entries.sort_by! &:first
109
85
  Hash[entries]
86
+
87
+ ## the following are v1x data types ##
88
+
89
+ when MARKER_UTF8_STRING
90
+ s = @src.byteslice *(decode_vl_info offset)
91
+ s.force_encoding 'utf-8'
92
+ when MARKER_ORD_SET
93
+ r = []
94
+ offset, size = decode_vl_info offset
95
+ size.times do |i|
96
+ id = decode_ref_id offset + i * @ref_byte_size
97
+ r << (decode_id id)
98
+ end
99
+ OrdSet.new r
100
+ when MARKER_SET
101
+ r = Set.new
102
+ offset, size = decode_vl_info offset
103
+ size.times do |i|
104
+ id = decode_ref_id offset + i * @ref_byte_size
105
+ r << (decode_id id)
106
+ end
107
+ r
108
+ when MARKER_NULL
109
+ nil
110
+ when MARKER_NO_BASE_URL, MARKER_WITH_BASE_URL
111
+ # TODO check with real v1x plist
112
+ url = decode_object offset + 1
113
+ Url.new url
114
+ when MARKER_UUID
115
+ bytes = @src.byteslice offset + 1, 16
116
+ hex, _ = bytes.unpack 'H*'
117
+ Uuid.new hex.upcase
118
+ when MARKER_FILL
119
+ decode_object offest + 1
110
120
  else
111
121
  raise "unused marker: 0b#{marker.to_s(2).rjust 8, '0'}"
112
122
  end
113
123
  end
114
124
 
115
125
  def decode_vl_info offset
116
- marker, = @src.unpack "@#{offset}C"
126
+ marker, _ = @src.unpack "@#{offset}C"
117
127
  vl_size_bits = marker & 0x0F
118
128
 
119
129
  if vl_size_bits == 0x0F
120
130
  # size is followed by marker int
121
- int_marker, = @src.unpack "@#{offset + 1}C"
131
+ int_marker, _ = @src.unpack "@#{offset + 1}C"
122
132
  num_bytes = 2 ** (int_marker & 0x0F)
123
133
  size = decode_integer offset + 2, num_bytes
124
134
  [offset + 2 + num_bytes, size]
@@ -151,13 +161,13 @@ module PropertyList
151
161
  # NOTE: only num_bytes = 8 or 16 it can be negative
152
162
  case num_bytes
153
163
  when 1
154
- i, = @src.unpack "@#{offset}C"
164
+ i, _ = @src.unpack "@#{offset}C"
155
165
  when 2
156
- i, = @src.unpack "@#{offset}n"
166
+ i, _ = @src.unpack "@#{offset}n"
157
167
  when 4
158
- i, = @src.unpack "@#{offset}N"
168
+ i, _ = @src.unpack "@#{offset}N"
159
169
  when 8
160
- i, = @src.unpack "@#{offset}q>"
170
+ i, _ = @src.unpack "@#{offset}q>"
161
171
  when 16
162
172
  hi, lo = @src.unpack "@#{offset}q>2"
163
173
  i = (hi << 64) | lo
@@ -1,3 +1,3 @@
1
1
  module PropertyList
2
- VERSION = '1.0.2'.freeze
2
+ VERSION = '1.0.3'.freeze
3
3
  end
@@ -4,7 +4,7 @@ module PropertyList
4
4
  #
5
5
  # Options:
6
6
  #
7
- # - `segment:` whether output an XML segment (not wrapped with `<?xml>`, `<DOCTYPE>`, `<plist>` tags), default is `false`.
7
+ # - `segment:` whether output an XML segment (not wrapped with `<?xml>, <DOCTYPE>, <plist>` tags), default is `false`.
8
8
  # - `xml_version:` you can also specify `"1.1"` for https://www.w3.org/TR/xml11/, default is `"1.0"`, no effect if `:segment` is set to `true`.
9
9
  # - `gnu_dtd:` use GNUStep DTD instead (which is a bit different in string escaping), default is `false`.
10
10
  # - `indent_unit:` the indent unit, default value is `"\t"`, set to or `''` if you don't need indent.
@@ -124,10 +124,6 @@ module PropertyList
124
124
  @output << "#@indent<data>\n#{base64}#@indent</data>\n"
125
125
  end
126
126
 
127
- def comment_tag content
128
- @output << "#@indent<!-- #{content} -->\n"
129
- end
130
-
131
127
  def tag name, contents=nil
132
128
  if block_given?
133
129
  @output << "#@indent<#{name}>\n"
@@ -22,7 +22,6 @@ module PropertyList
22
22
  # TODO xml_encoding = xml_declaration.match(/(?:\A|\s)encoding=(?:"(.*?)"|'(.*?)')(?:\s|\Z)/)
23
23
 
24
24
  skip_space_and_comments
25
- # TODO doctype should co-exist with xml
26
25
  @lexer.skip(/\s*<!DOCTYPE\s+.*?>/m)
27
26
  skip_space_and_comments
28
27
 
@@ -115,7 +114,7 @@ module PropertyList
115
114
  def syntax_error msg
116
115
  pre = @lexer.string[0...@lexer.pos]
117
116
  line = pre.count("\n") + 1
118
- col = pre.size - pre.rindex("\n")
117
+ col = pre.size - (pre.rindex("\n") || -1)
119
118
  raise SyntaxError, msg + " at line: #{line} col: #{col} #{@lexer.inspect}", caller
120
119
  end
121
120
  end
data/lib/property-list.rb CHANGED
@@ -44,38 +44,69 @@ module PropertyList
44
44
 
45
45
  # binary plist v0x elements:
46
46
 
47
- class UID
47
+ # These are used extensively in files written using NSKeyedArchiver, a serializer for Objective-C objects.
48
+ # The value is the index in parse_result["$objects"]
49
+ #
50
+ # call-seq:
51
+ #
52
+ # PropertyList::Uid.new 34
53
+ class Uid
48
54
  def initialize uid
49
55
  @uid = uid
50
56
  end
57
+
51
58
  attr_reader :uid
59
+
60
+ def == other
61
+ other.is_a?(Uid) and @uid == other.uid
62
+ end
52
63
  end
53
64
 
54
65
  # binary plist v1x elements:
55
66
 
56
- class URL
67
+ # call-seq:
68
+ #
69
+ # PropertyList::Url.new 'http://foo.com' # with base
70
+ # PropertyList::Url.new '/foo.com' # no base
71
+ class Url
57
72
  def initialize url
58
73
  @url = url
59
74
  end
75
+
60
76
  attr_reader :url
77
+
78
+ def == other
79
+ other.is_a?(Url) and @url == other.url
80
+ end
61
81
  end
62
82
 
63
- class UUID
83
+ # call-seq:
84
+ #
85
+ # PropertyList::Uuid.new 'F' * 32
86
+ class Uuid
64
87
  def initialize uuid
65
88
  @uuid = uuid
66
89
  end
90
+
67
91
  attr_reader :uuid
92
+
93
+ def == other
94
+ other.is_a?(Uuid) and @uuid == other.uuid
95
+ end
68
96
  end
69
97
 
70
- class OrderedSet
98
+ # call-seq:
99
+ #
100
+ # PropertyList::OrdSet.new ['foo', 'bar', 3, 4]
101
+ class OrdSet
71
102
  def initialize elements
72
103
  @elements = elements.uniq
73
104
  end
74
105
 
75
- def each
76
- @elements.each do |e|
77
- yield e
78
- end
106
+ attr_reader :elements
107
+
108
+ def == other
109
+ other.is_a?(OrdSet) and @elements == other.elements
79
110
  end
80
111
  end
81
112
  end
@@ -1,24 +1,29 @@
1
1
  require_relative 'lib/property-list/version'
2
2
 
3
+ class Array
4
+ if ![].respond_to?(:grep_v)
5
+ def grep_v reg
6
+ self - grep(reg)
7
+ end
8
+ end
9
+ end
10
+
11
+ puts 'wa?'
3
12
  Gem::Specification.new do |spec|
4
13
  spec.name = "property-list"
5
14
  spec.version = PropertyList::VERSION
6
- spec.authors = ["Luikore"]
15
+ puts 'gsd'
16
+ spec.author = "Luikore"
17
+ puts 'hmm'
7
18
  spec.email = 'no@email'
8
19
 
9
- spec.summary = "Property List (plist, propertylist) library with all formats support"
10
- spec.description = "Fully featured propertylist library.
11
- Can load and dump XML/ASCII/Binary plists and offer fine-grained formatting options.
20
+ spec.summary = "Property list (plist) library with all formats support"
21
+ spec.description = "Fully featured property_plist library.
22
+ Can load and dump XML/ASCII/Binary/SMIME propertyplist and offer fine-grained formatting options.
12
23
  Cross platform, clean code, performance tuned, no dependency."
13
24
  spec.homepage = "https://github.com/luikore/property-list"
14
25
  spec.license = "BSD-3-Clause"
15
26
 
16
27
  spec.files = `git ls-files -z`.split("\x0").grep_v %r{^(test|spec|features)/}
17
28
  spec.require_paths = ["lib"]
18
-
19
- spec.add_development_dependency "bundler", "~> 1.15"
20
- spec.add_development_dependency "rake", "~> 12.0"
21
- spec.add_development_dependency "test-unit", "~> 1.2"
22
- spec.add_development_dependency "pry", "~> 0.10"
23
- spec.add_development_dependency "simplecov", "~> 0.14"
24
29
  end
metadata CHANGED
@@ -1,88 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: property-list
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luikore
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-13 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.15'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.15'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '12.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '12.0'
41
- - !ruby/object:Gem::Dependency
42
- name: test-unit
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1.2'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '1.2'
55
- - !ruby/object:Gem::Dependency
56
- name: pry
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '0.10'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '0.10'
69
- - !ruby/object:Gem::Dependency
70
- name: simplecov
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '0.14'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '0.14'
11
+ date: 2017-09-15 00:00:00.000000000 Z
12
+ dependencies: []
83
13
  description: |-
84
- Fully featured propertylist library.
85
- Can load and dump XML/ASCII/Binary plists and offer fine-grained formatting options.
14
+ Fully featured property_plist library.
15
+ Can load and dump XML/ASCII/Binary/SMIME propertyplist and offer fine-grained formatting options.
86
16
  Cross platform, clean code, performance tuned, no dependency.
87
17
  email: no@email
88
18
  executables: []
@@ -91,6 +21,7 @@ extra_rdoc_files: []
91
21
  files:
92
22
  - ".gitignore"
93
23
  - ".rdoc_options"
24
+ - ".travis.yml"
94
25
  - LICENSE
95
26
  - README.md
96
27
  - Rakefile
@@ -126,8 +57,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
57
  version: '0'
127
58
  requirements: []
128
59
  rubyforge_project:
129
- rubygems_version: 2.6.11
60
+ rubygems_version: 2.6.13
130
61
  signing_key:
131
62
  specification_version: 4
132
- summary: Property List (plist, propertylist) library with all formats support
63
+ summary: Property list (plist) library with all formats support
133
64
  test_files: []