File: rbCFTypes.rb

package info (click to toggle)
ruby-cfpropertylist 2.2.8-1.1%2Bdeb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 156 kB
  • sloc: ruby: 1,203; makefile: 2
file content (266 lines) | stat: -rw-r--r-- 6,588 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# -*- coding: utf-8 -*-
#
# CFTypes, e.g. CFString, CFInteger
# needed to create unambiguous plists
#
# Author::    Christian Kruse (mailto:cjk@wwwtech.de)
# Copyright:: Copyright (c) 2009
# License::   MIT License

require 'base64'

module CFPropertyList
  ##
  # Blob is intended to distinguish between a Ruby String instance that should
  # be converted to a CFString type and a Ruby String instance that should be
  # converted to a CFData type
  class Blob < String
  end

  ##
  # UidFixnum is intended to distinguish between a Ruby Fixnum
  # instance that should be converted to a CFInteger/CFReal type and a
  # Ruby Fixnum instance that should be converted to a CFUid type.
  class UidFixnum < Fixnum
  end

  # This class defines the base class for all CFType classes
  #
  class CFType
    # value of the type
    attr_accessor :value

    def initialize(value=nil)
      @value = value
    end

    def to_xml(parser)
    end

    def to_binary(bplist) end
  end

  # This class holds string values, both, UTF-8 and UTF-16BE
  # It will convert the value to UTF-16BE if necessary (i.e. if non-ascii char contained)
  class CFString < CFType
    # convert to XML
    def to_xml(parser)
      n = parser.new_node('string')
      n = parser.append_node(n, parser.new_text(@value)) unless @value.nil?
      n
    end

    # convert to binary
    def to_binary(bplist)
      bplist.string_to_binary(@value);
    end
  end

  # This class holds integer/fixnum values
  class CFInteger < CFType
    # convert to XML
    def to_xml(parser)
      n = parser.new_node('integer')
      n = parser.append_node(n, parser.new_text(@value.to_s))
      n
    end

    # convert to binary
    def to_binary(bplist)
      bplist.num_to_binary(self)
    end
  end

  # This class holds float values
  class CFReal < CFType
    # convert to XML
    def to_xml(parser)
      n = parser.new_node('real')
      n = parser.append_node(n, parser.new_text(@value.to_s))
      n
    end

    # convert to binary
    def to_binary(bplist)
      bplist.num_to_binary(self)
    end
  end

  # This class holds Time values. While Apple uses seconds since 2001,
  # the rest of the world uses seconds since 1970. So if you access value
  # directly, you get the Time class. If you access via get_value you either
  # geht the timestamp or the Apple timestamp
  class CFDate < CFType
    TIMESTAMP_APPLE = 0
    TIMESTAMP_UNIX  = 1;
    DATE_DIFF_APPLE_UNIX = 978307200

    # create a XML date strimg from a time object
    def CFDate.date_string(val)
      # 2009-05-13T20:23:43Z
      val.getutc.strftime("%Y-%m-%dT%H:%M:%SZ")
    end

    # parse a XML date string
    def CFDate.parse_date(val)
      # 2009-05-13T20:23:43Z
      val =~ %r{^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$}
      year,month,day,hour,min,sec = $1, $2, $3, $4, $5, $6
      return Time.utc(year,month,day,hour,min,sec).getlocal
    end

    # set value to defined state
    def initialize(value = nil,format=CFDate::TIMESTAMP_UNIX)
      if(value.is_a?(Time) || value.nil?) then
        @value = value.nil? ? Time.now : value
      elsif value.instance_of? Date
        @value = Time.utc(value.year, value.month, value.day, 0, 0, 0)
      elsif value.instance_of? DateTime
        @value = value.to_time.utc
      else
        set_value(value,format)
      end
    end

    # set value with timestamp, either Apple or UNIX
    def set_value(value,format=CFDate::TIMESTAMP_UNIX)
      if(format == CFDate::TIMESTAMP_UNIX) then
        @value = Time.at(value)
      else
        @value = Time.at(value + CFDate::DATE_DIFF_APPLE_UNIX)
      end
    end

    # get timestamp, either UNIX or Apple timestamp
    def get_value(format=CFDate::TIMESTAMP_UNIX)
      if(format == CFDate::TIMESTAMP_UNIX) then
        @value.to_i
      else
        @value.to_f - CFDate::DATE_DIFF_APPLE_UNIX
      end
    end

    # convert to XML
    def to_xml(parser)
      n = parser.new_node('date')
      n = parser.append_node(n, parser.new_text(CFDate::date_string(@value)))
      n
    end

    # convert to binary
    def to_binary(bplist)
      bplist.date_to_binary(@value)
    end
  end

  # This class contains a boolean value
  class CFBoolean < CFType
    # convert to XML
    def to_xml(parser)
      parser.new_node(@value ? 'true' : 'false')
    end

    # convert to binary
    def to_binary(bplist)
      bplist.bool_to_binary(@value);
    end
  end

  # This class contains binary data values
  class CFData < CFType
    # Base64 encoded data
    DATA_BASE64 = 0
    # Raw data
    DATA_RAW = 1

    # set value to defined state, either base64 encoded or raw
    def initialize(value=nil,format=DATA_BASE64)
      if(format == DATA_RAW)
        @raw_value = value
      else
        @value = value
      end
    end

    # get base64 encoded value
    def encoded_value
      @value ||= "\n#{Base64.encode64(@raw_value).gsub("\n", '').scan(/.{1,76}/).join("\n")}\n"
    end

    # get base64 decoded value
    def decoded_value
      @raw_value ||= Blob.new(Base64.decode64(@value))
    end

    # convert to XML
    def to_xml(parser)
      n = parser.new_node('data')
      n = parser.append_node(n, parser.new_text(encoded_value()))
      n
    end

    # convert to binary
    def to_binary(bplist)
      bplist.data_to_binary(decoded_value())
    end
  end

  # This class contains an array of values
  class CFArray < CFType
    # create a new array CFType
    def initialize(val=[])
      @value = val
    end

    # convert to XML
    def to_xml(parser)
      n = parser.new_node('array')
      @value.each do |v|
        n = parser.append_node(n, v.to_xml(parser))
      end
      n
    end

    # convert to binary
    def to_binary(bplist)
      bplist.array_to_binary(self)
    end
  end

  # this class contains a hash of values
  class CFDictionary < CFType
    # Create new CFDictonary type.
    def initialize(value={})
      @value = value
    end

    # convert to XML
    def to_xml(parser)
      n = parser.new_node('dict')
      @value.each_pair do |key, value|
        k = parser.append_node(parser.new_node('key'), parser.new_text(key.to_s))
        n = parser.append_node(n, k)
        n = parser.append_node(n, value.to_xml(parser))
      end
      n
    end

    # convert to binary
    def to_binary(bplist)
      bplist.dict_to_binary(self)
    end
  end

  class CFUid < CFType
    def to_xml(parser)
      CFDictionary.new({'CF$UID' => CFInteger.new(@value)}).to_xml(parser)
    end

    # convert to binary
    def to_binary(bplist)
      bplist.uid_to_binary(@value)
    end
  end
end

# eof