CFPropertyList 2.0.16 → 2.0.17

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.
@@ -16,7 +16,7 @@ module CFPropertyList
16
16
  @offsets = []
17
17
 
18
18
  fd = nil
19
- if(opts.has_key?(:file)) then
19
+ if(opts.has_key?(:file))
20
20
  fd = File.open(opts[:file],"rb")
21
21
  file = opts[:file]
22
22
  else
@@ -40,7 +40,7 @@ module CFPropertyList
40
40
  # decode offset table
41
41
  formats = ["","C*","n*","(H6)*","N*"]
42
42
  @offsets = coded_offset_table.unpack(formats[offset_size])
43
- if(offset_size == 3) then
43
+ if(offset_size == 3)
44
44
  0.upto(@offsets.size-1) { |i| @offsets[i] = @offsets[i].to_i(16) }
45
45
  end
46
46
 
@@ -48,7 +48,7 @@ module CFPropertyList
48
48
  val = read_binary_object_at(file,fd,top_object)
49
49
 
50
50
  fd.close
51
- return val
51
+ val
52
52
  end
53
53
 
54
54
 
@@ -60,19 +60,21 @@ module CFPropertyList
60
60
 
61
61
  @written_object_count = 0
62
62
  @object_table = []
63
- @object_ref_size = 0
64
63
 
65
64
  @offsets = []
66
65
 
67
66
  binary_str = "bplist00"
68
67
 
69
68
  @object_refs = count_object_refs(opts[:root])
70
- @object_ref_size = Binary.bytes_needed(@object_refs)
71
69
 
72
70
  opts[:root].to_binary(self)
73
71
 
74
72
  next_offset = 8
75
- offsets = @object_table.collect { |object| offset = next_offset; next_offset += object.bytesize; offset }
73
+ offsets = @object_table.map do |object|
74
+ offset = next_offset
75
+ next_offset += object.bytesize
76
+ offset
77
+ end
76
78
  binary_str << @object_table.join
77
79
 
78
80
  table_offset = next_offset
@@ -89,60 +91,59 @@ module CFPropertyList
89
91
  end
90
92
  end
91
93
 
92
- binary_str << [offset_size, @object_ref_size].pack("x6CC")
94
+ binary_str << [offset_size, object_ref_size(@object_refs)].pack("x6CC")
93
95
  binary_str << [@object_table.size].pack("x4N")
94
96
  binary_str << [0].pack("x4N")
95
97
  binary_str << [table_offset].pack("x4N")
96
98
 
97
- return binary_str
99
+ binary_str
100
+ end
101
+
102
+ def object_ref_size object_refs
103
+ Binary.bytes_needed(object_refs)
98
104
  end
99
105
 
100
106
  # read a „null” type (i.e. null byte, marker byte, bool value)
101
107
  def read_binary_null_type(length)
102
108
  case length
103
- when 0 then return 0 # null byte
104
- when 8 then return CFBoolean.new(false)
105
- when 9 then return CFBoolean.new(true)
106
- when 15 then return 15 # fill type
109
+ when 0 then 0 # null byte
110
+ when 8 then CFBoolean.new(false)
111
+ when 9 then CFBoolean.new(true)
112
+ when 15 then 15 # fill type
113
+ else
114
+ raise CFFormatError.new("unknown null type: #{length}")
107
115
  end
108
-
109
- raise CFFormatError.new("unknown null type: #{length}")
110
116
  end
111
117
  protected :read_binary_null_type
112
118
 
113
119
  # read a binary int value
114
120
  def read_binary_int(fname,fd,length)
115
- raise CFFormatError.new("Integer greater than 8 bytes: #{length}") if length > 3
121
+ if length > 3
122
+ raise CFFormatError.new("Integer greater than 8 bytes: #{length}")
123
+ end
116
124
 
117
125
  nbytes = 1 << length
118
126
 
119
- val = nil
120
127
  buff = fd.read(nbytes)
121
128
 
122
- case length
123
- when 0 then
124
- val = buff.unpack("C")
125
- val = val[0]
126
- when 1 then
127
- val = buff.unpack("n")
128
- val = val[0]
129
- when 2 then
130
- val = buff.unpack("N")
131
- val = val[0]
132
- when 3
133
- hiword,loword = buff.unpack("NN")
134
- if (hiword & 0x80000000) != 0
135
- # 8 byte integers are always signed, and are negative when bit 63 is
136
- # set. Decoding into either a Fixnum or Bignum is tricky, however,
137
- # because the size of a Fixnum varies among systems, and Ruby
138
- # doesn't consider the number to be negative, and won't sign extend.
139
- val = -(2**63 - ((hiword & 0x7fffffff) << 32 | loword))
140
- else
141
- val = hiword << 32 | loword
129
+ CFInteger.new(
130
+ case length
131
+ when 0 then buff.unpack("C")[0]
132
+ when 1 then buff.unpack("n")[0]
133
+ when 2 then buff.unpack("N")[0]
134
+ when 3
135
+ hiword,loword = buff.unpack("NN")
136
+ if (hiword & 0x80000000) != 0
137
+ # 8 byte integers are always signed, and are negative when bit 63 is
138
+ # set. Decoding into either a Fixnum or Bignum is tricky, however,
139
+ # because the size of a Fixnum varies among systems, and Ruby
140
+ # doesn't consider the number to be negative, and won't sign extend.
141
+ -(2**63 - ((hiword & 0x7fffffff) << 32 | loword))
142
+ else
143
+ hiword << 32 | loword
144
+ end
142
145
  end
143
- end
144
-
145
- return CFInteger.new(val);
146
+ )
146
147
  end
147
148
  protected :read_binary_int
148
149
 
@@ -151,23 +152,22 @@ module CFPropertyList
151
152
  raise CFFormatError.new("Real greater than 8 bytes: #{length}") if length > 3
152
153
 
153
154
  nbytes = 1 << length
154
- val = nil
155
155
  buff = fd.read(nbytes)
156
156
 
157
- case length
158
- when 0 then # 1 byte float? must be an error
159
- raise CFFormatError.new("got #{length+1} byte float, must be an error!")
160
- when 1 then # 2 byte float? must be an error
161
- raise CFFormatError.new("got #{length+1} byte float, must be an error!")
162
- when 2 then
163
- val = buff.reverse.unpack("f")
164
- val = val[0]
165
- when 3 then
166
- val = buff.reverse.unpack("d")
167
- val = val[0]
168
- end
169
-
170
- return CFReal.new(val)
157
+ CFReal.new(
158
+ case length
159
+ when 0 # 1 byte float? must be an error
160
+ raise CFFormatError.new("got #{length+1} byte float, must be an error!")
161
+ when 1 # 2 byte float? must be an error
162
+ raise CFFormatError.new("got #{length+1} byte float, must be an error!")
163
+ when 2 then
164
+ buff.reverse.unpack("f")[0]
165
+ when 3 then
166
+ buff.reverse.unpack("d")[0]
167
+ else
168
+ fail "unexpected length: #{length}"
169
+ end
170
+ )
171
171
  end
172
172
  protected :read_binary_real
173
173
 
@@ -176,48 +176,46 @@ module CFPropertyList
176
176
  raise CFFormatError.new("Date greater than 8 bytes: #{length}") if length > 3
177
177
 
178
178
  nbytes = 1 << length
179
- val = nil
180
179
  buff = fd.read(nbytes)
181
180
 
182
- case length
183
- when 0 then # 1 byte CFDate is an error
184
- raise CFFormatError.new("#{length+1} byte CFDate, error")
185
- when 1 then # 2 byte CFDate is an error
186
- raise CFFormatError.new("#{length+1} byte CFDate, error")
187
- when 2 then
188
- val = buff.reverse.unpack("f")
189
- val = val[0]
190
- when 3 then
191
- val = buff.reverse.unpack("d")
192
- val = val[0]
193
- end
194
-
195
- return CFDate.new(val,CFDate::TIMESTAMP_APPLE)
181
+ CFDate.new(
182
+ case length
183
+ when 0 then # 1 byte CFDate is an error
184
+ raise CFFormatError.new("#{length+1} byte CFDate, error")
185
+ when 1 then # 2 byte CFDate is an error
186
+ raise CFFormatError.new("#{length+1} byte CFDate, error")
187
+ when 2 then
188
+ buff.reverse.unpack("f")[0]
189
+ when 3 then
190
+ buff.reverse.unpack("d")[0]
191
+ end,
192
+ CFDate::TIMESTAMP_APPLE
193
+ )
196
194
  end
197
195
  protected :read_binary_date
198
196
 
199
197
  # Read a binary data value
200
198
  def read_binary_data(fname,fd,length)
201
- buff = "";
202
- buff = fd.read(length) if length > 0
203
- return CFData.new(buff,CFData::DATA_RAW)
199
+ CFData.new(read_fd(fd, length), CFData::DATA_RAW)
204
200
  end
205
201
  protected :read_binary_data
206
202
 
203
+ def read_fd fd, length
204
+ length > 0 ? fd.read(length) : ""
205
+ end
206
+
207
207
  # Read a binary string value
208
208
  def read_binary_string(fname,fd,length)
209
- buff = ""
210
- buff = fd.read(length) if length > 0
211
-
209
+ buff = read_fd fd, length
212
210
  @unique_table[buff] = true unless @unique_table.has_key?(buff)
213
- return CFString.new(buff)
211
+ CFString.new(buff)
214
212
  end
215
213
  protected :read_binary_string
216
214
 
217
215
  # Convert the given string from one charset to another
218
216
  def Binary.charset_convert(str,from,to="UTF-8")
219
217
  return str.clone.force_encoding(from).encode(to) if str.respond_to?("encode")
220
- return Iconv.conv(to,from,str)
218
+ Iconv.conv(to,from,str)
221
219
  end
222
220
 
223
221
  # Count characters considering character set
@@ -228,7 +226,7 @@ module CFPropertyList
228
226
  utf8_str = Iconv.conv("UTF-8",charset,str)
229
227
  size = utf8_str.scan(/./mu).size
230
228
  end
231
-
229
+
232
230
  # UTF-16 code units in the range D800-DBFF are the beginning of
233
231
  # a surrogate pair, and count as one additional character for
234
232
  # length calculation.
@@ -239,8 +237,8 @@ module CFPropertyList
239
237
  str.split('').each_slice(2) { |pair| size += 1 if ("\xd8".."\xdb").include?(pair[0]) }
240
238
  end
241
239
  end
242
-
243
- return size
240
+
241
+ size
244
242
  end
245
243
 
246
244
  # Read a unicode string value, coded as UTF-16BE
@@ -251,7 +249,7 @@ module CFPropertyList
251
249
  buff = fd.read(2*length)
252
250
 
253
251
  @unique_table[buff] = true unless @unique_table.has_key?(buff)
254
- return CFString.new(Binary.charset_convert(buff,"UTF-16BE","UTF-8"))
252
+ CFString.new(Binary.charset_convert(buff,"UTF-16BE","UTF-8"))
255
253
  end
256
254
  protected :read_binary_unicode_string
257
255
 
@@ -260,7 +258,7 @@ module CFPropertyList
260
258
  ary = []
261
259
 
262
260
  # first: read object refs
263
- if(length != 0) then
261
+ if(length != 0)
264
262
  buff = fd.read(length * @object_ref_size)
265
263
  objects = buff.unpack(@object_ref_size == 1 ? "C*" : "n*")
266
264
 
@@ -271,7 +269,7 @@ module CFPropertyList
271
269
  end
272
270
  end
273
271
 
274
- return CFArray.new(ary)
272
+ CFArray.new(ary)
275
273
  end
276
274
  protected :read_binary_array
277
275
 
@@ -296,7 +294,7 @@ module CFPropertyList
296
294
  end
297
295
  end
298
296
 
299
- return CFDictionary.new(dict)
297
+ CFDictionary.new(dict)
300
298
  end
301
299
  protected :read_binary_dict
302
300
 
@@ -316,29 +314,26 @@ module CFPropertyList
316
314
  object_length = object_length.value
317
315
  end
318
316
 
319
- retval = nil
320
317
  case object_type
321
- when '0' then # null, false, true, fillbyte
322
- retval = read_binary_null_type(object_length)
323
- when '1' then # integer
324
- retval = read_binary_int(fname,fd,object_length)
325
- when '2' then # real
326
- retval = read_binary_real(fname,fd,object_length)
327
- when '3' then # date
328
- retval = read_binary_date(fname,fd,object_length)
329
- when '4' then # data
330
- retval = read_binary_data(fname,fd,object_length)
331
- when '5' then # byte string, usually utf8 encoded
332
- retval = read_binary_string(fname,fd,object_length)
333
- when '6' then # unicode string (utf16be)
334
- retval = read_binary_unicode_string(fname,fd,object_length)
335
- when 'a' then # array
336
- retval = read_binary_array(fname,fd,object_length)
337
- when 'd' then # dictionary
338
- retval = read_binary_dict(fname,fd,object_length)
318
+ when '0' # null, false, true, fillbyte
319
+ read_binary_null_type(object_length)
320
+ when '1' # integer
321
+ read_binary_int(fname,fd,object_length)
322
+ when '2' # real
323
+ read_binary_real(fname,fd,object_length)
324
+ when '3' # date
325
+ read_binary_date(fname,fd,object_length)
326
+ when '4' # data
327
+ read_binary_data(fname,fd,object_length)
328
+ when '5' # byte string, usually utf8 encoded
329
+ read_binary_string(fname,fd,object_length)
330
+ when '6' # unicode string (utf16be)
331
+ read_binary_unicode_string(fname,fd,object_length)
332
+ when 'a' # array
333
+ read_binary_array(fname,fd,object_length)
334
+ when 'd' # dictionary
335
+ read_binary_dict(fname,fd,object_length)
339
336
  end
340
-
341
- return retval
342
337
  end
343
338
  protected :read_binary_object
344
339
 
@@ -346,36 +341,30 @@ module CFPropertyList
346
341
  def read_binary_object_at(fname,fd,pos)
347
342
  position = @offsets[pos]
348
343
  fd.seek(position,IO::SEEK_SET)
349
- return read_binary_object(fname,fd)
344
+ read_binary_object(fname,fd)
350
345
  end
351
346
  protected :read_binary_object_at
352
347
 
353
348
  # pack an +int+ of +nbytes+ with size
354
349
  def Binary.pack_it_with_size(nbytes,int)
355
350
  case nbytes
356
- when 1
357
- return [int].pack('c')
358
- when 2
359
- return [int].pack('n')
360
- when 4
361
- return [int].pack('N')
351
+ when 1 then [int].pack('c')
352
+ when 2 then [int].pack('n')
353
+ when 4 then [int].pack('N')
362
354
  when 8
363
- return [int >> 32, int & 0xFFFFFFFF].pack('NN')
355
+ [int >> 32, int & 0xFFFFFFFF].pack('NN')
364
356
  else
365
357
  raise CFFormatError.new("Don't know how to pack #{nbytes} byte integer")
366
358
  end
367
359
  end
368
-
360
+
369
361
  def Binary.pack_int_array_with_size(nbytes, array)
370
362
  case nbytes
371
- when 1
372
- array.pack('C*')
373
- when 2
374
- array.pack('n*')
375
- when 4
376
- array.pack('N*')
363
+ when 1 then array.pack('C*')
364
+ when 2 then array.pack('n*')
365
+ when 4 then array.pack('N*')
377
366
  when 8
378
- array.collect { |int| [int >> 32, int & 0xFFFFFFFF].pack('NN') }.join
367
+ array.map { |int| [int >> 32, int & 0xFFFFFFFF].pack('NN') }.join
379
368
  else
380
369
  raise CFFormatError.new("Don't know how to pack #{nbytes} byte integer")
381
370
  end
@@ -383,41 +372,36 @@ module CFPropertyList
383
372
 
384
373
  # calculate how many bytes are needed to save +count+
385
374
  def Binary.bytes_needed(count)
386
- if count < 2**8
387
- nbytes = 1
388
- elsif count < 2**16
389
- nbytes = 2
390
- elsif count < 2**32
391
- nbytes = 4
392
- elsif count < 2**64
393
- nbytes = 8
375
+ case
376
+ when count < 2**8 then 1
377
+ when count < 2**16 then 2
378
+ when count < 2**32 then 4
379
+ when count < 2**64 then 8
394
380
  else
395
381
  raise CFFormatError.new("Data size too large: #{count}")
396
382
  end
397
-
398
- return nbytes
399
383
  end
400
384
 
401
385
  # Create a type byte for binary format as defined by apple
402
386
  def Binary.type_bytes(type, length)
403
387
  if length < 15
404
- return [(type << 4) | length].pack('C')
388
+ [(type << 4) | length].pack('C')
405
389
  else
406
390
  bytes = [(type << 4) | 0xF]
407
391
  if length <= 0xFF
408
- return bytes.push(0x10, length).pack('CCC') # 1 byte length
392
+ bytes.push(0x10, length).pack('CCC') # 1 byte length
409
393
  elsif length <= 0xFFFF
410
- return bytes.push(0x11, length).pack('CCn') # 2 byte length
394
+ bytes.push(0x11, length).pack('CCn') # 2 byte length
411
395
  elsif length <= 0xFFFFFFFF
412
- return bytes.push(0x12, length).pack('CCN') # 4 byte length
396
+ bytes.push(0x12, length).pack('CCN') # 4 byte length
413
397
  elsif length <= 0x7FFFFFFFFFFFFFFF
414
- return bytes.push(0x13, length >> 32, length & 0xFFFFFFFF).pack('CCNN') # 8 byte length
398
+ bytes.push(0x13, length >> 32, length & 0xFFFFFFFF).pack('CCNN') # 8 byte length
415
399
  else
416
400
  raise CFFormatError.new("Integer too large: #{int}")
417
401
  end
418
402
  end
419
403
  end
420
-
404
+
421
405
  def count_object_refs(object)
422
406
  case object
423
407
  when CFArray
@@ -443,140 +427,115 @@ module CFPropertyList
443
427
 
444
428
  def Binary.ascii_string?(str)
445
429
  if str.respond_to?(:ascii_only?)
446
- return str.ascii_only?
430
+ str.ascii_only?
447
431
  else
448
- return str.scan(/[\x80-\xFF]/mn).size == 0
432
+ str !~ /[\x80-\xFF]/mn
449
433
  end
450
434
  end
451
-
435
+
452
436
  # Uniques and transforms a string value to binary format and adds it to the object table
453
437
  def string_to_binary(val)
454
- saved_object_count = -1
455
-
456
- unless(@unique_table.has_key?(val)) then
457
- saved_object_count = @written_object_count
458
- @written_object_count += 1
459
-
460
- @unique_table[val] = saved_object_count
461
- utf16 = !Binary.ascii_string?(val)
462
-
463
- utf8_strlen = 0
464
- if(utf16) then
438
+ @unique_table[val] ||= begin
439
+ if !Binary.ascii_string?(val)
465
440
  utf8_strlen = Binary.charset_strlen(val, "UTF-8")
466
441
  val = Binary.charset_convert(val,"UTF-8","UTF-16BE")
467
442
  bdata = Binary.type_bytes(0b0110, Binary.charset_strlen(val,"UTF-16BE"))
468
443
 
469
444
  val.force_encoding("ASCII-8BIT") if val.respond_to?("encode")
470
- @object_table[saved_object_count] = bdata + val
445
+ @object_table[@written_object_count] = bdata << val
471
446
  else
472
447
  utf8_strlen = val.bytesize
473
448
  bdata = Binary.type_bytes(0b0101,val.bytesize)
474
- @object_table[saved_object_count] = bdata + val
449
+ @object_table[@written_object_count] = bdata << val
475
450
  end
476
- else
477
- saved_object_count = @unique_table[val]
451
+ @written_object_count += 1
452
+ @written_object_count - 1
478
453
  end
479
-
480
- return saved_object_count
481
454
  end
482
455
 
483
456
  # Codes an integer to binary format
484
457
  def int_to_binary(value)
485
458
  nbytes = 0
486
- nbytes = 1 if value > 0xFF # 1 byte integer
459
+ nbytes = 1 if value > 0xFF # 1 byte integer
487
460
  nbytes += 1 if value > 0xFFFF # 4 byte integer
488
461
  nbytes += 1 if value > 0xFFFFFFFF # 8 byte integer
489
- nbytes = 3 if value < 0 # 8 byte integer, since signed
490
-
491
- bdata = Binary.type_bytes(0b0001, nbytes)
492
- buff = ""
493
-
494
- if(nbytes < 3) then
495
- fmt = "N"
496
-
497
- if(nbytes == 0) then
498
- fmt = "C"
499
- elsif(nbytes == 1)
500
- fmt = "n"
462
+ nbytes = 3 if value < 0 # 8 byte integer, since signed
463
+
464
+ Binary.type_bytes(0b0001, nbytes) <<
465
+ if nbytes < 3
466
+ [value].pack(
467
+ if nbytes == 0 then "C"
468
+ elsif nbytes == 1 then "n"
469
+ else "N"
470
+ end
471
+ )
472
+ else
473
+ # 64 bit signed integer; we need the higher and the lower 32 bit of the value
474
+ high_word = value >> 32
475
+ low_word = value & 0xFFFFFFFF
476
+ [high_word,low_word].pack("NN")
501
477
  end
502
-
503
- buff = [value].pack(fmt)
504
- else
505
- # 64 bit signed integer; we need the higher and the lower 32 bit of the value
506
- high_word = value >> 32
507
- low_word = value & 0xFFFFFFFF
508
- buff = [high_word,low_word].pack("NN")
509
- end
510
-
511
- return bdata + buff
512
478
  end
513
479
 
514
480
  # Codes a real value to binary format
515
481
  def real_to_binary(val)
516
- bdata = Binary.type_bytes(0b0010,3)
517
- buff = [val].pack("d")
518
- return bdata + buff.reverse
482
+ Binary.type_bytes(0b0010,3) << [val].pack("d").reverse
519
483
  end
520
484
 
521
485
  # Converts a numeric value to binary and adds it to the object table
522
486
  def num_to_binary(value)
523
- saved_object_count = @written_object_count
524
- @written_object_count += 1
525
-
526
- val = ""
527
- if(value.is_a?(CFInteger)) then
528
- val = int_to_binary(value.value)
529
- else
530
- val = real_to_binary(value.value)
531
- end
487
+ @object_table[@written_object_count] =
488
+ if value.is_a?(CFInteger)
489
+ int_to_binary(value.value)
490
+ else
491
+ real_to_binary(value.value)
492
+ end
532
493
 
533
- @object_table[saved_object_count] = val
534
- return saved_object_count
494
+ @written_object_count += 1
495
+ @written_object_count - 1
535
496
  end
536
497
 
537
498
  # Convert date value (apple format) to binary and adds it to the object table
538
499
  def date_to_binary(val)
539
- saved_object_count = @written_object_count
540
- @written_object_count += 1
541
-
542
500
  val = val.getutc.to_f - CFDate::DATE_DIFF_APPLE_UNIX # CFDate is a real, number of seconds since 01/01/2001 00:00:00 GMT
543
501
 
544
- bdata = Binary.type_bytes(0b0011, 3)
545
- @object_table[saved_object_count] = bdata + [val].pack("d").reverse
502
+ @object_table[@written_object_count] =
503
+ (Binary.type_bytes(0b0011, 3) << [val].pack("d").reverse)
546
504
 
547
- return saved_object_count
505
+ @written_object_count += 1
506
+ @written_object_count - 1
548
507
  end
549
508
 
550
509
  # Convert a bool value to binary and add it to the object table
551
510
  def bool_to_binary(val)
552
- saved_object_count = @written_object_count
553
- @written_object_count += 1
554
511
 
555
- @object_table[saved_object_count] = val ? "\x9" : "\x8" # 0x9 is 1001, type indicator for true; 0x8 is 1000, type indicator for false
556
- return saved_object_count
512
+ @object_table[@written_object_count] = val ? "\x9" : "\x8" # 0x9 is 1001, type indicator for true; 0x8 is 1000, type indicator for false
513
+ @written_object_count += 1
514
+ @written_object_count - 1
557
515
  end
558
516
 
559
517
  # Convert data value to binary format and add it to the object table
560
518
  def data_to_binary(val)
561
- saved_object_count = @written_object_count
562
- @written_object_count += 1
563
-
564
- bdata = Binary.type_bytes(0b0100, val.bytesize)
565
- @object_table[saved_object_count] = bdata + val
519
+ @object_table[@written_object_count] =
520
+ (Binary.type_bytes(0b0100, val.bytesize) << val)
566
521
 
567
- return saved_object_count
522
+ @written_object_count += 1
523
+ @written_object_count - 1
568
524
  end
569
525
 
570
526
  # Convert array to binary format and add it to the object table
571
527
  def array_to_binary(val)
572
528
  saved_object_count = @written_object_count
573
529
  @written_object_count += 1
530
+ #@object_refs += val.value.size
574
531
 
575
- bdata = Binary.type_bytes(0b1010, val.value.size) +
576
- Binary.pack_int_array_with_size(@object_ref_size, val.value.collect { |v| v.to_binary(self) })
532
+ values = val.value.map { |v| v.to_binary(self) }
533
+ bdata = Binary.type_bytes(0b1010, val.value.size) <<
534
+ Binary.pack_int_array_with_size(object_ref_size(@object_refs),
535
+ values)
577
536
 
578
537
  @object_table[saved_object_count] = bdata
579
- return saved_object_count
538
+ saved_object_count
580
539
  end
581
540
 
582
541
  # Convert dictionary to binary format and add it to the object table
@@ -584,15 +543,44 @@ module CFPropertyList
584
543
  saved_object_count = @written_object_count
585
544
  @written_object_count += 1
586
545
 
587
- keys_and_values = val.value.keys.collect { |k| CFString.new(k).to_binary(self) }
588
- keys_and_values += val.value.keys.collect { |k| val.value[k].to_binary(self) }
589
-
590
- bdata = Binary.type_bytes(0b1101,val.value.size) +
591
- Binary.pack_int_array_with_size(@object_ref_size, keys_and_values)
546
+ #@object_refs += val.value.keys.size * 2
547
+
548
+ keys_and_values = val.value.keys.map { |k| CFString.new(k).to_binary(self) }
549
+ keys_and_values.concat(val.value.values.map { |v| v.to_binary(self) })
550
+
551
+ bdata = Binary.type_bytes(0b1101,val.value.size) <<
552
+ Binary.pack_int_array_with_size(object_ref_size(@object_refs), keys_and_values)
592
553
 
593
554
  @object_table[saved_object_count] = bdata
594
555
  return saved_object_count
595
556
  end
557
+
558
+ =begin It is difficult to reap benefits from an Enumerator
559
+ # like an array, but we don't know length ahead of time
560
+ def enum_to_binary(val)
561
+ saved_object_count = @written_object_count
562
+ @written_object_count += 1
563
+
564
+ size = 0
565
+ # This destroys our low-memory stream.
566
+ # However, testing shows that it is faster
567
+ # Probably because packing this single Array (in pack_int_array_with_size)
568
+ # is faster than packing each individual array member separately
569
+ # i.e. to be faster it needs an Enumerator#pack
570
+ binary = val.value.map do |v|
571
+ size += 1;
572
+ v.to_binary(self)
573
+ end
574
+ @object_refs += size
575
+
576
+ bdata = Binary.type_bytes(0b1010, size) <<
577
+ Binary.pack_int_array_with_size(object_ref_size(@object_refs), binary)
578
+
579
+ @object_table[saved_object_count] = bdata
580
+ saved_object_count
581
+ end
582
+ =end
583
+
596
584
  end
597
585
  end
598
586
 
@@ -101,41 +101,55 @@ module CFPropertyList
101
101
  #
102
102
  # cftypes = CFPropertyList.guess(x,:convert_unknown_to_string => true,:converter_method => :to_hash)
103
103
  def guess(object, options = {})
104
- if(object.is_a?(Fixnum) || object.is_a?(Integer)) then
105
- return CFInteger.new(object)
106
- elsif(object.is_a?(Float) || (Object.const_defined?('BigDecimal') and object.is_a?(BigDecimal))) then
107
- return CFReal.new(object)
108
- elsif(object.is_a?(TrueClass) || object.is_a?(FalseClass)) then
109
- return CFBoolean.new(object)
110
- elsif(object.is_a?(String)) then
111
- return object.blob? ? CFData.new(object, CFData::DATA_RAW) : CFString.new(object)
112
- elsif(object.respond_to?(:read)) then
113
- return CFData.new(object.read(), CFData::DATA_RAW)
114
- elsif(object.is_a?(Time) || object.is_a?(DateTime) || object.is_a?(Date)) then
115
- return CFDate.new(object)
116
- elsif(object.is_a?(Array)) then
104
+ case object
105
+ when Fixnum, Integer then CFInteger.new(object)
106
+ when Float then CFReal.new(object)
107
+ when TrueClass, FalseClass then CFBoolean.new(object)
108
+
109
+ when String
110
+ object.blob? ? CFData.new(object, CFData::DATA_RAW) : CFString.new(object)
111
+
112
+ when Time, DateTime, Date then CFDate.new(object)
113
+
114
+ when Array, Enumerator
117
115
  ary = Array.new
118
- object.each do
119
- |o|
116
+ object.each do |o|
120
117
  ary.push CFPropertyList.guess(o, options)
121
118
  end
119
+ CFArray.new(ary)
122
120
 
123
- return CFArray.new(ary)
124
- elsif(object.is_a?(Hash)) then
121
+ when Hash
125
122
  hsh = Hash.new
126
- object.each_pair do
127
- |k,v|
123
+ object.each_pair do |k,v|
128
124
  k = k.to_s if k.is_a?(Symbol)
129
125
  hsh[k] = CFPropertyList.guess(v, options)
130
126
  end
127
+ CFDictionary.new(hsh)
128
+
129
+ =begin
130
+ when Enumerator
131
+ CFEnumerator.new(
132
+ Enumerator.new do |yielder|
133
+ object.each do |o|
134
+ yielder << CFPropertyList.guess(o, options)
135
+ end
136
+ end
137
+ )
138
+ =end
131
139
 
132
- return CFDictionary.new(hsh)
133
- elsif options[:converter_method] and object.respond_to?(options[:converter_method]) then
134
- return CFPropertyList.guess(object.send(options[:converter_method]),options)
135
- elsif options[:convert_unknown_to_string] then
136
- return CFString.new(object.to_s)
137
140
  else
138
- raise CFTypeError.new("Unknown class #{object.class.to_s}! Try using :convert_unknown_to_string if you want to use unknown object types!")
141
+ case
142
+ when Object.const_defined?('BigDecimal') && object.is_a?(BigDecimal)
143
+ CFReal.new(object)
144
+ when object.respond_to?(:read)
145
+ CFData.new(object.read(), CFData::DATA_RAW)
146
+ when options[:converter_method] && object.respond_to?(options[:converter_method])
147
+ CFPropertyList.guess(object.send(options[:converter_method]),options)
148
+ when options[:convert_unknown_to_string]
149
+ CFString.new(object.to_s)
150
+ else
151
+ raise CFTypeError.new("Unknown class #{object.class.to_s}. Try using :convert_unknown_to_string if you want to use unknown object types!")
152
+ end
139
153
  end
140
154
  end
141
155
 
@@ -337,6 +351,17 @@ class Array
337
351
  end
338
352
  end
339
353
 
354
+ class Enumerator
355
+ # convert an array to plist format
356
+ def to_plist(options={})
357
+ options[:plist_format] ||= CFPropertyList::List::FORMAT_BINARY
358
+
359
+ plist = CFPropertyList::List.new
360
+ plist.value = CFPropertyList.guess(self, options)
361
+ plist.to_str(options[:plist_format])
362
+ end
363
+ end
364
+
340
365
  class Hash
341
366
  # convert a hash to plist format
342
367
  def to_plist(options={})
@@ -16,19 +16,13 @@ module CFPropertyList
16
16
  # value of the type
17
17
  attr_accessor :value
18
18
 
19
-
20
- # set internal value to parameter value by default
21
19
  def initialize(value=nil)
22
20
  @value = value
23
21
  end
24
22
 
25
- # convert type to XML
26
- def to_xml
27
- end
23
+ def to_xml; end
28
24
 
29
- # convert type to binary
30
- def to_binary(bplist)
31
- end
25
+ def to_binary(bplist) end
32
26
  end
33
27
 
34
28
  # This class holds string values, both, UTF-8 and UTF-16BE
@@ -38,12 +32,12 @@ module CFPropertyList
38
32
  def to_xml
39
33
  n = LibXML::XML::Node.new('string')
40
34
  n << LibXML::XML::Node.new_text(@value) unless @value.nil?
41
- return n
35
+ n
42
36
  end
43
37
 
44
38
  # convert to binary
45
39
  def to_binary(bplist)
46
- return bplist.string_to_binary(@value);
40
+ bplist.string_to_binary(@value);
47
41
  end
48
42
  end
49
43
 
@@ -56,7 +50,7 @@ module CFPropertyList
56
50
 
57
51
  # convert to binary
58
52
  def to_binary(bplist)
59
- return bplist.num_to_binary(self)
53
+ bplist.num_to_binary(self)
60
54
  end
61
55
  end
62
56
 
@@ -69,7 +63,7 @@ module CFPropertyList
69
63
 
70
64
  # convert to binary
71
65
  def to_binary(bplist)
72
- return bplist.num_to_binary(self)
66
+ bplist.num_to_binary(self)
73
67
  end
74
68
  end
75
69
 
@@ -100,6 +94,10 @@ module CFPropertyList
100
94
  def initialize(value = nil,format=CFDate::TIMESTAMP_UNIX)
101
95
  if(value.is_a?(Time) || value.nil?) then
102
96
  @value = value.nil? ? Time.now : value
97
+ elsif value.instance_of? Date
98
+ @value = Time.utc(value.year, value.month, value.day, 0, 0, 0)
99
+ elsif value.instance_of? DateTime
100
+ @value = value.to_time.utc
103
101
  else
104
102
  set_value(value,format)
105
103
  end
@@ -117,20 +115,20 @@ module CFPropertyList
117
115
  # get timestamp, either UNIX or Apple timestamp
118
116
  def get_value(format=CFDate::TIMESTAMP_UNIX)
119
117
  if(format == CFDate::TIMESTAMP_UNIX) then
120
- return @value.to_i
118
+ @value.to_i
121
119
  else
122
- return @value.to_f - CFDate::DATE_DIFF_APPLE_UNIX
120
+ @value.to_f - CFDate::DATE_DIFF_APPLE_UNIX
123
121
  end
124
122
  end
125
123
 
126
124
  # convert to XML
127
125
  def to_xml
128
- return LibXML::XML::Node.new('date') << LibXML::XML::Node.new_text(CFDate::date_string(@value))
126
+ LibXML::XML::Node.new('date') << LibXML::XML::Node.new_text(CFDate::date_string(@value))
129
127
  end
130
128
 
131
129
  # convert to binary
132
130
  def to_binary(bplist)
133
- return bplist.date_to_binary(@value)
131
+ bplist.date_to_binary(@value)
134
132
  end
135
133
  end
136
134
 
@@ -138,12 +136,12 @@ module CFPropertyList
138
136
  class CFBoolean < CFType
139
137
  # convert to XML
140
138
  def to_xml
141
- return LibXML::XML::Node.new(@value ? 'true' : 'false')
139
+ LibXML::XML::Node.new(@value ? 'true' : 'false')
142
140
  end
143
141
 
144
142
  # convert to binary
145
143
  def to_binary(bplist)
146
- return bplist.bool_to_binary(@value);
144
+ bplist.bool_to_binary(@value);
147
145
  end
148
146
  end
149
147
 
@@ -156,7 +154,7 @@ module CFPropertyList
156
154
 
157
155
  # set value to defined state, either base64 encoded or raw
158
156
  def initialize(value=nil,format=DATA_BASE64)
159
- if(format == DATA_RAW) then
157
+ if(format == DATA_RAW)
160
158
  @raw_value = value
161
159
  @raw_value.blob = true
162
160
  else
@@ -178,12 +176,12 @@ module CFPropertyList
178
176
 
179
177
  # convert to XML
180
178
  def to_xml
181
- return LibXML::XML::Node.new('data') << LibXML::XML::Node.new_text(encoded_value())
179
+ LibXML::XML::Node.new('data') << LibXML::XML::Node.new_text(encoded_value())
182
180
  end
183
181
 
184
182
  # convert to binary
185
183
  def to_binary(bplist)
186
- return bplist.data_to_binary(decoded_value())
184
+ bplist.data_to_binary(decoded_value())
187
185
  end
188
186
  end
189
187
 
@@ -197,20 +195,26 @@ module CFPropertyList
197
195
  # convert to XML
198
196
  def to_xml
199
197
  n = LibXML::XML::Node.new('array')
200
- @value.each do
201
- |v|
198
+ @value.each do |v|
202
199
  n << v.to_xml
203
200
  end
204
-
205
- return n
201
+ n
206
202
  end
207
203
 
208
204
  # convert to binary
209
205
  def to_binary(bplist)
210
- return bplist.array_to_binary(self)
206
+ bplist.array_to_binary(self)
211
207
  end
212
208
  end
213
209
 
210
+ =begin
211
+ class CFEnumerator < CFArray
212
+ def to_binary(bplist)
213
+ bplist.enum_to_binary(self)
214
+ end
215
+ end
216
+ =end
217
+
214
218
  # this class contains a hash of values
215
219
  class CFDictionary < CFType
216
220
  # Create new CFDictonary type.
@@ -221,19 +225,17 @@ module CFPropertyList
221
225
  # convert to XML
222
226
  def to_xml
223
227
  n = LibXML::XML::Node.new('dict')
224
- @value.each_pair do
225
- |key,value|
228
+ @value.each_pair do |key,value|
226
229
  k = LibXML::XML::Node.new('key') << LibXML::XML::Node.new_text(key)
227
230
  n << k
228
231
  n << value.to_xml
229
232
  end
230
-
231
- return n
233
+ n
232
234
  end
233
235
 
234
236
  # convert to binary
235
237
  def to_binary(bplist)
236
- return bplist.dict_to_binary(self)
238
+ bplist.dict_to_binary(self)
237
239
  end
238
240
  end
239
241
  end
@@ -33,8 +33,7 @@ module CFPropertyList
33
33
  str = doc.to_s(:indent => opts[:formatted])
34
34
  str1 = String.new
35
35
  first = false
36
- str.each_line do
37
- |line|
36
+ str.each_line do |line|
38
37
  str1 << line
39
38
  unless(first) then
40
39
  str1 << "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" if line =~ /^\s*<\?xml/
@@ -56,7 +55,7 @@ module CFPropertyList
56
55
  else
57
56
  n.content
58
57
  end
59
-
58
+
60
59
  content.force_encoding('UTF-8') if content.respond_to?(:force_encoding)
61
60
  content
62
61
  end
@@ -71,8 +70,7 @@ module CFPropertyList
71
70
  key = nil
72
71
 
73
72
  if node.children? then
74
- node.children.each do
75
- |n|
73
+ node.children.each do |n|
76
74
  next if n.text? # avoid a bug of libxml
77
75
 
78
76
  if n.name == "key" then
@@ -91,8 +89,7 @@ module CFPropertyList
91
89
  ary = Array.new
92
90
 
93
91
  if node.children? then
94
- node.children.each do
95
- |n|
92
+ node.children.each do |n|
96
93
  ary.push import_xml(n)
97
94
  end
98
95
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 2
7
7
  - 0
8
- - 16
9
- version: 2.0.16
8
+ - 17
9
+ version: 2.0.17
10
10
  platform: ruby
11
11
  authors:
12
12
  - Christian Kruse
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-03-21 00:00:00 +01:00
17
+ date: 2011-07-02 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -57,11 +57,11 @@ extra_rdoc_files:
57
57
  - README
58
58
  files:
59
59
  - lib/cfpropertylist.rb
60
+ - lib/rbCFTypes.rb
61
+ - lib/rbXMLCFPropertyList.rb
60
62
  - lib/rbBinaryCFPropertyList.rb
61
63
  - lib/rbCFPlistError.rb
62
64
  - lib/rbCFPropertyList.rb
63
- - lib/rbCFTypes.rb
64
- - lib/rbXMLCFPropertyList.rb
65
65
  - README
66
66
  has_rdoc: true
67
67
  homepage: http://github.com/ckruse/CFPropertyList