/
ocf.rb
131 lines (118 loc) · 3.21 KB
/
ocf.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
require 'zip/zip'
module EeePub
# Class to create OCF
class OCF
# Class for 'container.xml' of OCF
class Container < ContainerItem
attr_accessor :rootfiles
# @param [String or Array or Hash]
#
# @example
# # with String
# EeePub::OCF::Container.new('container.opf')
#
# @example
# # with Array
# EeePub::OCF::Container.new(['container.opf', 'other.opf'])
#
# @example
# # with Hash
# EeePub::OCF::Container.new(
# :rootfiles => [
# {:full_path => 'container.opf', :media_type => 'application/oebps-package+xml'}
# ]
# )
def initialize(arg)
case arg
when String
set_values(
:rootfiles => [
{:full_path => arg, :media_type => guess_media_type(arg)}
]
)
when Array
# TODO: spec
set_values(
:rootfiles => arg.keys.map { |k|
filename = arg[k]
{:full_path => filename, :media_type => guess_media_type(filename)}
}
)
when Hash
set_values(arg)
end
end
private
def build_xml(builder)
builder.container :xmlns => "urn:oasis:names:tc:opendocument:xmlns:container", :version => "1.0" do
builder.rootfiles do
rootfiles.each do |i|
builder.rootfile convert_to_xml_attributes(i)
end
end
end
end
end
attr_accessor :dir, :container
# @param [Hash<Symbol, Object>] values the values of symbols and objects for OCF
#
# @example
# EeePub::OCF.new(
# :dir => '/path/to/dir',
# :container => 'container.opf'
# )
def initialize(values)
values.each do |k, v|
self.send(:"#{k}=", v)
end
end
# Set container
#
# @param [EeePub::OCF::Container or args for EeePub::OCF::Container]
def container=(arg)
if arg.is_a?(EeePub::OCF::Container)
@container = arg
else
# TODO: spec
@container = EeePub::OCF::Container.new(arg)
end
end
# Save as OCF
#
# @param [String] output_path the output file path of ePub
def save(output_path)
output_path = File.expand_path(output_path)
create_epub do
mimetype = Zip::ZipOutputStream::open(output_path) do |os|
os.put_next_entry("mimetype", nil, nil, Zip::ZipEntry::STORED, Zlib::NO_COMPRESSION)
os << "application/epub+zip"
end
zipfile = Zip::ZipFile.open(output_path)
Dir.glob('**/*').each do |path|
zipfile.add(path, path)
end
zipfile.commit
end
FileUtils.remove_entry_secure dir
end
# Stream OCF
#
# @return [String] streaming output of the zip/epub file.
def render
create_epub do
temp_file = Tempfile.new("ocf")
self.save(temp_file.path)
return temp_file.read
end
end
private
def create_epub
FileUtils.chdir(dir) do
meta_inf = 'META-INF'
FileUtils.mkdir_p(meta_inf)
container.save(File.join(meta_inf, 'container.xml'))
yield
end
end
end
end