binary_plist 0.0.1

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.
@@ -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
+