binary_plist 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ 0.0.1 (Jul 23, 2010)
2
+
3
+ * Initial release
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Sam Soffes
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Readme.markdown ADDED
@@ -0,0 +1,55 @@
1
+ # BinaryPlist
2
+
3
+ Rails plugin for easily adding a binary plist format. The binary plist format is ideal for transferring data to an Objective-C based application.
4
+
5
+ ## Installation
6
+
7
+ Add the following line to your bundle and run `bundle install`.
8
+
9
+ gem "binary_plist"
10
+
11
+ ## Usage
12
+
13
+ All you have to do is add the `bplist` format to your `respond_to` block:
14
+
15
+ def index
16
+ @posts = Post.all
17
+ respond_to do |format|
18
+ format.html
19
+ format.bplist { render :bplist => @posts }
20
+ end
21
+ end
22
+
23
+ You can do the combined style if you're support multiple formats like `json` or `xml`.
24
+
25
+ def index
26
+ @posts = Post.all
27
+ respond_to do |format|
28
+ format.html
29
+ format.any(:json, :bplist) { render request.format.to_sym => @posts }
30
+ end
31
+ end
32
+
33
+ ## Consuming
34
+
35
+ On the Objective-C side, it's ridiculously easy to consume the plist data.
36
+
37
+ NSURL *url = [NSURL URLWithString:@"http://localhost:3000/posts.bplist"];
38
+ NSArray *posts = [NSArray arrayWithContentsOfURL:url];
39
+
40
+ You can also use the more flexible syntax:
41
+
42
+ NSURL *url = [NSURL URLWithString:@"http://localhost:3000/posts.bplist"];
43
+ NSDate *date = [NSData dataWithContentsOfURL:url];
44
+ id result = [NSPropertyListSerialization propertyListFromData:data
45
+ mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:nil];
46
+
47
+ if ([result isKindOfClass:[NSArray class]]) {
48
+ // Handle array response
49
+ } else if ([result isKindOfClass:[NSDictionary class]]) {
50
+ // Handle dictionary response
51
+ } else {
52
+ // Etc...
53
+ }
54
+
55
+ Copyright (c) 2010 Sam Soffes, released under the MIT license
data/init.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "binary_plist"
2
+
3
+ Mime::Type.register BinaryPlist::MIME_TYPE, :bplist
4
+
5
+ ActionController::Renderers.add :bplist do |data, options|
6
+ # TODO: Make this less hacky
7
+ data = ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(data, options))
8
+
9
+ self.content_type ||= Mime::BPLIST
10
+ self.response_body = BinaryPlist::Converter.convert(data)
11
+ end
@@ -0,0 +1,179 @@
1
+ # Based on Apple Binary Property List serializer - http://gist.github.com/303378
2
+ require 'iconv'
3
+
4
+ module BinaryPlist
5
+
6
+ # Very generic type for now
7
+ MIME_TYPE = 'application/octet-stream'
8
+
9
+ module Converter
10
+
11
+ # Difference between Apple and UNIX timestamps
12
+ DATE_EPOCH_OFFSET_APPLE_UNIX = 978307200
13
+
14
+ # Text encoding
15
+ INPUT_TEXT_ENCODING = 'UTF-8'
16
+ PLIST_TEXT_ENCODING = 'UTF-16BE'
17
+
18
+ # For marking strings as binary data which will be decoded as a CFData object
19
+ CFData = Struct.new(:data)
20
+
21
+ # Convert a Ruby data structure into an OS X binary property list file. (.plist)
22
+ # Works as you'd expect. Integers are limited to 4 bytes, even though the format implies longer values can be written.
23
+ # Strings are assumed to be in UTF-8 format. Symbols are written as strings.
24
+ def self.convert(data)
25
+ write("", data)
26
+ end
27
+
28
+ # Alternative interface which writes data to the out object using <<
29
+ def self.write(out, data)
30
+ # Find out how many objects there are, so we know how big the references are
31
+ count = count_objects(data)
32
+ ref_format, ref_size = int_format_and_size(count)
33
+
34
+ # Now serialize all the objects
35
+ values = Array.new
36
+ append_values(data, values, ref_format)
37
+
38
+ # Write header, then the values, calculating offsets as they're written
39
+ out << 'bplist00'
40
+ offset = 8
41
+ offsets = Array.new
42
+ values.each do |v|
43
+ offsets << offset
44
+ out << v
45
+ offset += v.length
46
+ end
47
+
48
+ # How big should the offset ints be?
49
+ # Decoder gets upset if the size can't fit the entire file, even if it's not strictly needed, so add the length of the last value.
50
+ offset_format, offset_size = int_format_and_size(offsets.last + values.last.length)
51
+
52
+ # Write the offsets
53
+ out << offsets.pack(offset_format)
54
+
55
+ # Write trailer
56
+ out << [0,0,offset_size,ref_size, 0,values.length, 0,0, 0,offset].pack("NnCCNNNNNN")
57
+
58
+ out
59
+ end
60
+
61
+ private
62
+
63
+ def self.count_objects(data)
64
+ case data
65
+ when Array
66
+ data.inject(1) { |sum,x| sum + count_objects(x) }
67
+ when Hash
68
+ # Note: Assumes that the keys aren't a Hash or Array
69
+ data.length + count_objects(data.values)
70
+ else
71
+ 1
72
+ end
73
+ end
74
+
75
+ def self.append_values(data, values, ref_format)
76
+ case data
77
+
78
+ # Constant values
79
+ when nil
80
+ # values << "\x00"
81
+ # raise "Can't store a nil in a binary plist. While the format supports it, decoders don't like it."
82
+ append_values("", values, ref_format)
83
+ when false
84
+ values << "\x08"
85
+ when true
86
+ values << "\x09"
87
+
88
+ when Integer
89
+ raise "Integer out of range to write in binary plist" if data < -2147483648 || data > 0x7FFFFFFF
90
+ values << packed_int(data)
91
+
92
+ when Float
93
+ values << "\x23#{[data].pack("d").reverse}"
94
+
95
+ when Symbol
96
+ append_values(data.to_s, values, ref_format)
97
+
98
+ when String
99
+ if data =~ /[\x80-\xff]/
100
+ # Has high bits set, so is UTF-8 and must be reencoded for the plist file
101
+ c = Iconv.iconv(PLIST_TEXT_ENCODING, INPUT_TEXT_ENCODING, data).join
102
+ values << "#{objhdr_with_length(0x60, c.length / 2)}#{c}"
103
+ else
104
+ # Just ASCII
105
+ o = objhdr_with_length(0x50, data.length)
106
+ o << data
107
+ values << o
108
+ end
109
+
110
+ when CFData
111
+ o = objhdr_with_length(0x40, data.data.length)
112
+ o << data.data
113
+ values << o
114
+
115
+ when Time
116
+ v = data.getutc.to_f - DATE_EPOCH_OFFSET_APPLE_UNIX
117
+ values << "\x33#{[v].pack("d").reverse}"
118
+
119
+ when Hash
120
+ o = objhdr_with_length(0xd0, data.length)
121
+ values << o # now, so we get the refs of other objects right
122
+ ks = Array.new
123
+ vs = Array.new
124
+ data.each do |k,v|
125
+ ks << values.length
126
+ append_values(k, values, ref_format)
127
+ vs << values.length
128
+ append_values(v, values, ref_format)
129
+ end
130
+ o << ks.pack(ref_format)
131
+ o << vs.pack(ref_format)
132
+
133
+ when Array
134
+ o = objhdr_with_length(0xa0, data.length)
135
+ values << o # now, so we get the refs of other objects right
136
+ refs = Array.new
137
+ data.each do |e|
138
+ refs << values.length # index in array of object we're about to write
139
+ append_values(e, values, ref_format)
140
+ end
141
+ o << refs.pack(ref_format)
142
+
143
+ else
144
+ raise "Couldn't serialize value of class #{data.class.name}"
145
+ end
146
+ end
147
+
148
+ def self.int_format_and_size(i)
149
+ if i > 0xffff
150
+ ['N*',4]
151
+ elsif i > 0xff
152
+ ['n*',2]
153
+ else
154
+ ['C*',1]
155
+ end
156
+ end
157
+
158
+ def self.packed_int(data)
159
+ if data < 0
160
+ # Need to use 64 bits for negative numbers.
161
+ [0x13,0xffffffff,data].pack("CNN")
162
+ elsif data > 0xffff
163
+ [0x12,data].pack("CN")
164
+ elsif data > 0xff
165
+ [0x11,data].pack("Cn")
166
+ else
167
+ [0x10,data].pack("CC")
168
+ end
169
+ end
170
+
171
+ def self.objhdr_with_length(id, length)
172
+ if length < 0xf
173
+ (id + length).chr
174
+ else
175
+ (id + 0xf).chr + packed_int(length)
176
+ end
177
+ end
178
+ end
179
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: binary_plist
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Sam Soffes
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-23 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activesupport
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 3
32
+ - 0
33
+ version: "3.0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description: Easily add the Apple Binary Plist format to your controllers for transferring data to Objective-C applications.
37
+ email: sam@samsoff.es
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - lib/binary_plist.rb
46
+ - Changelog.markdown
47
+ - LICENSE
48
+ - Readme.markdown
49
+ - init.rb
50
+ has_rdoc: true
51
+ homepage: http://github.com/samsoffes/binary_plist
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ hash: 3
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ requirements: []
78
+
79
+ rubyforge_project:
80
+ rubygems_version: 1.3.7
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Easily add the Apple Binary Plist format to your controllers.
84
+ test_files: []
85
+