rubycf 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +20 -0
- data/extconf.rb +10 -0
- data/lib/cfarray.c +32 -0
- data/lib/cfarray.h +5 -0
- data/lib/cfdata.c +19 -0
- data/lib/cfdata.h +5 -0
- data/lib/cfdate.c +18 -0
- data/lib/cfdate.h +5 -0
- data/lib/cfdictionary.c +49 -0
- data/lib/cfdictionary.h +5 -0
- data/lib/cfnumber.c +55 -0
- data/lib/cfnumber.h +8 -0
- data/lib/cfstring.c +30 -0
- data/lib/cfstring.h +5 -0
- data/lib/plist.c +180 -0
- data/lib/plist.h +12 -0
- data/lib/rubycf.c +27 -0
- data/lib/rubycf_extensions.rb +59 -0
- metadata +71 -0
data/README
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Ruby extension for dealing with CoreFoundation types. Mostly designed for marshaling structures through binary plists.
|
2
|
+
|
3
|
+
See tests for usage.
|
4
|
+
|
5
|
+
To get this to work outside of the OS X, you need to compile lib/CoreFoundation and link against it when building the gem. This isn't build into extconf.rb yet, but it will need to be in the future.
|
6
|
+
|
7
|
+
About CFData:
|
8
|
+
Since Ruby doesn't treat strings any differently from raw data and CoreFoundation does, there needed to be a way to specify if a string is a string or if it's just data. For this purpose, I've created the class RubyCF::Data, which is just a container for a ruby string. When a RubyCF::Data object is passed into the plist encoder, it will encode the data as CFData. Likewise, when a CFData object is encountered while decoding a plist, a RubyCF::Data object will be created.
|
9
|
+
|
10
|
+
TODO
|
11
|
+
--------------
|
12
|
+
- rubyland convenience methods
|
13
|
+
|
14
|
+
|
15
|
+
==========
|
16
|
+
notes:
|
17
|
+
|
18
|
+
Building CFLite:
|
19
|
+
http://cafeine.crulrg.ulaval.ca/users/dccote/weblog/0514e/CoreFoundation_Lite_on_Linux.html
|
20
|
+
http://developer.apple.com/opensource/cflite.html
|
data/extconf.rb
ADDED
data/lib/cfarray.c
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#import "cfarray.h"
|
2
|
+
#import "plist.h"
|
3
|
+
|
4
|
+
VALUE rbcf_array_convert_to_ruby(CFArrayRef array_ref) {
|
5
|
+
|
6
|
+
CFIndex count = CFArrayGetCount(array_ref);
|
7
|
+
CFIndex i = 0;
|
8
|
+
|
9
|
+
VALUE array = rb_ary_new();
|
10
|
+
|
11
|
+
for(i=0; i < count; ++i){
|
12
|
+
rb_ary_push(array, rbcf_plist_convert_to_ruby(CFArrayGetValueAtIndex(array_ref, i)));
|
13
|
+
}
|
14
|
+
|
15
|
+
OBJ_TAINT(array);
|
16
|
+
|
17
|
+
return array;
|
18
|
+
}
|
19
|
+
|
20
|
+
CFArrayRef rbcf_array_convert_to_cf(VALUE array) {
|
21
|
+
CFIndex size = FIX2INT(rb_funcall(array, rb_intern("size"), 0));
|
22
|
+
CFIndex i;
|
23
|
+
CFTypeRef *values = (CFTypeRef *)malloc(size * sizeof(CFTypeRef));
|
24
|
+
for(i = 0; i < size; ++i){
|
25
|
+
values[i] = rbcf_plist_convert_to_cf(rb_ary_entry(array, i));
|
26
|
+
}
|
27
|
+
|
28
|
+
CFArrayRef newArray = CFArrayCreate(kCFAllocatorDefault, values, size, &kCFTypeArrayCallBacks);
|
29
|
+
rbcf_register_for_release(newArray);
|
30
|
+
|
31
|
+
return newArray;
|
32
|
+
}
|
data/lib/cfarray.h
ADDED
data/lib/cfdata.c
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#include "cfdata.h"
|
2
|
+
#include "plist.h"
|
3
|
+
|
4
|
+
VALUE rbcf_data_convert_to_ruby(CFDataRef data_ref) {
|
5
|
+
VALUE rubydata = rb_eval_string("RubyCF::Data.new('')");
|
6
|
+
rb_funcall(rubydata, rb_intern("data="), 1, rb_str_new((char *)CFDataGetBytePtr(data_ref), CFDataGetLength(data_ref)));
|
7
|
+
OBJ_TAINT(rubydata);
|
8
|
+
return rubydata;
|
9
|
+
}
|
10
|
+
|
11
|
+
|
12
|
+
CFDataRef rbcf_data_convert_to_cf(VALUE data_obj) {
|
13
|
+
VALUE data_str = rb_iv_get(data_obj, "@data");
|
14
|
+
|
15
|
+
CFDataRef outData = CFDataCreate(kCFAllocatorDefault, (UInt8 *)RSTRING(data_str)->ptr, RSTRING(data_str)->len);
|
16
|
+
rbcf_register_for_release(outData);
|
17
|
+
|
18
|
+
return outData;
|
19
|
+
}
|
data/lib/cfdata.h
ADDED
data/lib/cfdate.c
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#import "cfdate.h"
|
2
|
+
|
3
|
+
VALUE rbcf_date_convert_to_ruby(CFDateRef date_ref) {
|
4
|
+
//fixme: this isn't 100% accurate, but should be close enough
|
5
|
+
CFDateRef currentTime = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
|
6
|
+
CFTimeInterval difference = CFDateGetTimeIntervalSinceDate(date_ref, currentTime);
|
7
|
+
|
8
|
+
return rb_funcall(rb_funcall(rb_cTime, rb_intern("now"), 0), rb_intern("+"), 1, rb_float_new(difference));
|
9
|
+
}
|
10
|
+
|
11
|
+
CFDateRef rbcf_date_convert_to_cf(VALUE time) {
|
12
|
+
VALUE reference_date = rb_eval_string("Time.gm(2001, 'jan', 1)");
|
13
|
+
CFTimeInterval difference = NUM2DBL(rb_funcall(time, rb_intern("-"), 1, reference_date));
|
14
|
+
CFDateRef date = CFDateCreate(kCFAllocatorDefault, difference);
|
15
|
+
rbcf_register_for_release(date);
|
16
|
+
|
17
|
+
return date;
|
18
|
+
}
|
data/lib/cfdate.h
ADDED
data/lib/cfdictionary.c
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#import "cfdictionary.h"
|
2
|
+
#import "plist.h"
|
3
|
+
#import "cfstring.h"
|
4
|
+
|
5
|
+
VALUE rbcf_dict_convert_to_ruby(CFDictionaryRef dict_ref) {
|
6
|
+
|
7
|
+
CFIndex count = CFDictionaryGetCount(dict_ref);
|
8
|
+
CFIndex i;
|
9
|
+
|
10
|
+
CFTypeRef *keys = (CFTypeRef *)malloc(count * sizeof(CFTypeRef));
|
11
|
+
CFTypeRef *values = (CFTypeRef *)malloc(count * sizeof(CFTypeRef));
|
12
|
+
CFDictionaryGetKeysAndValues(dict_ref, (const void **)keys, (const void **)values);
|
13
|
+
|
14
|
+
VALUE hash = rb_hash_new();
|
15
|
+
|
16
|
+
for(i=0; i < count; ++i){
|
17
|
+
rb_hash_aset(hash, rbcf_string_convert_to_ruby(keys[i]), rbcf_plist_convert_to_ruby(values[i]));
|
18
|
+
}
|
19
|
+
|
20
|
+
free(keys);
|
21
|
+
free(values);
|
22
|
+
|
23
|
+
OBJ_TAINT(hash);
|
24
|
+
|
25
|
+
return hash;
|
26
|
+
}
|
27
|
+
|
28
|
+
CFDictionaryRef rbcf_dict_convert_to_cf(VALUE hash) {
|
29
|
+
|
30
|
+
VALUE flat_hash = rb_funcall(hash, rb_intern("to_a"), 0);
|
31
|
+
CFIndex size = FIX2INT(rb_funcall(hash, rb_intern("size"), 0));
|
32
|
+
CFTypeRef *keys = (CFTypeRef *)malloc(size * sizeof(CFTypeRef));
|
33
|
+
CFTypeRef *values = (CFTypeRef *)malloc(size * sizeof(CFTypeRef));
|
34
|
+
|
35
|
+
CFIndex i;
|
36
|
+
for(i = 0; i < size; ++i){
|
37
|
+
// Ruby Hash keys can be any object. Convert keys into strings before using as CFDictionary keys.
|
38
|
+
keys[i] = rbcf_plist_convert_to_cf(rb_funcall(rb_ary_entry(rb_ary_entry(flat_hash, i), 0), rb_intern("to_s"), 0));
|
39
|
+
values[i] = rbcf_plist_convert_to_cf(rb_ary_entry(rb_ary_entry(flat_hash, i), 1));
|
40
|
+
}
|
41
|
+
|
42
|
+
CFDictionaryRef dictionary = CFDictionaryCreate(kCFAllocatorDefault, keys, values, size, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
43
|
+
rbcf_register_for_release(dictionary);
|
44
|
+
|
45
|
+
free(keys);
|
46
|
+
free(values);
|
47
|
+
|
48
|
+
return dictionary;
|
49
|
+
}
|
data/lib/cfdictionary.h
ADDED
data/lib/cfnumber.c
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#include "cfnumber.h"
|
2
|
+
|
3
|
+
VALUE rbcf_boolean_convert_to_ruby(CFBooleanRef bool_ref) {
|
4
|
+
if(bool_ref == kCFBooleanTrue){
|
5
|
+
return Qtrue;
|
6
|
+
}
|
7
|
+
else {
|
8
|
+
return Qfalse;
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
VALUE rbcf_number_convert_to_ruby(CFNumberRef number_ref) {
|
13
|
+
if(CFNumberIsFloatType(number_ref)){
|
14
|
+
double value = 0.0;
|
15
|
+
if(CFNumberGetValue(number_ref, kCFNumberDoubleType, &value)){
|
16
|
+
return rb_float_new(value);
|
17
|
+
}
|
18
|
+
}
|
19
|
+
else{
|
20
|
+
long value = 0;
|
21
|
+
if(CFNumberGetValue(number_ref, kCFNumberLongType, &value)){
|
22
|
+
return INT2NUM(value);
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
return Qnil;
|
27
|
+
}
|
28
|
+
|
29
|
+
CFBooleanRef rbcf_boolean_convert_to_cf(VALUE boolean) {
|
30
|
+
if(boolean == Qtrue){
|
31
|
+
return kCFBooleanTrue;
|
32
|
+
}
|
33
|
+
else {
|
34
|
+
return kCFBooleanFalse;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
CFNumberRef rbcf_number_convert_to_cf(VALUE number) {
|
39
|
+
if(rb_obj_is_kind_of(number, rb_cInteger) == Qtrue){
|
40
|
+
long value = NUM2LONG(number);
|
41
|
+
CFNumberRef outnum = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &value);
|
42
|
+
rbcf_register_for_release(outnum);
|
43
|
+
return outnum;
|
44
|
+
}
|
45
|
+
else if(rb_obj_is_kind_of(number, rb_cFloat) == Qtrue) {
|
46
|
+
double value = NUM2DBL(number);
|
47
|
+
CFNumberRef outnum = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value);
|
48
|
+
rbcf_register_for_release(outnum);
|
49
|
+
return outnum;
|
50
|
+
}
|
51
|
+
else {
|
52
|
+
return NULL;
|
53
|
+
}
|
54
|
+
|
55
|
+
}
|
data/lib/cfnumber.h
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <CoreFoundation/CFNumber.h>
|
3
|
+
|
4
|
+
VALUE rbcf_boolean_convert_to_ruby(CFBooleanRef bool_ref);
|
5
|
+
VALUE rbcf_number_convert_to_ruby(CFNumberRef number_ref);
|
6
|
+
|
7
|
+
CFBooleanRef rbcf_boolean_convert_to_cf(VALUE boolean);
|
8
|
+
CFNumberRef rbcf_number_convert_to_cf(VALUE number);
|
data/lib/cfstring.c
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#include "cfstring.h"
|
2
|
+
|
3
|
+
VALUE rbcf_string_convert_to_ruby(CFStringRef string_ref) {
|
4
|
+
|
5
|
+
char *buffer;
|
6
|
+
CFIndex bufferSize = CFStringGetLength(string_ref) + 1;
|
7
|
+
VALUE rubystring;
|
8
|
+
|
9
|
+
buffer = malloc(bufferSize + 1);
|
10
|
+
|
11
|
+
if(CFStringGetCString(string_ref, buffer, bufferSize, kCFStringEncodingASCII)){
|
12
|
+
rubystring = rb_str_new2(buffer);
|
13
|
+
OBJ_TAINT(rubystring);
|
14
|
+
}
|
15
|
+
else{
|
16
|
+
rubystring = Qnil;
|
17
|
+
}
|
18
|
+
|
19
|
+
free(buffer);
|
20
|
+
return rubystring;
|
21
|
+
}
|
22
|
+
|
23
|
+
CFStringRef rbcf_string_convert_to_cf(VALUE string) {
|
24
|
+
|
25
|
+
CFIndex num_bytes;
|
26
|
+
char *bytes = rb_str2cstr(string, &num_bytes);
|
27
|
+
CFStringRef cfstring = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)bytes, num_bytes, kCFStringEncodingASCII, false);
|
28
|
+
rbcf_register_for_release(cfstring);
|
29
|
+
return cfstring;
|
30
|
+
}
|
data/lib/cfstring.h
ADDED
data/lib/plist.c
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
#include "plist.h"
|
2
|
+
|
3
|
+
#include <CoreFoundation/CFBase.h>
|
4
|
+
#include <CoreFoundation/CFString.h>
|
5
|
+
#include <CoreFoundation/CFNumber.h>
|
6
|
+
#include <CoreFoundation/CFStream.h>
|
7
|
+
#include <CoreFoundation/CFDictionary.h>
|
8
|
+
#include <CoreFoundation/CFArray.h>
|
9
|
+
|
10
|
+
#include "cfstring.h"
|
11
|
+
#include "cfnumber.h"
|
12
|
+
#include "cfdate.h"
|
13
|
+
#include "cfdictionary.h"
|
14
|
+
#include "cfarray.h"
|
15
|
+
#include "cfdata.h"
|
16
|
+
|
17
|
+
void rbcf_reset_release_pool();
|
18
|
+
static CFMutableArrayRef rbcf_plist_generation_release_pool;
|
19
|
+
|
20
|
+
static const void *rbcf_retain(CFAllocatorRef ref, const void *obj){
|
21
|
+
CFRetain(obj);
|
22
|
+
}
|
23
|
+
|
24
|
+
static void rbcf_release(CFAllocatorRef ref, const void *obj){
|
25
|
+
CFRelease(obj);
|
26
|
+
}
|
27
|
+
|
28
|
+
static const CFArrayCallBacks poolarraycallbacks = {
|
29
|
+
0,
|
30
|
+
rbcf_retain,
|
31
|
+
rbcf_release,
|
32
|
+
NULL,
|
33
|
+
NULL
|
34
|
+
};
|
35
|
+
|
36
|
+
void rbcf_register_for_release(CFTypeRef obj) {
|
37
|
+
if(!rbcf_plist_generation_release_pool){
|
38
|
+
rbcf_plist_generation_release_pool = CFArrayCreateMutable(kCFAllocatorDefault, 0, &poolarraycallbacks);
|
39
|
+
}
|
40
|
+
CFArrayAppendValue(rbcf_plist_generation_release_pool, obj);
|
41
|
+
CFRelease(obj);
|
42
|
+
}
|
43
|
+
|
44
|
+
void rbcf_reset_release_pool() {
|
45
|
+
if(rbcf_plist_generation_release_pool){
|
46
|
+
CFRelease(rbcf_plist_generation_release_pool);
|
47
|
+
rbcf_plist_generation_release_pool = NULL;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
VALUE rbcf_plist_convert_to_ruby(CFPropertyListRef plist) {
|
52
|
+
CFTypeID plist_type_id = CFGetTypeID(plist);
|
53
|
+
|
54
|
+
if(plist_type_id == CFStringGetTypeID()){
|
55
|
+
return rbcf_string_convert_to_ruby(plist);
|
56
|
+
}
|
57
|
+
else if(plist_type_id == CFBooleanGetTypeID()){
|
58
|
+
return rbcf_boolean_convert_to_ruby(plist);
|
59
|
+
}
|
60
|
+
else if(plist_type_id == CFNumberGetTypeID()){
|
61
|
+
return rbcf_number_convert_to_ruby(plist);
|
62
|
+
}
|
63
|
+
else if(plist_type_id == CFDateGetTypeID()){
|
64
|
+
return rbcf_date_convert_to_ruby(plist);
|
65
|
+
}
|
66
|
+
else if(plist_type_id == CFDataGetTypeID()){
|
67
|
+
return rbcf_data_convert_to_ruby(plist);
|
68
|
+
}
|
69
|
+
else if(plist_type_id == CFDictionaryGetTypeID()){
|
70
|
+
return rbcf_dict_convert_to_ruby(plist);
|
71
|
+
}
|
72
|
+
else if(plist_type_id == CFArrayGetTypeID()){
|
73
|
+
return rbcf_array_convert_to_ruby(plist);
|
74
|
+
}
|
75
|
+
else{
|
76
|
+
return Qnil;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
CFPropertyListRef rbcf_plist_convert_to_cf(VALUE structure) {
|
81
|
+
VALUE out;
|
82
|
+
|
83
|
+
if(rb_obj_is_kind_of(structure, rb_cString) == Qtrue){
|
84
|
+
return rbcf_string_convert_to_cf(structure);
|
85
|
+
}
|
86
|
+
else if(structure == Qtrue || structure == Qfalse){
|
87
|
+
return rbcf_boolean_convert_to_cf(structure);
|
88
|
+
}
|
89
|
+
else if(rb_obj_is_kind_of(structure, rb_cNumeric) == Qtrue){
|
90
|
+
return rbcf_number_convert_to_cf(structure);
|
91
|
+
}
|
92
|
+
else if(rb_obj_is_kind_of(structure, rb_cTime) == Qtrue){
|
93
|
+
return rbcf_date_convert_to_cf(structure);
|
94
|
+
}
|
95
|
+
else if(rb_obj_is_kind_of(structure, rb_eval_string("RubyCF::Data")) == Qtrue){
|
96
|
+
return rbcf_data_convert_to_cf(structure);
|
97
|
+
}
|
98
|
+
else if(rb_obj_is_kind_of(structure, rb_cArray) == Qtrue){
|
99
|
+
return rbcf_array_convert_to_cf(structure);
|
100
|
+
}
|
101
|
+
else if(rb_obj_is_kind_of(structure, rb_cHash) == Qtrue){
|
102
|
+
return rbcf_dict_convert_to_cf(structure);
|
103
|
+
}
|
104
|
+
else if(rb_respond_to(structure, rb_intern("to_hash"))){
|
105
|
+
return rbcf_dict_convert_to_cf(rb_funcall(structure, rb_intern("to_hash"), 0));
|
106
|
+
}
|
107
|
+
// default (depricated) behavior of to_a is to return [self], which is not helpful
|
108
|
+
else if(rb_respond_to(structure, rb_intern("to_a")) &&
|
109
|
+
rb_funcall(out = rb_funcall(structure, rb_intern("to_a"), 0), rb_intern("=="), 1, rb_ary_new3(1, structure)) == Qfalse
|
110
|
+
){
|
111
|
+
return rbcf_array_convert_to_cf(out);
|
112
|
+
}
|
113
|
+
else if(rb_respond_to(structure, rb_intern("to_f"))){
|
114
|
+
return rbcf_number_convert_to_cf(rb_funcall(structure, rb_intern("to_f"), 0));
|
115
|
+
}
|
116
|
+
else if(rb_respond_to(structure, rb_intern("to_int"))){
|
117
|
+
return rbcf_number_convert_to_cf(rb_funcall(structure, rb_intern("to_i"), 0));
|
118
|
+
}
|
119
|
+
else if(rb_respond_to(structure, rb_intern("to_str"))){
|
120
|
+
return rbcf_string_convert_to_cf(rb_funcall(structure, rb_intern("to_s"), 0));
|
121
|
+
}
|
122
|
+
else {
|
123
|
+
return NULL;
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
|
128
|
+
VALUE rbcf_plist_parse(VALUE self, VALUE data) {
|
129
|
+
CFPropertyListFormat format; // the format of the plist
|
130
|
+
CFStringRef errorString; // Parsing error string
|
131
|
+
|
132
|
+
if(rb_obj_is_kind_of(data, rb_cString) == Qtrue){
|
133
|
+
CFReadStreamRef stream = CFReadStreamCreateWithBytesNoCopy(NULL, (UInt8 *)RSTRING(data)->ptr, RSTRING(data)->len, kCFAllocatorNull);
|
134
|
+
|
135
|
+
if(CFReadStreamOpen(stream)){
|
136
|
+
CFPropertyListRef plist = CFPropertyListCreateFromStream(NULL, stream, 0, kCFPropertyListImmutable, &format, &errorString);
|
137
|
+
CFReadStreamClose(stream);
|
138
|
+
CFRelease(stream);
|
139
|
+
if(plist){
|
140
|
+
VALUE plist_value = rbcf_plist_convert_to_ruby(plist);
|
141
|
+
CFRelease(plist);
|
142
|
+
rbcf_reset_release_pool();
|
143
|
+
return plist_value;
|
144
|
+
}
|
145
|
+
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
rbcf_reset_release_pool();
|
150
|
+
return Qnil;
|
151
|
+
}
|
152
|
+
|
153
|
+
|
154
|
+
VALUE rbcf_plist_encode(int argc, VALUE *argv, VALUE self) {
|
155
|
+
VALUE structure, encoding;
|
156
|
+
rb_scan_args(argc, argv, "11", &structure, &encoding);
|
157
|
+
|
158
|
+
CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0; // the format of the plist
|
159
|
+
CFStringRef errorString; // Parsing error string
|
160
|
+
|
161
|
+
CFPropertyListRef cf_structure = rbcf_plist_convert_to_cf(structure);
|
162
|
+
CFWriteStreamRef stream = CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault, kCFAllocatorDefault);
|
163
|
+
if(CFWriteStreamOpen(stream)){
|
164
|
+
CFIndex num_bytes = CFPropertyListWriteToStream(cf_structure, stream, format, &errorString);
|
165
|
+
if(num_bytes > 0){
|
166
|
+
CFTypeRef data = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten);
|
167
|
+
rbcf_register_for_release(data);
|
168
|
+
CFRelease(stream);
|
169
|
+
if(data && CFGetTypeID(data) == CFDataGetTypeID()){
|
170
|
+
VALUE out_string = rb_str_new((char *)CFDataGetBytePtr(data), CFDataGetLength(data));
|
171
|
+
rbcf_reset_release_pool();
|
172
|
+
return out_string;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
176
|
+
|
177
|
+
rbcf_reset_release_pool();
|
178
|
+
return Qnil;
|
179
|
+
}
|
180
|
+
|
data/lib/plist.h
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <CoreFoundation/CFPropertyList.h>
|
3
|
+
|
4
|
+
RUBY_EXTERN VALUE rb_cCFData;
|
5
|
+
|
6
|
+
VALUE rbcf_plist_parse(VALUE self, VALUE data);
|
7
|
+
VALUE rbcf_plist_encode(int argc, VALUE *argv, VALUE self);
|
8
|
+
|
9
|
+
VALUE rbcf_plist_convert_to_ruby(CFPropertyListRef plist);
|
10
|
+
CFPropertyListRef rbcf_plist_convert_to_cf(VALUE structure);
|
11
|
+
|
12
|
+
void rbcf_register_for_release(CFTypeRef obj);
|
data/lib/rubycf.c
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
/*
|
2
|
+
* rubycf.c
|
3
|
+
* rubycf
|
4
|
+
*
|
5
|
+
* Created by Dave Grijalva on 12/22/08.
|
6
|
+
* Copyright 2008 __MyCompanyName__. All rights reserved.
|
7
|
+
*
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include <ruby.h>
|
11
|
+
#include <CoreFoundation/CoreFoundation.h>
|
12
|
+
#include "plist.h"
|
13
|
+
|
14
|
+
static VALUE rb_mRubyCF;
|
15
|
+
static VALUE rb_cPlist;
|
16
|
+
|
17
|
+
void Init_rubycf (void)
|
18
|
+
{
|
19
|
+
// Add the initialization code of your module here.
|
20
|
+
rb_mRubyCF = rb_define_module("RubyCF");
|
21
|
+
|
22
|
+
rb_cPlist = rb_define_class_under(rb_mRubyCF, "PList", rb_cObject);
|
23
|
+
rb_define_module_function(rb_cPlist, "parse", rbcf_plist_parse, 1);
|
24
|
+
rb_define_module_function(rb_cPlist, "encode", rbcf_plist_encode, -1);
|
25
|
+
|
26
|
+
rb_require("rubycf_extensions.rb");
|
27
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Extensions to the build in C functions
|
2
|
+
|
3
|
+
module RubyCF
|
4
|
+
class PList
|
5
|
+
class << self
|
6
|
+
alias decode parse
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.parse_file file
|
10
|
+
self.parse(file.is_a?(File) ? file.read : File.read(file))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# CF handles raw data different from strings. Ruby treats them the same.
|
15
|
+
# use RubyCF::Data objects to tell the plist encoder to treat the objects
|
16
|
+
# as data.
|
17
|
+
class Data
|
18
|
+
attr_reader :data
|
19
|
+
|
20
|
+
def self.from_file file
|
21
|
+
Data.new(file.is_a?(File) ? file.read : File.read(file))
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize string
|
25
|
+
self.data = string
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
"RubyCF::Data #{@data.size} bytes"
|
30
|
+
end
|
31
|
+
|
32
|
+
def == other
|
33
|
+
if(other.is_a?(RubyCF::Data))
|
34
|
+
return other.data == @data
|
35
|
+
else
|
36
|
+
return other == @data
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def data= string
|
41
|
+
@data = string.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Object
|
48
|
+
def to_plist
|
49
|
+
# supported types
|
50
|
+
# [Integer, Float, String, Array, Hash, RubyCF::Data].each do |klass|
|
51
|
+
return RubyCF::PList.encode(self) #if self.is_a? klass
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# if self.resond_to? :to_hash
|
55
|
+
# elsif self.resond_to? :to_a
|
56
|
+
# elsif self.resond_to?
|
57
|
+
#
|
58
|
+
end
|
59
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubycf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dave Grijalva
|
8
|
+
autorequire: rubycf
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-02 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: dgrijalva@ngmoco.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions:
|
21
|
+
- extconf.rb
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- lib/cfarray.c
|
26
|
+
- lib/cfarray.h
|
27
|
+
- lib/cfdata.c
|
28
|
+
- lib/cfdata.h
|
29
|
+
- lib/cfdate.c
|
30
|
+
- lib/cfdate.h
|
31
|
+
- lib/cfdictionary.c
|
32
|
+
- lib/cfdictionary.h
|
33
|
+
- lib/cfnumber.c
|
34
|
+
- lib/cfnumber.h
|
35
|
+
- lib/cfstring.c
|
36
|
+
- lib/cfstring.h
|
37
|
+
- lib/plist.c
|
38
|
+
- lib/plist.h
|
39
|
+
- lib/rubycf.c
|
40
|
+
- lib/rubycf_extensions.rb
|
41
|
+
- README
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://ngmoco.com/
|
44
|
+
licenses: []
|
45
|
+
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.3.5
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: Bindings for Apple Core Foundation
|
70
|
+
test_files: []
|
71
|
+
|