File Coverage

blib/lib/EBook/EPUB/Container.pm
Criterion Covered Total %
statement 15 90 16.6
branch 0 18 0.0
condition n/a
subroutine 5 14 35.7
pod 3 8 37.5
total 23 130 17.6


line stmt bran cond sub pod time code
1             # Copyright (c) 2009, 2010 Oleksandr Tymoshenko <gonzo@bluezbox.com>
2             # All rights reserved.
3              
4             # Redistribution and use in source and binary forms, with or without
5             # modification, are permitted provided that the following conditions
6             # are met:
7             # 1. Redistributions of source code must retain the above copyright
8             # notice, this list of conditions and the following disclaimer.
9             # 2. Redistributions in binary form must reproduce the above copyright
10             # notice, this list of conditions and the following disclaimer in the
11             # documentation and/or other materials provided with the distribution.
12              
13             # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14             # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16             # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17             # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18             # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19             # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20             # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21             # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22             # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23             # SUCH DAMAGE.
24              
25             # OEPBS Container format implementation
26             # http://www.idpf.org/ocf/ocf1.0/download/ocf10.htm
27             package EBook::EPUB::Container;
28              
29 1     1   4934 use strict;
  1         2  
  1         33  
30 1     1   1015 use XML::Writer;
  1         18156  
  1         32  
31 1     1   4208 use IO::File;
  1         3300  
  1         151  
32 1     1   9 use File::Find;
  1         2  
  1         51  
33              
34 1     1   6 use Carp;
  1         3  
  1         2407  
35              
36             sub new
37             {
38 0     0 1   my ($class, %params) = @_;
39 0           my $self = {
40             root_files => [],
41             files => [],
42             encrypted_files => [],
43             };
44 0           return bless $self, $class;
45             }
46              
47             #
48             # Add root file (item in <rootfiles> element)
49             #
50             sub add_root_file
51             {
52 0     0 0   my ($self, $path, $mediatype) = @_;
53 0           push @{$self->{root_files}}, {
  0            
54             path => $path,
55             mediatype => $mediatype,
56             };
57             }
58              
59             #
60             # Add content. Recurse if it's directory
61             #
62             sub add_path
63             {
64 0     0 1   my ($self, $from_path, $container_path) = @_;
65              
66             # Closure to collect files recursively
67             my $file_cb = sub {
68 0     0     my $file = $File::Find::name;
69 0           my $dest = $file;
70 0           $dest =~ s/\Q$from_path\E/$container_path/;
71              
72             # XXX: UNIX only
73 0 0         if (-d $file) {
74 0           $dest .= "/";
75             }
76              
77 0 0         if (!is_valid_path($dest)) {
78 0           croak("Bad container path: $dest");
79 0           return;
80             }
81              
82 0           push @{$self->{files}}, {
  0            
83             frompath => $file,
84             containerpath => $dest,
85             }
86 0           };
87 0 0         if (-d $from_path) {
88             # XXX: UNIX only
89             # Strip unncessary slashes
90 0           $from_path =~ s/\/+$//g;
91 0           $container_path =~ s/\/+$//g;
92 0           find( { wanted => $file_cb, no_chdir => 1 }, $from_path);
93             }
94             else {
95 0 0         if (!is_valid_path($container_path)) {
96 0           croak("Bad container path: $container_path");
97 0           return;
98             }
99              
100 0           push @{$self->{files}}, {
  0            
101             frompath => $from_path,
102             containerpath => $container_path,
103             }
104             }
105            
106             }
107              
108             #
109             # Add encrypted file, at the moment it means font "encrypted" with
110             # Adobe content protection algorithm
111             #
112             sub add_encrypted_path
113             {
114 0     0 1   my ($self, $path) = @_;
115              
116 0 0         if (!is_valid_path($path)) {
117 0           croak("Bad container path: $path");
118 0           return;
119             }
120              
121 0           push @{$self->{encrypted_files}}, $path;
  0            
122             }
123              
124             #
125             # Check if file name conforms specs
126             # TODO: make conformant to spec
127             sub is_valid_path
128             {
129 0     0 0   my $path = shift;
130 0 0         return if($path =~ /META-INF/);
131              
132 0           return 1;
133             }
134              
135             #
136             # Generate container.xml for META-INF directory
137             #
138             sub write_container
139             {
140 0     0 0   my ($self, $outname) = @_;
141 0           my $container = new IO::File(">$outname");
142              
143 0 0         if (!defined($container)) {
144 0           return;
145             }
146              
147 0           my $writer = new XML::Writer(
148             OUTPUT => $container,
149             DATA_MODE => 1,
150             DATA_INDENT => 2,
151             );
152 0           $writer->xmlDecl("utf-8");
153 0           $writer->startTag( "container",
154             "xmlns" => "urn:oasis:names:tc:opendocument:xmlns:container",
155             "version" => "1.0",
156             );
157 0           $writer->startTag("rootfiles");
158 0           foreach my $rf (@{$self->{root_files}}) {
  0            
159 0           $writer->emptyTag("rootfile",
160             "full-path", $rf->{path},
161             "media-type", $rf->{mediatype},
162             );
163             }
164 0           $writer->endTag("rootfiles");
165 0           $writer->endTag("container");
166 0           $writer->end();
167 0           $container->close();
168              
169 0           return 1;
170             }
171              
172             sub has_encrypted_files
173             {
174 0     0 0   my ($self) = @_;
175 0 0         return 1 if (@{$self->{encrypted_files}});
  0            
176              
177             # No encrypted data
178 0           return;
179             }
180              
181             #
182             # Generate encryption.xml for META-INF directory
183             #
184             sub write_encryption
185             {
186 0     0 0   my ($self, $outname) = @_;
187 0           my $container = new IO::File(">$outname");
188              
189 0 0         if (!defined($container)) {
190 0           return;
191             }
192              
193 0           my $writer = new XML::Writer(
194             OUTPUT => $container,
195             DATA_MODE => 1,
196             DATA_INDENT => 2,
197             );
198 0           $writer->xmlDecl("utf-8");
199 0           $writer->startTag( "encryption",
200             "xmlns" => "urn:oasis:names:tc:opendocument:xmlns:container",
201             );
202 0           foreach my $rf (@{$self->{encrypted_files}}) {
  0            
203 0           $writer->startTag('EncryptedData',
204             'xmlns' => 'http://www.w3.org/2001/04/xmlenc#',
205             );
206 0           $writer->emptyTag('EncryptionMethod',
207             'Algorithm' => 'http://ns.adobe.com/pdf/enc#RC',
208             );
209 0           $writer->startTag('CipherData');
210 0           $writer->emptyTag('CipherReference',
211             'URI' => $rf,
212             );
213 0           $writer->endTag('CipherData');
214 0           $writer->endTag('EncryptedData');
215             }
216              
217 0           $writer->endTag("encryption");
218 0           $writer->end();
219 0           $container->close();
220              
221 0           return 1;
222             }
223              
224              
225              
226             1;
227              
228             __END__;
229              
230             =head1 NAME
231              
232             EBook::EPUB::Container
233              
234             =head1 SYNOPSIS
235              
236             Abstract OEPBS Container implementation
237              
238             my $container = EBook::EPUB::Container->new()
239             $container->add_path('/path/to/content.ncx', 'DATA/content.ncx');
240             $container->add_path('/path/to/page1.xhtml', 'DATA/page1.xhtml');
241             $container->add_path('/path/to/page2.xhtml', 'DATA/page2.xhtml');
242             $container->add_root_file('DATA/content.ncx');
243              
244             =head1 SUBROUTINES/METHODS
245              
246             =over 4
247              
248             =item new()
249              
250             Create new instance of EBook::EPUB::Container object
251              
252             =item add_path($file_path, $container_path)
253              
254             Add existing file into container
255              
256             =item add_encrypted_path($container_path)
257              
258             Mark file $container_path as encrypted. File should be already encrypted and
259             added. This function just marks it encrypted
260              
261             =item add_root_path($container_path)
262              
263             Set file in container to be root file
264              
265             =back
266              
267             =head1 AUTHOR
268              
269             Oleksandr Tymoshenko, E<lt>gonzo@bluezbox.comE<gt>
270              
271             =head1 BUGS
272              
273             Please report any bugs or feature requests to E<lt>gonzo@bluezbox.comE<gt>
274              
275             =head1 LICENSE AND COPYRIGHT
276              
277             Copyright 2009, 2010 Oleksandr Tymoshenko.
278              
279             L<http://bluezbox.com>
280              
281             This module is free software; you can redistribute it and/or
282             modify it under the terms of the BSD license. See the F<LICENSE> file
283             included with this distribution.