fontist 1.8.7 → 1.8.8
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/fontist.gemspec +1 -5
- data/lib/fontist/font_installer.rb +37 -37
- data/lib/fontist/import/recursive_extraction.rb +25 -119
- data/lib/fontist/utils.rb +0 -8
- data/lib/fontist/version.rb +1 -1
- metadata +10 -85
- data/lib/fontist/import/extractors.rb +0 -9
- data/lib/fontist/import/extractors/cab_extractor.rb +0 -37
- data/lib/fontist/import/extractors/cpio_extractor.rb +0 -39
- data/lib/fontist/import/extractors/extractor.rb +0 -19
- data/lib/fontist/import/extractors/gzip_extractor.rb +0 -27
- data/lib/fontist/import/extractors/ole_extractor.rb +0 -41
- data/lib/fontist/import/extractors/rpm_extractor.rb +0 -45
- data/lib/fontist/import/extractors/seven_zip_extractor.rb +0 -44
- data/lib/fontist/import/extractors/tar_extractor.rb +0 -47
- data/lib/fontist/import/extractors/zip_extractor.rb +0 -31
- data/lib/fontist/utils/cpio/cpio.rb +0 -199
- data/lib/fontist/utils/cpio_extractor.rb +0 -47
- data/lib/fontist/utils/exe_extractor.rb +0 -75
- data/lib/fontist/utils/gzip_extractor.rb +0 -24
- data/lib/fontist/utils/msi_extractor.rb +0 -31
- data/lib/fontist/utils/rpm_extractor.rb +0 -44
- data/lib/fontist/utils/seven_zip_extractor.rb +0 -41
- data/lib/fontist/utils/tar_extractor.rb +0 -61
- data/lib/fontist/utils/zip_extractor.rb +0 -52
@@ -1,9 +0,0 @@
|
|
1
|
-
require_relative "extractors/extractor"
|
2
|
-
require_relative "extractors/zip_extractor"
|
3
|
-
require_relative "extractors/ole_extractor"
|
4
|
-
require_relative "extractors/seven_zip_extractor"
|
5
|
-
require_relative "extractors/cab_extractor"
|
6
|
-
require_relative "extractors/rpm_extractor"
|
7
|
-
require_relative "extractors/gzip_extractor"
|
8
|
-
require_relative "extractors/cpio_extractor"
|
9
|
-
require_relative "extractors/tar_extractor"
|
@@ -1,37 +0,0 @@
|
|
1
|
-
module Fontist
|
2
|
-
module Import
|
3
|
-
module Extractors
|
4
|
-
class CabExtractor < Extractor
|
5
|
-
def extract
|
6
|
-
dir = Dir.mktmpdir
|
7
|
-
extract_exe(@archive, dir)
|
8
|
-
dir
|
9
|
-
end
|
10
|
-
|
11
|
-
def format
|
12
|
-
File.extname(@archive) == ".exe" ? "exe" : "cab"
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def extract_exe(archive, dir)
|
18
|
-
opened = decompressor.search(archive)
|
19
|
-
file = opened.files
|
20
|
-
|
21
|
-
while file
|
22
|
-
path = File.join(dir, file.filename)
|
23
|
-
decompressor.extract(file, path)
|
24
|
-
file = file.next
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def decompressor
|
29
|
-
@decompressor ||= begin
|
30
|
-
require "libmspack"
|
31
|
-
LibMsPack::CabDecompressor.new
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
module Fontist
|
2
|
-
module Import
|
3
|
-
module Extractors
|
4
|
-
class CpioExtractor < Extractor
|
5
|
-
def extract
|
6
|
-
dir = Dir.mktmpdir
|
7
|
-
extract_cpio(@archive, dir)
|
8
|
-
dir
|
9
|
-
end
|
10
|
-
|
11
|
-
def format
|
12
|
-
"cpio"
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def extract_cpio(archive, dir)
|
18
|
-
archive_file = File.open(archive, "rb")
|
19
|
-
|
20
|
-
reader_class.new(archive_file).each do |entry, file|
|
21
|
-
path = File.join(dir, entry.name)
|
22
|
-
if entry.directory?
|
23
|
-
FileUtils.mkdir_p(path)
|
24
|
-
else
|
25
|
-
File.write(path, file.read)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def reader_class
|
31
|
-
@reader_class ||= begin
|
32
|
-
require "fontist/utils/cpio/cpio"
|
33
|
-
CPIO::ASCIIReader
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module Fontist
|
2
|
-
module Import
|
3
|
-
module Extractors
|
4
|
-
class Extractor
|
5
|
-
def initialize(archive)
|
6
|
-
@archive = archive
|
7
|
-
end
|
8
|
-
|
9
|
-
def extract
|
10
|
-
raise NotImplementedError.new("You must implement this method")
|
11
|
-
end
|
12
|
-
|
13
|
-
def format
|
14
|
-
raise NotImplementedError.new("You must implement this method")
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module Fontist
|
2
|
-
module Import
|
3
|
-
module Extractors
|
4
|
-
class GzipExtractor < Extractor
|
5
|
-
def extract
|
6
|
-
dir = Dir.mktmpdir
|
7
|
-
extract_gzip(@archive, dir)
|
8
|
-
dir
|
9
|
-
end
|
10
|
-
|
11
|
-
def format
|
12
|
-
"gzip"
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def extract_gzip(archive, dir)
|
18
|
-
Zlib::GzipReader.open(archive) do |gz|
|
19
|
-
basename = File.basename(archive, ".*")
|
20
|
-
path = File.join(dir, basename)
|
21
|
-
File.write(path, gz.read)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module Fontist
|
2
|
-
module Import
|
3
|
-
module Extractors
|
4
|
-
class OleExtractor < Extractor
|
5
|
-
def extract
|
6
|
-
dir = Dir.mktmpdir
|
7
|
-
extract_ole(@archive, dir)
|
8
|
-
dir
|
9
|
-
end
|
10
|
-
|
11
|
-
def format
|
12
|
-
"msi"
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def extract_ole(archive, dir)
|
18
|
-
ole = storage.open(archive)
|
19
|
-
file = the_largest_file(ole)
|
20
|
-
|
21
|
-
content = ole.file.read(file)
|
22
|
-
path = File.join(dir, "data.cab")
|
23
|
-
File.open(path, "wb") { |f| f.write(content) }
|
24
|
-
end
|
25
|
-
|
26
|
-
def storage
|
27
|
-
@storage ||= begin
|
28
|
-
require "ole/storage"
|
29
|
-
Ole::Storage
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def the_largest_file(ole)
|
34
|
-
ole.dir.entries(".").max_by do |x|
|
35
|
-
ole.file.size(x)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module Fontist
|
2
|
-
module Import
|
3
|
-
module Extractors
|
4
|
-
class RpmExtractor < Extractor
|
5
|
-
def extract
|
6
|
-
dir = Dir.mktmpdir
|
7
|
-
extract_rpm(@archive, dir)
|
8
|
-
dir
|
9
|
-
end
|
10
|
-
|
11
|
-
def format
|
12
|
-
"rpm"
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def extract_rpm(archive, dir)
|
18
|
-
file = File.open(archive, "rb")
|
19
|
-
rpm = rpm_class.new(file)
|
20
|
-
content = rpm.payload.read
|
21
|
-
path = target_path(archive, rpm.tags, dir)
|
22
|
-
|
23
|
-
File.write(path, content)
|
24
|
-
ensure
|
25
|
-
file.close
|
26
|
-
end
|
27
|
-
|
28
|
-
def rpm_class
|
29
|
-
@rpm_class ||= begin
|
30
|
-
require "arr-pm"
|
31
|
-
RPM::File
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def target_path(archive, tags, dir)
|
36
|
-
archive_format = tags[:payloadformat]
|
37
|
-
compression_format = tags[:payloadcompressor] == "gzip" ? "gz" : tags[:payloadcompressor]
|
38
|
-
basename = File.basename(archive, ".*")
|
39
|
-
filename = basename + "." + archive_format + "." + compression_format
|
40
|
-
File.join(dir, filename)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module Fontist
|
2
|
-
module Import
|
3
|
-
module Extractors
|
4
|
-
class SevenZipExtractor < Extractor
|
5
|
-
def extract
|
6
|
-
dir = Dir.mktmpdir
|
7
|
-
extract_7z(@archive, dir)
|
8
|
-
dir
|
9
|
-
end
|
10
|
-
|
11
|
-
def try
|
12
|
-
File.open(@archive, "rb") do |file|
|
13
|
-
reader.open(file)
|
14
|
-
end
|
15
|
-
|
16
|
-
true
|
17
|
-
rescue StandardError => e
|
18
|
-
return false if e.message.start_with?("Invalid file format")
|
19
|
-
|
20
|
-
raise
|
21
|
-
end
|
22
|
-
|
23
|
-
def format
|
24
|
-
"seven_zip"
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def extract_7z(archive, dir)
|
30
|
-
File.open(archive, "rb") do |file|
|
31
|
-
reader.extract_all(file, dir)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def reader
|
36
|
-
@reader ||= begin
|
37
|
-
require "seven_zip_ruby"
|
38
|
-
SevenZipRuby::Reader
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module Fontist
|
2
|
-
module Import
|
3
|
-
module Extractors
|
4
|
-
class TarExtractor < Extractor
|
5
|
-
def extract
|
6
|
-
dir = Dir.mktmpdir
|
7
|
-
extract_tar(@archive, dir)
|
8
|
-
dir
|
9
|
-
end
|
10
|
-
|
11
|
-
def format
|
12
|
-
"tar"
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def extract_tar(archive, dir)
|
18
|
-
archive_file = File.open(archive, "rb")
|
19
|
-
reader_class.new(archive_file) do |tar|
|
20
|
-
tar.each do |tarfile|
|
21
|
-
save_tar_file(tarfile, dir)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def reader_class
|
27
|
-
@reader_class ||= begin
|
28
|
-
require "rubygems/package"
|
29
|
-
Gem::Package::TarReader
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def save_tar_file(file, dir)
|
34
|
-
path = File.join(dir, file.full_name)
|
35
|
-
|
36
|
-
if file.directory?
|
37
|
-
FileUtils.mkdir_p(path)
|
38
|
-
else
|
39
|
-
File.open(path, "wb") do |f|
|
40
|
-
f.print(file.read)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require "zip"
|
2
|
-
|
3
|
-
module Fontist
|
4
|
-
module Import
|
5
|
-
module Extractors
|
6
|
-
class ZipExtractor < Extractor
|
7
|
-
def extract
|
8
|
-
dir = Dir.mktmpdir
|
9
|
-
extract_zip(@archive, dir)
|
10
|
-
dir
|
11
|
-
end
|
12
|
-
|
13
|
-
def format
|
14
|
-
"zip"
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def extract_zip(archive, dir)
|
20
|
-
Zip::File.open(archive) do |zip_file|
|
21
|
-
zip_file.each do |entry|
|
22
|
-
path = File.join(dir, entry.name)
|
23
|
-
FileUtils.mkdir_p(File.dirname(path))
|
24
|
-
entry.extract(path)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,199 +0,0 @@
|
|
1
|
-
# code is obtained from https://github.com/jordansissel/ruby-arr-pm/blob/8071591173ebb90dea27d5acfdde69a37dcb2744/cpio.rb
|
2
|
-
# rubocop:disable all
|
3
|
-
class BoundedIO
|
4
|
-
attr_reader :length
|
5
|
-
attr_reader :remaining
|
6
|
-
|
7
|
-
def initialize(io, length, &eof_callback)
|
8
|
-
@io = io
|
9
|
-
@length = length
|
10
|
-
@remaining = length
|
11
|
-
|
12
|
-
@eof_callback = eof_callback
|
13
|
-
@eof = false
|
14
|
-
end
|
15
|
-
|
16
|
-
def read(size=nil)
|
17
|
-
return nil if eof?
|
18
|
-
size = @remaining if size.nil?
|
19
|
-
data = @io.read(size)
|
20
|
-
@remaining -= data.bytesize
|
21
|
-
eof?
|
22
|
-
data
|
23
|
-
end
|
24
|
-
|
25
|
-
def sysread(size)
|
26
|
-
raise EOFError, "end of file reached" if eof?
|
27
|
-
read(size)
|
28
|
-
end
|
29
|
-
|
30
|
-
def eof?
|
31
|
-
return false if @remaining > 0
|
32
|
-
return @eof if @eof
|
33
|
-
|
34
|
-
@eof_callback.call
|
35
|
-
@eof = true
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
module CPIO
|
40
|
-
FIELDS = [
|
41
|
-
:magic, :ino, :mode, :uid, :gid, :nlink, :mtime, :filesize, :devmajor,
|
42
|
-
:devminor, :rdevmajor, :rdevminor, :namesize, :check
|
43
|
-
]
|
44
|
-
end
|
45
|
-
|
46
|
-
class CPIO::ASCIIReader
|
47
|
-
FIELD_SIZES = {
|
48
|
-
:magic => 6,
|
49
|
-
:ino => 8,
|
50
|
-
:mode => 8,
|
51
|
-
:uid => 8,
|
52
|
-
:gid => 8,
|
53
|
-
:nlink => 8,
|
54
|
-
:mtime => 8,
|
55
|
-
:filesize => 8,
|
56
|
-
:devmajor => 8,
|
57
|
-
:devminor => 8,
|
58
|
-
:rdevmajor => 8,
|
59
|
-
:rdevminor => 8,
|
60
|
-
:namesize => 8,
|
61
|
-
:check => 8
|
62
|
-
}
|
63
|
-
HEADER_LENGTH = FIELD_SIZES.reduce(0) { |m, (_, v)| m + v }
|
64
|
-
HEADER_PACK = FIELD_SIZES.collect { |_, v| "A#{v}" }.join
|
65
|
-
|
66
|
-
FIELD_ORDER = [
|
67
|
-
:magic, :ino, :mode, :uid, :gid, :nlink, :mtime, :filesize, :devmajor,
|
68
|
-
:devminor, :rdevmajor, :rdevminor, :namesize, :check
|
69
|
-
]
|
70
|
-
|
71
|
-
def initialize(io)
|
72
|
-
@io = io
|
73
|
-
end
|
74
|
-
|
75
|
-
private
|
76
|
-
|
77
|
-
def io
|
78
|
-
@io
|
79
|
-
end
|
80
|
-
|
81
|
-
def each(&block)
|
82
|
-
while true
|
83
|
-
entry = read
|
84
|
-
break if entry.nil?
|
85
|
-
# The CPIO format has the end-of-stream marker as a file called "TRAILER!!!"
|
86
|
-
break if entry.name == "TRAILER!!!"
|
87
|
-
block.call(entry, entry.file)
|
88
|
-
verify_correct_read(entry) unless entry.directory?
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def verify_correct_read(entry)
|
93
|
-
# Read and throw away the whole file if not read at all.
|
94
|
-
entry.file.tap do |file|
|
95
|
-
if file.nil? || file.remaining == 0
|
96
|
-
# All OK! :)
|
97
|
-
elsif file.remaining == file.length
|
98
|
-
file.read(16384) while !file.eof?
|
99
|
-
else
|
100
|
-
# The file was only partially read? This should be an error by the
|
101
|
-
# user.
|
102
|
-
consumed = file.length - file.remaining
|
103
|
-
raise BadState, "Only #{consumed} bytes were read of the #{file.length} byte file: #{entry.name}"
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def read
|
109
|
-
entry = CPIOEntry.new
|
110
|
-
header = io.read(HEADER_LENGTH)
|
111
|
-
return nil if header.nil?
|
112
|
-
FIELD_ORDER.zip(header.unpack(HEADER_PACK)).each do |field, value|
|
113
|
-
entry.send("#{field}=", value.to_i(16))
|
114
|
-
end
|
115
|
-
|
116
|
-
entry.validate
|
117
|
-
entry.mtime = Time.at(entry.mtime)
|
118
|
-
read_name(entry, @io)
|
119
|
-
read_file(entry, @io)
|
120
|
-
entry
|
121
|
-
end
|
122
|
-
|
123
|
-
def read_name(entry, io)
|
124
|
-
entry.name = io.read(entry.namesize - 1) # - 1 for null terminator
|
125
|
-
nul = io.read(1)
|
126
|
-
raise ArgumentError, "Corrupt CPIO or bug? Name null terminator was not null: #{nul.inspect}" if nul != "\0"
|
127
|
-
padding_data = io.read(padding_name(entry))
|
128
|
-
# Padding should be all null bytes
|
129
|
-
if padding_data != ("\0" * padding_data.bytesize)
|
130
|
-
raise ArgumentError, "Corrupt CPIO or bug? Name null padding was #{padding_name(entry)} bytes: #{padding_data.inspect}"
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def read_file(entry, io)
|
135
|
-
if entry.directory?
|
136
|
-
entry.file = nil
|
137
|
-
#read_file_padding(entry, io)
|
138
|
-
nil
|
139
|
-
else
|
140
|
-
entry.file = BoundedIO.new(io, entry.filesize) do
|
141
|
-
read_file_padding(entry, io)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
def read_file_padding(entry, io)
|
147
|
-
padding_data = io.read(padding_file(entry))
|
148
|
-
if padding_data != ("\0" * padding_data.bytesize)
|
149
|
-
raise ArgumentError, "Corrupt CPIO or bug? File null padding was #{padding_file(entry)} bytes: #{padding_data.inspect}"
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def padding_name(entry)
|
154
|
-
# name padding is padding up to a multiple of 4 after header+namesize
|
155
|
-
-(HEADER_LENGTH + entry.namesize) % 4
|
156
|
-
end
|
157
|
-
|
158
|
-
def padding_file(entry)
|
159
|
-
(-(HEADER_LENGTH + entry.filesize + 2) % 4)
|
160
|
-
end
|
161
|
-
public(:each)
|
162
|
-
end
|
163
|
-
|
164
|
-
class CPIOEntry
|
165
|
-
CPIO::FIELDS.each do |field|
|
166
|
-
attr_accessor field
|
167
|
-
end
|
168
|
-
|
169
|
-
attr_accessor :name
|
170
|
-
attr_accessor :file
|
171
|
-
|
172
|
-
DIRECTORY_FLAG = 0040000
|
173
|
-
|
174
|
-
def validate
|
175
|
-
raise "Invalid magic #{magic.inspect}" if magic != 0x070701
|
176
|
-
raise "Invalid ino #{ino.inspect}" if ino < 0
|
177
|
-
raise "Invalid mode #{mode.inspect}" if mode < 0
|
178
|
-
raise "Invalid uid #{uid.inspect}" if uid < 0
|
179
|
-
raise "Invalid gid #{gid.inspect}" if gid < 0
|
180
|
-
raise "Invalid nlink #{nlink.inspect}" if nlink < 0
|
181
|
-
raise "Invalid mtime #{mtime.inspect}" if mtime < 0
|
182
|
-
raise "Invalid filesize #{filesize.inspect}" if filesize < 0
|
183
|
-
raise "Invalid devmajor #{devmajor.inspect}" if devmajor < 0
|
184
|
-
raise "Invalid devminor #{devminor.inspect}" if devminor < 0
|
185
|
-
raise "Invalid rdevmajor #{rdevmajor.inspect}" if rdevmajor < 0
|
186
|
-
raise "Invalid rdevminor #{rdevminor.inspect}" if rdevminor < 0
|
187
|
-
raise "Invalid namesize #{namesize.inspect}" if namesize < 0
|
188
|
-
raise "Invalid check #{check.inspect}" if check < 0
|
189
|
-
end # def validate
|
190
|
-
|
191
|
-
def read(*args)
|
192
|
-
return nil if directory?
|
193
|
-
file.read(*args)
|
194
|
-
end
|
195
|
-
|
196
|
-
def directory?
|
197
|
-
mode & DIRECTORY_FLAG > 0
|
198
|
-
end
|
199
|
-
end
|