keyed_archive 0.1.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 20bed81f6f133648cf631d3216523aeddbc14eeb
4
- data.tar.gz: 2d7912ef9102f3ece3b77a64fc872ed1207676c2
2
+ SHA256:
3
+ metadata.gz: d932ce3e1c5bf7832937aeba3b66736cc94b9036ae9a242e32ef3d4310cece72
4
+ data.tar.gz: 74e5020a25d5346e1789fd12d4e4038c00f64c99a9a44f8906bbfa47d677f879
5
5
  SHA512:
6
- metadata.gz: 3762da9e73d7512f57c2132b04694a94b8b7b34711253b1b1785b88a5c7835c5d3ea558c32094bb5dde4cc7f68b3ffbd1ea0fb5ff7c20f9cfdc6946f1d292c4d
7
- data.tar.gz: e68c08996edb3c3e0932c1c5e842de86dd56e263a95ae73ebeba886dd66aea00ec486b428e6878a875b146aed104f61e2cc8254085f3fa062e43dd6f9f914553
6
+ metadata.gz: 0a0152d78b35fd324d3c48838ce21c19d71530e5d0234dabe668dd89e5dd88fae5f51539dbf6a62162a52fd4fabf1ac4e7ecba7540170acf277c75d5122e53d5
7
+ data.tar.gz: 5051e71618ab45823bd96fa1e1e00ec0d33c5311af024da0a1e2ec14e31115570b523324c6f64f060bf434da3559c864de0df2f72572b64c81a124280ea3daa6
data/README.md CHANGED
@@ -18,6 +18,22 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
+ ### Basic Syntax
22
+
23
+ KeyedArchive supports the initializer arguments which CFPropertyList supports: `:file` to read data directly from a file and `:data` to read data from a variable that already has your NSKeyedArchive data within it.
24
+
25
+ ```ruby
26
+
27
+ # Create KeyedArchive by reading a file directly
28
+ keyed_archive_from_file = KeyedArchive.new(:file => "path/to/file.plist")
29
+
30
+ # Create KeyedArchive from a variable holding content which can
31
+ # be parsed as a plist, either XML or binary.
32
+ file_contents = File.read("path/to/file.plist")
33
+ keyed_archive_from_variable = KeyedArchive.new(:data => file_contents)
34
+
35
+ ```
36
+
21
37
  ### Opening a keyed archive
22
38
  ```xml
23
39
  <?xml version="1.0" encoding="UTF-8"?>
@@ -48,11 +64,12 @@ Or install it yourself as:
48
64
  require 'keyed_archive'
49
65
 
50
66
  filename = "path/to/file.plist"
51
- keyed_archive = KeyedArchive.new("path/to/file.plist")
52
- keyed_archive.archiver # "NSKeyedArchiver"
53
- keyed_archive.objects # ["$null"]
54
- keyed_archive.top # {"root"=>{"CF$UID"=>1}}
55
- keyed_archive.version # 100000
67
+ keyed_archive = KeyedArchive.new(:file => "path/to/file.plist")
68
+ keyed_archive.archiver # "NSKeyedArchiver"
69
+ keyed_archive.objects # ["$null"]
70
+ keyed_archive.top # {"root"=>1}
71
+ keyed_archive.version # 100000
72
+ keyed_archive.unpacked_top # {"root"=>nil}
56
73
  ```
57
74
 
58
75
  ### Unpacking keyed archive objects
@@ -88,14 +105,15 @@ keyed_archive.version # 100000
88
105
  ```ruby
89
106
  require 'keyed_archive'
90
107
 
91
- keyed_archive = KeyedArchive.new("path/to/file.plist")
92
- keyed_archive.objects # ["$null", "value", {"reference"=>{"CF$UID"=>3}}, {"key"=>{"CF$UID"=>1}}]
93
- keyed_archive.unpacked_objects() # ["$null", {"key"=>"value"}]
108
+ keyed_archive = KeyedArchive.new(:file => "path/to/file.plist")
109
+ keyed_archive.objects # ["$null", {"key"=>"value"}]
110
+ keyed_archive.top # {"root"=>1}
111
+ keyed_archive.unpacked_top() # {"root"=>{"key"=>"value"}}
94
112
  ```
95
113
 
96
114
  ## Contributing
97
115
 
98
- 1. Fork it ( http://github.com/<my-github-username>/keyed_archive/fork )
116
+ 1. Fork it ( http://github.com/\<my-github-username\>/keyed_archive/fork )
99
117
  2. Create your feature branch (`git checkout -b my-new-feature`)
100
118
  3. Commit your changes (`git commit -am 'Add some feature'`)
101
119
  4. Push to the branch (`git push origin my-new-feature`)
@@ -17,9 +17,9 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_dependency "CFPropertyList", "~> 2.2.7"
20
+ spec.add_dependency "CFPropertyList", "~> 3.0"
21
21
 
22
- spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "bundler", "~> 2.1"
23
23
  spec.add_development_dependency "rake"
24
- spec.add_development_dependency "rspec", "~> 2.14.1"
24
+ spec.add_development_dependency "rspec", "~> 3.9"
25
25
  end
@@ -1,18 +1,31 @@
1
1
  require 'cfpropertylist'
2
2
 
3
- require "keyed_archive/unpacked_objects"
4
- require "keyed_archive/version"
3
+ require 'keyed_archive/unpacked_objects'
4
+ require 'keyed_archive/version'
5
5
 
6
6
  class KeyedArchive
7
7
  attr_accessor :archiver, :objects, :top, :version
8
8
 
9
- def initialize(file)
10
- plist = CFPropertyList::List.new(:file => file)
11
- data = CFPropertyList.native_types(plist.value)
9
+ #
10
+ # Take the same sort of arguments as CFPropertyList
11
+ # :file => filename to load
12
+ # :data => variable with the data to load directly
13
+ def initialize(opts={})
14
+ blob = opts[:data]
15
+ filename = opts[:file]
12
16
 
13
- @archiver = data['$archiver']
14
- @objects = data['$objects']
15
- @top = data['$top']
16
- @version = data['$version']
17
+ plist = CFPropertyList::List.new(:file => filename) unless filename.nil? or !File.exists?(filename)
18
+ plist = CFPropertyList::List.new(:data => blob) unless blob.nil? or blob.length < 1
19
+
20
+ if !plist.nil?
21
+ data = CFPropertyList.native_types(plist.value)
22
+
23
+ @archiver = data['$archiver']
24
+ @objects = data['$objects']
25
+ @top = data['$top']
26
+ @version = data['$version']
27
+ else
28
+ raise "Plist not created"
29
+ end
17
30
  end
18
31
  end
@@ -1,31 +1,75 @@
1
1
  class KeyedArchive
2
- def unpacked_objects
3
- objects = @objects.clone
4
- unpacked_objects = []
5
-
6
- objects.each_with_index do |object, index|
7
- if object.is_a? Hash
8
- object.each_pair do |key, value|
9
- if value.is_a? Hash
10
- uid = value['CF$UID']
11
-
12
- if uid
13
- new_object = {}
14
- new_object[key] = @objects[uid]
15
- objects.push new_object
16
- unpacked_objects.delete_at(index - 1)
17
- end
18
- else
19
- new_object = {}
20
- new_object[key] = value
21
- unpacked_objects.push new_object
2
+
3
+ # Loops through the entries within '$top'
4
+ # to replace any values that are pointers to objects.
5
+ def unpacked_top
6
+
7
+ # Create the return value
8
+ unpacked_top = Hash.new
9
+
10
+ # Loop over each pair in the '$top' hash
11
+ # to recursively replace the values
12
+ @top.each_pair do |key, value|
13
+ unpacked_top[key] = recursive_replace(value, -1, [])
14
+ end
15
+
16
+ # Politely return, our job is done
17
+ return unpacked_top
18
+ end
19
+
20
+ private
21
+
22
+ # Handles the recursive replacement of values within the
23
+ # '$objects' array. Tracks the object locations it has
24
+ # already touched to prevent infinite loops.
25
+ def recursive_replace(value, current_location, locations)
26
+ # By default we just return the value itself, usually a String
27
+ to_return = value
28
+
29
+ # If the value is really representing nil, change it to nil
30
+ if value.is_a? String and value == "$null"
31
+ to_return = nil
32
+ end
33
+
34
+ # If we have an Integer, we want to bring in the object
35
+ # that Integer points to
36
+ if value.is_a? Integer
37
+
38
+ # If we ever find a reference to one of our parents, just stop where we are
39
+ if locations.include?(current_location)
40
+ to_return = value
41
+ else
42
+ to_return = recursive_replace(@objects[value], value, locations.clone.push(current_location))
43
+ end
44
+
45
+ # If we have a Hash, we want to check each entry
46
+ # and replace any values which need it
47
+ elsif value.is_a? Hash
48
+
49
+ # Build up a new Hash
50
+ to_return = Hash.new
51
+
52
+ # Loop over the pairs to check the key, value, or both
53
+ value.each_pair do |tmp_key, tmp_value|
54
+
55
+ # If this points to an array of objects,
56
+ # then we should bring those values in
57
+ if tmp_key == "NS.objects" or tmp_key == "NS.keys"
58
+ new_array = Array.new
59
+ tmp_value.each do |entry|
60
+ new_array.push(recursive_replace(entry, entry, locations.clone.push(current_location)))
22
61
  end
62
+ to_return[tmp_key] = new_array
63
+
64
+ # Otherwise, we just want to replace the value with
65
+ # its recursive version
66
+ else
67
+ to_return[tmp_key] = recursive_replace(tmp_value, tmp_value, locations.clone.push(current_location))
23
68
  end
24
- else
25
- unpacked_objects.push object
26
69
  end
27
70
  end
28
71
 
29
- return unpacked_objects
72
+ # Give back the value, politely
73
+ return to_return
30
74
  end
31
75
  end
@@ -1,3 +1,3 @@
1
1
  class KeyedArchive
2
- VERSION = "0.1.0"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -2,29 +2,35 @@ require "keyed_archive"
2
2
 
3
3
  describe KeyedArchive, "#initialize" do
4
4
  let(:filename) { 'spec/fixtures/empty.plist' }
5
+ let(:blob) { File.read('spec/fixtures/empty.bplist') }
5
6
 
6
7
  it "should create an instance" do
7
- keyed_archive = KeyedArchive.new(filename)
8
+ keyed_archive = KeyedArchive.new(:file => filename)
8
9
  expect(keyed_archive).to be_instance_of(KeyedArchive)
9
10
  end
10
11
 
11
12
  it "should set the archiver" do
12
- keyed_archive = KeyedArchive.new(filename)
13
+ keyed_archive = KeyedArchive.new(:file => filename)
13
14
  expect(keyed_archive.archiver).to be_a(String)
14
15
  end
15
16
 
16
17
  it "should set the objects" do
17
- keyed_archive = KeyedArchive.new(filename)
18
+ keyed_archive = KeyedArchive.new(:file => filename)
18
19
  expect(keyed_archive.objects).to be_an(Array)
19
20
  end
20
21
 
21
22
  it "should set the top" do
22
- keyed_archive = KeyedArchive.new(filename)
23
+ keyed_archive = KeyedArchive.new(:file => filename)
23
24
  expect(keyed_archive.top).to be_a(Hash)
24
25
  end
25
26
 
26
27
  it "should set the version" do
27
- keyed_archive = KeyedArchive.new(filename)
28
+ keyed_archive = KeyedArchive.new(:file => filename)
29
+ expect(keyed_archive.version).to be_an(Integer)
30
+ end
31
+
32
+ it "should read data from variables as well" do
33
+ keyed_archive = KeyedArchive.new(:data => blob)
28
34
  expect(keyed_archive.version).to be_an(Integer)
29
35
  end
30
36
  end
@@ -2,10 +2,17 @@ require "keyed_archive/unpacked_objects"
2
2
 
3
3
  shared_examples "unpack" do
4
4
  it "should unpack objects" do
5
- keyed_archive = KeyedArchive.new(filename)
6
- unpacked_objects = keyed_archive.unpacked_objects()
7
- fixture_archive = KeyedArchive.new(fixture)
8
- expect(unpacked_objects).to eq(fixture_archive.objects)
5
+ keyed_archive = KeyedArchive.new(:file => filename)
6
+ unpacked_top = keyed_archive.unpacked_top()
7
+ fixture_archive = KeyedArchive.new(:file => fixture)
8
+ expect(unpacked_top["root"]).to eq(fixture_archive.objects[1]["key"])
9
+ end
10
+
11
+ it "should handle variables" do
12
+ keyed_archive = KeyedArchive.new(:data => blob)
13
+ unpacked_top = keyed_archive.unpacked_top()
14
+ fixture_archive = KeyedArchive.new(:file => fixture)
15
+ expect(unpacked_top["root"]).to eq(fixture_archive.objects[1]["key"])
9
16
  end
10
17
  end
11
18
 
@@ -13,6 +20,7 @@ describe KeyedArchive, "#unpack" do
13
20
  context "single reference" do
14
21
  it_behaves_like "unpack" do
15
22
  let(:filename) { "spec/fixtures/single_object_reference.plist" }
23
+ let(:blob) { File.read("spec/fixtures/single_object_reference.plist") }
16
24
  let(:fixture) { "spec/fixtures/single_object_reference_unpacked.plist" }
17
25
  end
18
26
  end
@@ -20,6 +28,7 @@ describe KeyedArchive, "#unpack" do
20
28
  context "double reference" do
21
29
  it_behaves_like "unpack" do
22
30
  let(:filename) { "spec/fixtures/double_object_reference.plist" }
31
+ let(:blob) { File.read("spec/fixtures/double_object_reference.plist") }
23
32
  let(:fixture) { "spec/fixtures/double_object_reference_unpacked.plist" }
24
33
  end
25
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keyed_archive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Young
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-22 00:00:00.000000000 Z
11
+ date: 2020-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: CFPropertyList
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.2.7
19
+ version: '3.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 2.2.7
26
+ version: '3.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.5'
33
+ version: '2.1'
34
34
  type: :development
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: '1.5'
40
+ version: '2.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,15 +58,15 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 2.14.1
61
+ version: '3.9'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 2.14.1
69
- description:
68
+ version: '3.9'
69
+ description:
70
70
  email:
71
71
  - paulyoungonline@gmail.com
72
72
  executables: []
@@ -85,7 +85,9 @@ files:
85
85
  - lib/keyed_archive/version.rb
86
86
  - spec/fixtures/double_object_reference.plist
87
87
  - spec/fixtures/double_object_reference_unpacked.plist
88
+ - spec/fixtures/empty.bplist
88
89
  - spec/fixtures/empty.plist
90
+ - spec/fixtures/single_object_reference.bplist
89
91
  - spec/fixtures/single_object_reference.plist
90
92
  - spec/fixtures/single_object_reference_unpacked.plist
91
93
  - spec/keyed_archive_spec.rb
@@ -94,7 +96,7 @@ homepage: https://github.com/paulyoung/keyed_archive
94
96
  licenses:
95
97
  - MIT
96
98
  metadata: {}
97
- post_install_message:
99
+ post_install_message:
98
100
  rdoc_options: []
99
101
  require_paths:
100
102
  - lib
@@ -109,15 +111,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
111
  - !ruby/object:Gem::Version
110
112
  version: '0'
111
113
  requirements: []
112
- rubyforge_project:
113
- rubygems_version: 2.2.2
114
- signing_key:
114
+ rubygems_version: 3.1.2
115
+ signing_key:
115
116
  specification_version: 4
116
117
  summary: A Ruby gem for working with files produced by NSKeyedArchiver.
117
118
  test_files:
118
119
  - spec/fixtures/double_object_reference.plist
119
120
  - spec/fixtures/double_object_reference_unpacked.plist
121
+ - spec/fixtures/empty.bplist
120
122
  - spec/fixtures/empty.plist
123
+ - spec/fixtures/single_object_reference.bplist
121
124
  - spec/fixtures/single_object_reference.plist
122
125
  - spec/fixtures/single_object_reference_unpacked.plist
123
126
  - spec/keyed_archive_spec.rb