CFPropertyList 2.0.16 → 2.0.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -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