xcodeproj 1.3.3 → 1.4.0
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.
- checksums.yaml +4 -4
- data/lib/xcodeproj/gem_version.rb +1 -1
- data/lib/xcodeproj/plist.rb +25 -27
- data/lib/xcodeproj/project.rb +19 -1
- data/lib/xcodeproj/project/object.rb +25 -3
- data/lib/xcodeproj/project/object/build_configuration.rb +52 -0
- data/lib/xcodeproj/project/object/build_file.rb +4 -0
- data/lib/xcodeproj/project/object/build_phase.rb +8 -0
- data/lib/xcodeproj/project/object/build_rule.rb +4 -0
- data/lib/xcodeproj/project/object/configuration_list.rb +9 -0
- data/lib/xcodeproj/project/object/container_item_proxy.rb +26 -3
- data/lib/xcodeproj/project/object/file_reference.rb +7 -1
- data/lib/xcodeproj/project/object/group.rb +4 -0
- data/lib/xcodeproj/project/object/reference_proxy.rb +4 -0
- data/lib/xcodeproj/project/object/root_object.rb +14 -0
- data/lib/xcodeproj/project/object/target_dependency.rb +4 -0
- data/lib/xcodeproj/project/object_dictionary.rb +5 -1
- metadata +34 -11
- data/lib/xcodeproj/plist/ffi.rb +0 -153
- data/lib/xcodeproj/plist/ffi/chdir_override.rb +0 -27
- data/lib/xcodeproj/plist/ffi/core_foundation.rb +0 -441
- data/lib/xcodeproj/plist/ffi/dev_tools_core.rb +0 -194
- data/lib/xcodeproj/plist/plist_gem.rb +0 -27
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xcodeproj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eloy Duran
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-10-
|
11
|
+
date: 2016-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -25,19 +25,19 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: CFPropertyList
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 2.3.3
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 2.3.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: claide
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,6 +58,34 @@ dependencies:
|
|
58
58
|
- - "<"
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '2.0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: colored
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '1.2'
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '1.2'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: nanaimo
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 0.1.0
|
82
|
+
type: :runtime
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 0.1.0
|
61
89
|
description: Xcodeproj lets you create and modify Xcode projects from Ruby. Script
|
62
90
|
boring management tasks or build Xcode-friendly libraries. Also includes support
|
63
91
|
for Xcode workspaces (.xcworkspace) and configuration files (.xcconfig).
|
@@ -84,11 +112,6 @@ files:
|
|
84
112
|
- lib/xcodeproj/gem_version.rb
|
85
113
|
- lib/xcodeproj/helper.rb
|
86
114
|
- lib/xcodeproj/plist.rb
|
87
|
-
- lib/xcodeproj/plist/ffi.rb
|
88
|
-
- lib/xcodeproj/plist/ffi/chdir_override.rb
|
89
|
-
- lib/xcodeproj/plist/ffi/core_foundation.rb
|
90
|
-
- lib/xcodeproj/plist/ffi/dev_tools_core.rb
|
91
|
-
- lib/xcodeproj/plist/plist_gem.rb
|
92
115
|
- lib/xcodeproj/project.rb
|
93
116
|
- lib/xcodeproj/project/case_converter.rb
|
94
117
|
- lib/xcodeproj/project/object.rb
|
@@ -150,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
173
|
version: '0'
|
151
174
|
requirements: []
|
152
175
|
rubyforge_project:
|
153
|
-
rubygems_version: 2.
|
176
|
+
rubygems_version: 2.6.7
|
154
177
|
signing_key:
|
155
178
|
specification_version: 3
|
156
179
|
summary: Create and modify Xcode projects from Ruby.
|
data/lib/xcodeproj/plist/ffi.rb
DELETED
@@ -1,153 +0,0 @@
|
|
1
|
-
|
2
|
-
module Xcodeproj
|
3
|
-
module Plist
|
4
|
-
# Provides support for loading and serializing property list files via
|
5
|
-
# Fiddle and CoreFoundation / Xcode.
|
6
|
-
#
|
7
|
-
module FFI
|
8
|
-
autoload :CoreFoundation, 'xcodeproj/plist/ffi/core_foundation'
|
9
|
-
autoload :DevToolsCore, 'xcodeproj/plist/ffi/dev_tools_core'
|
10
|
-
|
11
|
-
class << self
|
12
|
-
# Attempts to load the `fiddle` and Xcode based plist serializer.
|
13
|
-
#
|
14
|
-
# @return [String,Nil] The loading error message, or `nil` if loading
|
15
|
-
# was successful.
|
16
|
-
#
|
17
|
-
def attempt_to_load!
|
18
|
-
return @attempt_to_load if defined?(@attempt_to_load)
|
19
|
-
@attempt_to_load = begin
|
20
|
-
require 'fiddle'
|
21
|
-
nil
|
22
|
-
rescue LoadError
|
23
|
-
'Xcodeproj relies on a library called `fiddle` to read and write ' \
|
24
|
-
'Xcode project files. Ensure your Ruby installation includes ' \
|
25
|
-
'`fiddle` and try again.'
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# Serializes a hash as an XML property list file.
|
30
|
-
#
|
31
|
-
# @param [#to_hash] hash
|
32
|
-
# The hash to store.
|
33
|
-
#
|
34
|
-
# @param [#to_s] path
|
35
|
-
# The path of the file.
|
36
|
-
#
|
37
|
-
def write_to_path(hash, path)
|
38
|
-
raise ThreadError, 'Can only write plists from the main thread.' unless Thread.current == Thread.main
|
39
|
-
|
40
|
-
path = File.expand_path(path)
|
41
|
-
|
42
|
-
should_fork = ENV['FORK_XCODE_WRITING']
|
43
|
-
success = ruby_hash_write_xcode(hash, path, should_fork)
|
44
|
-
|
45
|
-
unless success
|
46
|
-
CoreFoundation.RubyHashPropertyListWrite(hash, path)
|
47
|
-
fix_encoding(path)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# @return [Hash] Returns the native objects loaded from a property list
|
52
|
-
# file.
|
53
|
-
#
|
54
|
-
# @param [#to_s] path
|
55
|
-
# The path of the file.
|
56
|
-
#
|
57
|
-
def read_from_path(path)
|
58
|
-
CoreFoundation.RubyHashPropertyListRead(path)
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
# Simple workaround to escape characters which are outside of ASCII
|
64
|
-
# character-encoding. Relies on the fact that there are no XML characters
|
65
|
-
# which would need to be escaped.
|
66
|
-
#
|
67
|
-
# @note This is necessary because Xcode (4.6 currently) uses the MacRoman
|
68
|
-
# encoding unless the `// !$*UTF8*$!` magic comment is present. It
|
69
|
-
# is not possible to serialize a plist using the NeXTSTEP format
|
70
|
-
# without access to the private classes of Xcode and that comment
|
71
|
-
# is not compatible with the XML format. For the complete
|
72
|
-
# discussion see CocoaPods/CocoaPods#926.
|
73
|
-
#
|
74
|
-
#
|
75
|
-
# @note Sadly this hack is not sufficient for supporting Emoji.
|
76
|
-
#
|
77
|
-
# @param [String, Pathname] The path of the file which needs to be fixed.
|
78
|
-
#
|
79
|
-
# @return [void]
|
80
|
-
#
|
81
|
-
def fix_encoding(filename)
|
82
|
-
output = ''
|
83
|
-
input = File.open(filename, 'rb', &:read)
|
84
|
-
input.unpack('U*').each do |codepoint|
|
85
|
-
if codepoint > 127 # ASCII is 7-bit, so 0-127 are valid characters
|
86
|
-
output << "&##{codepoint};"
|
87
|
-
else
|
88
|
-
output << codepoint.chr
|
89
|
-
end
|
90
|
-
end
|
91
|
-
File.open(filename, 'wb') { |file| file.write(output) }
|
92
|
-
end
|
93
|
-
|
94
|
-
# Serializes a hash as an ASCII plist, using Xcode.
|
95
|
-
#
|
96
|
-
# @param [Hash] hash
|
97
|
-
# The hash to store.
|
98
|
-
#
|
99
|
-
# @param [String] path
|
100
|
-
# The path of the file.
|
101
|
-
#
|
102
|
-
def ruby_hash_write_xcode(hash, path, should_fork)
|
103
|
-
return false unless path.end_with?('pbxproj')
|
104
|
-
if should_fork
|
105
|
-
require 'open3'
|
106
|
-
_output, status = Open3.capture2e(Gem.ruby, '-e', <<-RUBY, path, :stdin_data => Marshal.dump(hash))
|
107
|
-
$LOAD_PATH.replace #{$LOAD_PATH}
|
108
|
-
path = ARGV.first
|
109
|
-
hash = Marshal.load(STDIN)
|
110
|
-
require "xcodeproj"
|
111
|
-
require "xcodeproj/plist/ffi"
|
112
|
-
ffi = Xcodeproj::Plist::FFI
|
113
|
-
success = ffi::DevToolsCore.load_xcode_frameworks && ffi.send(:ruby_hash_write_devtoolscore, hash, path)
|
114
|
-
exit(success ? 0 : 1)
|
115
|
-
RUBY
|
116
|
-
|
117
|
-
status.success?
|
118
|
-
else
|
119
|
-
monkey_patch_chdir
|
120
|
-
success = DevToolsCore.load_xcode_frameworks && ruby_hash_write_devtoolscore(hash, path)
|
121
|
-
|
122
|
-
success
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def ruby_hash_write_devtoolscore(hash, path)
|
127
|
-
success = true
|
128
|
-
|
129
|
-
begin
|
130
|
-
plist = DevToolsCore::CFDictionary.new(CoreFoundation.RubyHashToCFDictionary(hash))
|
131
|
-
data = DevToolsCore::NSData.new(plist.plistDescriptionUTF8Data)
|
132
|
-
success &= data.writeToFileAtomically(path)
|
133
|
-
|
134
|
-
project = DevToolsCore::PBXProject.new(path)
|
135
|
-
success &= project.writeToFileSystemProjectFile
|
136
|
-
project.close
|
137
|
-
rescue Fiddle::DLError
|
138
|
-
success = false
|
139
|
-
end
|
140
|
-
|
141
|
-
success
|
142
|
-
end
|
143
|
-
|
144
|
-
def monkey_patch_chdir
|
145
|
-
require 'xcodeproj/plist/ffi/chdir_override'
|
146
|
-
class << Dir
|
147
|
-
alias_method :chdir, :cp_chdir
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# Since Xcode 8 beta 4, calling `PBXProject.projectWithFile` breaks subsequent calls to
|
2
|
-
# `chdir`. While sounding ridiculous, this is unfortunately true and debugging it from the
|
3
|
-
# userland side showed no difference at all to successful calls to `chdir`, but the working
|
4
|
-
# directory is simply not changed in the end. This workaround is even more absurd, monkey
|
5
|
-
# patching all calls to `chdir` to use `__pthread_chdir` which appears to work.
|
6
|
-
class Dir
|
7
|
-
def self.cp_chdir(path)
|
8
|
-
old_dir = Dir.getwd
|
9
|
-
res = cp_actually_chdir(path)
|
10
|
-
|
11
|
-
if block_given?
|
12
|
-
begin
|
13
|
-
return yield
|
14
|
-
ensure
|
15
|
-
cp_actually_chdir(old_dir)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
res
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.cp_actually_chdir(path)
|
23
|
-
libc = Fiddle.dlopen '/usr/lib/libc.dylib'
|
24
|
-
f = Fiddle::Function.new(libc['__pthread_chdir'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
25
|
-
f.call(path.to_s)
|
26
|
-
end
|
27
|
-
end
|
@@ -1,441 +0,0 @@
|
|
1
|
-
require 'fiddle'
|
2
|
-
|
3
|
-
module Xcodeproj
|
4
|
-
module Plist
|
5
|
-
module FFI
|
6
|
-
# This module provides an interface to the CoreFoundation OS X framework.
|
7
|
-
# Specifically it bridges the functions required to be able to read and write
|
8
|
-
# property lists.
|
9
|
-
#
|
10
|
-
# Everything in here should be considered an implementation detail and thus is
|
11
|
-
# not further documented.
|
12
|
-
#
|
13
|
-
# @todo Move this out into its own gem.
|
14
|
-
#
|
15
|
-
# @!visibility private
|
16
|
-
#
|
17
|
-
module CoreFoundation
|
18
|
-
PATH = '/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation'
|
19
|
-
|
20
|
-
# rubocop:disable Style/MethodName
|
21
|
-
# rubocop:disable Style/VariableName
|
22
|
-
|
23
|
-
# @!group Ruby hash as property list (de)serialization
|
24
|
-
#---------------------------------------------------------------------------#
|
25
|
-
|
26
|
-
def self.RubyHashPropertyListWrite(hash, path)
|
27
|
-
url = CFURLCreateFromFileSystemRepresentation(NULL,
|
28
|
-
path,
|
29
|
-
path.bytesize,
|
30
|
-
FALSE)
|
31
|
-
stream = CFWriteStreamCreateWithFile(NULL, url)
|
32
|
-
unless CFWriteStreamOpen(stream) == TRUE
|
33
|
-
raise IOError, 'Unable to open stream.'
|
34
|
-
end
|
35
|
-
|
36
|
-
plist = RubyHashToCFDictionary(hash)
|
37
|
-
|
38
|
-
error_ptr = CFTypeRefPointer()
|
39
|
-
result = CFPropertyListWrite(plist,
|
40
|
-
stream,
|
41
|
-
KCFPropertyListXMLFormat_v1_0,
|
42
|
-
0,
|
43
|
-
error_ptr)
|
44
|
-
CFWriteStreamClose(stream)
|
45
|
-
|
46
|
-
if result == 0
|
47
|
-
description = CFCopyDescription(error_ptr.ptr)
|
48
|
-
raise IOError, "Unable to write plist data: #{description}"
|
49
|
-
end
|
50
|
-
result
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.RubyHashPropertyListRead(path)
|
54
|
-
url = CFURLCreateFromFileSystemRepresentation(NULL,
|
55
|
-
path,
|
56
|
-
path.bytesize,
|
57
|
-
FALSE)
|
58
|
-
stream = CFReadStreamCreateWithFile(NULL, url)
|
59
|
-
unless CFReadStreamOpen(stream) == TRUE
|
60
|
-
raise IOError, 'Unable to open stream.'
|
61
|
-
end
|
62
|
-
|
63
|
-
error_ptr = CFTypeRefPointer()
|
64
|
-
plist = CFPropertyListCreateWithStream(NULL,
|
65
|
-
stream,
|
66
|
-
0,
|
67
|
-
KCFPropertyListImmutable,
|
68
|
-
NULL,
|
69
|
-
error_ptr)
|
70
|
-
CFReadStreamClose(stream)
|
71
|
-
|
72
|
-
if plist.null?
|
73
|
-
description = CFCopyDescription(error_ptr.ptr)
|
74
|
-
raise IOError, "Unable to read plist data: #{description}"
|
75
|
-
elsif CFGetTypeID(plist) != CFDictionaryGetTypeID()
|
76
|
-
raise TypeError, 'Expected a plist with a dictionary root object.'
|
77
|
-
end
|
78
|
-
|
79
|
-
CFDictionaryToRubyHash(plist)
|
80
|
-
end
|
81
|
-
|
82
|
-
# @!group Types
|
83
|
-
#---------------------------------------------------------------------------#
|
84
|
-
|
85
|
-
# rubocop:disable Style/ConstantName
|
86
|
-
|
87
|
-
NULL = Fiddle::NULL
|
88
|
-
|
89
|
-
Void = Fiddle::TYPE_VOID
|
90
|
-
VoidPointer = Fiddle::TYPE_VOIDP
|
91
|
-
FunctionPointer = VoidPointer
|
92
|
-
|
93
|
-
UInt32 = -Fiddle::TYPE_INT
|
94
|
-
UInt8 = -Fiddle::TYPE_CHAR
|
95
|
-
|
96
|
-
SInt32Pointer = VoidPointer
|
97
|
-
UInt8Pointer = VoidPointer
|
98
|
-
CharPointer = VoidPointer
|
99
|
-
|
100
|
-
Boolean = Fiddle::TYPE_CHAR
|
101
|
-
TRUE = 1
|
102
|
-
FALSE = 0
|
103
|
-
|
104
|
-
SINT64_MAX = 2**63 - 1
|
105
|
-
SINT64_MIN = -SINT64_MAX - 1
|
106
|
-
|
107
|
-
SIZEOF_SINT64 = 8
|
108
|
-
SIZEOF_FLOAT64 = 8
|
109
|
-
|
110
|
-
SINT64_PACK_TEMPLATE = 'q'
|
111
|
-
FLOAT64_PACK_TEMPLATE = 'd'
|
112
|
-
|
113
|
-
CFTypeRef = VoidPointer
|
114
|
-
CFTypeRefPointer = VoidPointer
|
115
|
-
CFIndex = Fiddle::TYPE_LONG
|
116
|
-
CFTypeID = -Fiddle::TYPE_LONG
|
117
|
-
CFOptionFlags = UInt32
|
118
|
-
|
119
|
-
CFPropertyListMutabilityOptions = Fiddle::TYPE_INT
|
120
|
-
KCFPropertyListImmutable = 0
|
121
|
-
|
122
|
-
CFPropertyListFormat = Fiddle::TYPE_INT
|
123
|
-
KCFPropertyListXMLFormat_v1_0 = 100
|
124
|
-
CFPropertyListFormatPointer = VoidPointer
|
125
|
-
|
126
|
-
CFStringEncoding = UInt32
|
127
|
-
KCFStringEncodingUTF8 = 0x08000100
|
128
|
-
|
129
|
-
CFNumberType = Fiddle::TYPE_INT
|
130
|
-
KCFNumberSInt64Type = 4
|
131
|
-
KCFNumberFloat64Type = 6
|
132
|
-
|
133
|
-
# rubocop:enable Style/ConstantName
|
134
|
-
|
135
|
-
private
|
136
|
-
|
137
|
-
# @!group Helpers
|
138
|
-
#---------------------------------------------------------------------------#
|
139
|
-
|
140
|
-
def self.image
|
141
|
-
@image ||= Fiddle.dlopen(PATH)
|
142
|
-
end
|
143
|
-
|
144
|
-
def self.free_function
|
145
|
-
@free_function ||= Fiddle::Function.new(Fiddle::Handle.new['free'], [VoidPointer], Void)
|
146
|
-
end
|
147
|
-
|
148
|
-
def self.CFRelease_function
|
149
|
-
@CFRelease ||= Fiddle::Function.new(image['CFRelease'], [CFTypeRef], Void)
|
150
|
-
end
|
151
|
-
|
152
|
-
def self.extern_image(image, symbol, parameter_types, return_type)
|
153
|
-
symbol = symbol.to_s
|
154
|
-
create_function = symbol.include?('Create')
|
155
|
-
function_cache_key = "@__#{symbol}__"
|
156
|
-
|
157
|
-
# Define a singleton method on the CoreFoundation module.
|
158
|
-
define_singleton_method(symbol) do |*args|
|
159
|
-
unless args.size == parameter_types.size
|
160
|
-
raise ArgumentError, "wrong number of arguments (#{args.size} for " \
|
161
|
-
"#{parameter_types.size})"
|
162
|
-
end
|
163
|
-
|
164
|
-
unless function = instance_variable_get(function_cache_key)
|
165
|
-
function = Fiddle::Function.new(image[symbol],
|
166
|
-
parameter_types,
|
167
|
-
return_type)
|
168
|
-
instance_variable_set(function_cache_key, function)
|
169
|
-
end
|
170
|
-
|
171
|
-
result = function.call(*args)
|
172
|
-
create_function ? CFAutoRelease(result) : result
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def self.extern(symbol, parameter_types, return_type)
|
177
|
-
extern_image(image, symbol, parameter_types, return_type)
|
178
|
-
end
|
179
|
-
|
180
|
-
public
|
181
|
-
|
182
|
-
# @!group CoreFoundation function definitions
|
183
|
-
#---------------------------------------------------------------------------#
|
184
|
-
|
185
|
-
# CFTypeRef description
|
186
|
-
extern :CFShow, [CFTypeRef], Void
|
187
|
-
extern :CFCopyDescription, [CFTypeRef], CFTypeRef
|
188
|
-
|
189
|
-
# CFType reflection
|
190
|
-
extern :CFGetTypeID, [CFTypeRef], CFTypeID
|
191
|
-
extern :CFDictionaryGetTypeID, [], CFTypeID
|
192
|
-
extern :CFStringGetTypeID, [], CFTypeID
|
193
|
-
extern :CFArrayGetTypeID, [], CFTypeID
|
194
|
-
extern :CFBooleanGetTypeID, [], CFTypeID
|
195
|
-
extern :CFNumberGetTypeID, [], CFTypeID
|
196
|
-
|
197
|
-
# CFStream
|
198
|
-
extern :CFWriteStreamCreateWithFile, [CFTypeRef, CFTypeRef], CFTypeRef
|
199
|
-
extern :CFWriteStreamOpen, [CFTypeRef], Boolean
|
200
|
-
extern :CFWriteStreamClose, [CFTypeRef], Void
|
201
|
-
extern :CFReadStreamCreateWithFile, [CFTypeRef, CFTypeRef], CFTypeRef
|
202
|
-
extern :CFReadStreamOpen, [CFTypeRef], Boolean
|
203
|
-
extern :CFReadStreamClose, [CFTypeRef], Void
|
204
|
-
|
205
|
-
# CFURL
|
206
|
-
extern :CFURLCreateFromFileSystemRepresentation, [CFTypeRef, UInt8Pointer, CFIndex, Boolean], CFTypeRef
|
207
|
-
|
208
|
-
# CFPropertyList
|
209
|
-
extern :CFPropertyListWrite, [CFTypeRef, CFTypeRef, CFPropertyListFormat, CFOptionFlags, CFTypeRefPointer], CFIndex
|
210
|
-
extern :CFPropertyListCreateWithStream, [CFTypeRef, CFTypeRef, CFIndex, CFOptionFlags, CFPropertyListFormatPointer, CFTypeRefPointer], CFTypeRef
|
211
|
-
|
212
|
-
# CFString
|
213
|
-
extern :CFStringCreateExternalRepresentation, [CFTypeRef, CFTypeRef, CFStringEncoding, UInt8], CFTypeRef
|
214
|
-
extern :CFStringCreateWithCString, [CFTypeRef, CharPointer, CFStringEncoding], CFTypeRef
|
215
|
-
|
216
|
-
# CFData
|
217
|
-
extern :CFDataGetLength, [CFTypeRef], CFIndex
|
218
|
-
extern :CFDataGetBytePtr, [CFTypeRef], VoidPointer
|
219
|
-
|
220
|
-
# CFDictionary
|
221
|
-
extern :CFDictionaryCreateMutable, [CFTypeRef, CFIndex, VoidPointer, VoidPointer], CFTypeRef
|
222
|
-
extern :CFDictionaryAddValue, [CFTypeRef, CFTypeRef, CFTypeRef], VoidPointer
|
223
|
-
extern :CFDictionaryApplyFunction, [CFTypeRef, FunctionPointer, VoidPointer], Void
|
224
|
-
|
225
|
-
# CFArray
|
226
|
-
extern :CFArrayCreateMutable, [CFTypeRef, CFIndex, VoidPointer], CFTypeRef
|
227
|
-
extern :CFArrayAppendValue, [CFTypeRef, CFTypeRef], VoidPointer
|
228
|
-
extern :CFArrayGetCount, [CFTypeRef], CFIndex
|
229
|
-
extern :CFArrayGetValueAtIndex, [CFTypeRef, CFIndex], CFTypeRef
|
230
|
-
|
231
|
-
# CFBoolean
|
232
|
-
extern :CFBooleanGetValue, [CFTypeRef], Boolean
|
233
|
-
|
234
|
-
# CFNumber
|
235
|
-
extern :CFNumberIsFloatType, [CFTypeRef], Boolean
|
236
|
-
extern :CFNumberGetValue, [CFTypeRef, CFNumberType, VoidPointer], Boolean
|
237
|
-
extern :CFNumberCreate, [CFTypeRef, CFNumberType, VoidPointer], CFTypeRef
|
238
|
-
|
239
|
-
# @!group Custom convenience functions
|
240
|
-
#---------------------------------------------------------------------------#
|
241
|
-
|
242
|
-
def self.CFBooleanTrue
|
243
|
-
@CFBooleanTrue ||= Fiddle::Pointer.new(image['kCFBooleanTrue']).ptr
|
244
|
-
end
|
245
|
-
|
246
|
-
def self.CFBooleanFalse
|
247
|
-
@CFBooleanFalse ||= Fiddle::Pointer.new(image['kCFBooleanFalse']).ptr
|
248
|
-
end
|
249
|
-
|
250
|
-
def self.CFTypeArrayCallBacks
|
251
|
-
@CFTypeArrayCallBacks ||= image['kCFTypeArrayCallBacks']
|
252
|
-
end
|
253
|
-
|
254
|
-
def self.CFTypeDictionaryKeyCallBacks
|
255
|
-
@CFTypeDictionaryKeyCallBacks ||= image['kCFTypeDictionaryKeyCallBacks']
|
256
|
-
end
|
257
|
-
|
258
|
-
def self.CFTypeDictionaryValueCallBacks
|
259
|
-
@CFTypeDictionaryValueCallBacks ||= image['kCFTypeDictionaryValueCallBacks']
|
260
|
-
end
|
261
|
-
|
262
|
-
# This pointer will assign `CFRelease` as the free function when
|
263
|
-
# dereferencing the pointer.
|
264
|
-
#
|
265
|
-
# @note This means that the object will *not* be released if it's not
|
266
|
-
# dereferenced, but that would be a leak anyways, so be sure to do so.
|
267
|
-
#
|
268
|
-
def self.CFTypeRefPointer
|
269
|
-
pointer = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INTPTR_T, free_function)
|
270
|
-
def pointer.ptr
|
271
|
-
::CoreFoundation.CFAutoRelease(super)
|
272
|
-
end
|
273
|
-
pointer
|
274
|
-
end
|
275
|
-
|
276
|
-
def self.CFAutoRelease(cf_type_reference)
|
277
|
-
cf_type_reference.free = CFRelease_function() unless cf_type_reference.null?
|
278
|
-
cf_type_reference
|
279
|
-
end
|
280
|
-
|
281
|
-
def self.CFDictionaryApplyBlock(dictionary, &applier)
|
282
|
-
param_types = [CFTypeRef, CFTypeRef, VoidPointer]
|
283
|
-
closure = Fiddle::Closure::BlockCaller.new(Void, param_types, &applier)
|
284
|
-
closure_function = Fiddle::Function.new(closure, param_types, Void)
|
285
|
-
CFDictionaryApplyFunction(dictionary, closure_function, NULL)
|
286
|
-
end
|
287
|
-
|
288
|
-
def self.CFArrayApplyBlock(array)
|
289
|
-
CFArrayGetCount(array).times do |index|
|
290
|
-
yield CFArrayGetValueAtIndex(array, index)
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
# @!group CFTypeRef to Ruby value conversion
|
295
|
-
#---------------------------------------------------------------------------#
|
296
|
-
|
297
|
-
def self.CFTypeRefToRubyValue(cf_type_reference)
|
298
|
-
case CFGetTypeID(cf_type_reference)
|
299
|
-
when CFStringGetTypeID()
|
300
|
-
CFStringToRubyString(cf_type_reference)
|
301
|
-
when CFDictionaryGetTypeID()
|
302
|
-
CFDictionaryToRubyHash(cf_type_reference)
|
303
|
-
when CFArrayGetTypeID()
|
304
|
-
CFArrayToRubyArray(cf_type_reference)
|
305
|
-
when CFBooleanGetTypeID()
|
306
|
-
CFBooleanToRubyBoolean(cf_type_reference)
|
307
|
-
when CFNumberGetTypeID()
|
308
|
-
CFNumberToRubyNumber(cf_type_reference)
|
309
|
-
else
|
310
|
-
description = CFStringToRubyString(CFCopyDescription(cf_type_reference))
|
311
|
-
raise TypeError, "Unknown type: #{description}"
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
def self.CFStringToRubyString(string)
|
316
|
-
data = CFStringCreateExternalRepresentation(NULL,
|
317
|
-
string,
|
318
|
-
KCFStringEncodingUTF8,
|
319
|
-
0)
|
320
|
-
if data.null?
|
321
|
-
raise TypeError, 'Unable to convert CFStringRef.'
|
322
|
-
end
|
323
|
-
bytes_ptr = CFDataGetBytePtr(data)
|
324
|
-
result = bytes_ptr.to_str(CFDataGetLength(data))
|
325
|
-
result.force_encoding(Encoding::UTF_8)
|
326
|
-
result
|
327
|
-
end
|
328
|
-
|
329
|
-
def self.CFDictionaryToRubyHash(dictionary)
|
330
|
-
result = {}
|
331
|
-
CFDictionaryApplyBlock(dictionary) do |key, value|
|
332
|
-
result[CFStringToRubyString(key)] = CFTypeRefToRubyValue(value)
|
333
|
-
end
|
334
|
-
result
|
335
|
-
end
|
336
|
-
|
337
|
-
def self.CFArrayToRubyArray(array)
|
338
|
-
result = []
|
339
|
-
CFArrayApplyBlock(array) do |element|
|
340
|
-
result << CFTypeRefToRubyValue(element)
|
341
|
-
end
|
342
|
-
result
|
343
|
-
end
|
344
|
-
|
345
|
-
def self.CFBooleanToRubyBoolean(boolean)
|
346
|
-
CFBooleanGetValue(boolean) == TRUE
|
347
|
-
end
|
348
|
-
|
349
|
-
def self.CFNumberToRubyNumber(number)
|
350
|
-
if CFNumberIsFloatType(number) == FALSE
|
351
|
-
value_type = KCFNumberSInt64Type
|
352
|
-
pack_template = SINT64_PACK_TEMPLATE
|
353
|
-
size = SIZEOF_SINT64
|
354
|
-
else
|
355
|
-
value_type = KCFNumberFloat64Type
|
356
|
-
pack_template = FLOAT64_PACK_TEMPLATE
|
357
|
-
size = SIZEOF_FLOAT64
|
358
|
-
end
|
359
|
-
ptr = Fiddle::Pointer.malloc(size)
|
360
|
-
CFNumberGetValue(number, value_type, ptr)
|
361
|
-
ptr.to_str.unpack(pack_template).first
|
362
|
-
end
|
363
|
-
|
364
|
-
# @!group Ruby value to CFTypeRef conversion
|
365
|
-
#---------------------------------------------------------------------------#
|
366
|
-
|
367
|
-
def self.RubyValueToCFTypeRef(value)
|
368
|
-
result = case value
|
369
|
-
when String
|
370
|
-
RubyStringToCFString(value)
|
371
|
-
when Hash
|
372
|
-
RubyHashToCFDictionary(value)
|
373
|
-
when Array
|
374
|
-
RubyArrayToCFArray(value)
|
375
|
-
when true, false
|
376
|
-
RubyBooleanToCFBoolean(value)
|
377
|
-
when Numeric
|
378
|
-
RubyNumberToCFNumber(value)
|
379
|
-
else
|
380
|
-
RubyStringToCFString(value.to_s)
|
381
|
-
end
|
382
|
-
if result.null?
|
383
|
-
raise TypeError, "Unable to convert Ruby value `#{value.inspect}' " \
|
384
|
-
'into a CFTypeRef.'
|
385
|
-
end
|
386
|
-
result
|
387
|
-
end
|
388
|
-
|
389
|
-
def self.RubyStringToCFString(string)
|
390
|
-
CFStringCreateWithCString(NULL,
|
391
|
-
Fiddle::Pointer[string.encode('UTF-8')],
|
392
|
-
KCFStringEncodingUTF8)
|
393
|
-
end
|
394
|
-
|
395
|
-
def self.RubyHashToCFDictionary(hash)
|
396
|
-
result = CFDictionaryCreateMutable(NULL,
|
397
|
-
0,
|
398
|
-
CFTypeDictionaryKeyCallBacks(),
|
399
|
-
CFTypeDictionaryValueCallBacks())
|
400
|
-
hash.each do |key, value|
|
401
|
-
key = RubyStringToCFString(key.to_s)
|
402
|
-
value = RubyValueToCFTypeRef(value)
|
403
|
-
CFDictionaryAddValue(result, key, value)
|
404
|
-
end
|
405
|
-
result
|
406
|
-
end
|
407
|
-
|
408
|
-
def self.RubyArrayToCFArray(array)
|
409
|
-
result = CFArrayCreateMutable(NULL, 0, CFTypeArrayCallBacks())
|
410
|
-
array.each do |element|
|
411
|
-
element = RubyValueToCFTypeRef(element)
|
412
|
-
CFArrayAppendValue(result, element)
|
413
|
-
end
|
414
|
-
result
|
415
|
-
end
|
416
|
-
|
417
|
-
def self.RubyNumberToCFNumber(value)
|
418
|
-
case value
|
419
|
-
when Float
|
420
|
-
value_type = KCFNumberFloat64Type
|
421
|
-
pack_template = FLOAT64_PACK_TEMPLATE
|
422
|
-
when SINT64_MIN..SINT64_MAX
|
423
|
-
value_type = KCFNumberSInt64Type
|
424
|
-
pack_template = SINT64_PACK_TEMPLATE
|
425
|
-
else # the value is too big to be stored in a CFNumber so store it as a CFString
|
426
|
-
return RubyStringToCFString(value.to_s)
|
427
|
-
end
|
428
|
-
ptr = Fiddle::Pointer.to_ptr([value].pack(pack_template))
|
429
|
-
CFNumberCreate(NULL, value_type, ptr)
|
430
|
-
end
|
431
|
-
|
432
|
-
def self.RubyBooleanToCFBoolean(value)
|
433
|
-
value ? CFBooleanTrue() : CFBooleanFalse()
|
434
|
-
end
|
435
|
-
|
436
|
-
# rubocop:enable Style/MethodName
|
437
|
-
# rubocop:enable Style/VariableName
|
438
|
-
end
|
439
|
-
end
|
440
|
-
end
|
441
|
-
end
|