Skip to content

Commit

Permalink
refactor: tweak the OCFRersources closing code
Browse files Browse the repository at this point in the history
- Introduce an `OCFResources` interface (currently only
  implemented by `OCFZipResources`) to prepare for other
  kink of OCF resources like unpackaged EPUBs with no
  intermediary ZIP archive.
- call the `close()` method in a `finally` block
  • Loading branch information
rdeltour committed Dec 30, 2024
1 parent 96a6e1c commit 0dae4f2
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 153 deletions.
302 changes: 155 additions & 147 deletions src/main/java/com/adobe/epubcheck/ocf/OCFChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,177 +74,184 @@ public void check()
// It will be augmented with detected validation version, profile, etc.
OCFCheckerState state = new OCFCheckerState(context);

// Check the EPUB file (zip)
// -------------------------
//
checkZipFile();

// Check the OCF Container file structure
// --------------------------------------
//
if (!checkContainerStructure(state))
{
return;
}
;
OCFContainer container = state.getContainer();

//
// Check the mimetype file
// ------------------------------
//
checkMimetypeFile(state);

//
// Check the container.xml file
// ----------------------------
//
if (!checkContainerFile(state))
try
{
return;
}
List<URL> packageDocs = state.getPackageDocuments();
// Check the EPUB file (zip)
// -------------------------
//
checkZipFile();

// Check the OCF Container file structure
// --------------------------------------
//
if (!checkContainerStructure(state))
{
return;
}
;
OCFContainer container = state.getContainer();

//
// Check the mimetype file
// ------------------------------
//
checkMimetypeFile(state);

//
// Check the container.xml file
// ----------------------------
//
if (!checkContainerFile(state))
{
return;
}
List<URL> packageDocs = state.getPackageDocuments();

//
// Check the declared package documents
// ------------------------------------
//
if (!checkDeclaredPackageDocuments(state))
{
return;
}
//
// Check the declared package documents
// ------------------------------------
//
if (!checkDeclaredPackageDocuments(state))
{
return;
}

//
// Override the context-provided version and profile
// by what is actually declared in the publication
// -------------------------------------------------
EPUBVersion validationVersion = checkPublicationVersion(state);
state.setVersion(validationVersion);
state.setProfile(checkPublicationProfile(state, validationVersion));

//
// Check if there are multiple renditions
// --------------------------------------
// EPUB 2.0 says there SHOULD be only one OPS rendition
if (validationVersion == EPUBVersion.VERSION_2 && packageDocs.size() > 1)
{
report.message(MessageId.PKG_013, OCFMetaFile.CONTAINER.asLocation(container));
}
// EPUB 3.0 Multiple Renditions recommends the presence of a metadata file
if (validationVersion == EPUBVersion.VERSION_3 && packageDocs.size() > 1)
{
state.addProperty(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.MULTIPLE_RENDITION));
if (!OCFMetaFile.METADATA.isPresent(container))
//
// Override the context-provided version and profile
// by what is actually declared in the publication
// -------------------------------------------------
EPUBVersion validationVersion = checkPublicationVersion(state);
state.setVersion(validationVersion);
state.setProfile(checkPublicationProfile(state, validationVersion));

//
// Check if there are multiple renditions
// --------------------------------------
// EPUB 2.0 says there SHOULD be only one OPS rendition
if (validationVersion == EPUBVersion.VERSION_2 && packageDocs.size() > 1)
{
report.message(MessageId.RSC_019, EPUBLocation.of(context));
report.message(MessageId.PKG_013, OCFMetaFile.CONTAINER.asLocation(container));
}
if (state.getMappingDocument().isPresent())
// EPUB 3.0 Multiple Renditions recommends the presence of a metadata file
if (validationVersion == EPUBVersion.VERSION_3 && packageDocs.size() > 1)
{
new MappingDocumentChecker(
state.context().mimetype("application/xhtml+xml").url(state.getMappingDocument().get())
.addProperty(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.RENDITION_MAPPING))
.build()).check();
state.addProperty(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.MULTIPLE_RENDITION));
if (!OCFMetaFile.METADATA.isPresent(container))
{
report.message(MessageId.RSC_019, EPUBLocation.of(context));
}
if (state.getMappingDocument().isPresent())
{
new MappingDocumentChecker(
state.context().mimetype("application/xhtml+xml")
.url(state.getMappingDocument().get())
.addProperty(
EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.RENDITION_MAPPING))
.build()).check();
}
}
}

//
// Check other META-INF files
// ------------------------------
//
checkEncryptionFile(state);
checkOtherMetaFiles(state);
container = state.getContainer();

//
// Check each Publication (i.e. Package Document)
// ----------------------------------------------
//
List<OPFHandler> opfHandlers = new LinkedList<OPFHandler>();
for (URL packageDoc : packageDocs)
{
ValidationContextBuilder opfContext = state.context().url(packageDoc)
.mimetype(MIMEType.PACKAGE_DOC.toString()).featureReport(new FeatureReport());
//
// Check other META-INF files
// ------------------------------
//
checkEncryptionFile(state);
checkOtherMetaFiles(state);
container = state.getContainer();

//
// Check each Publication (i.e. Package Document)
// ----------------------------------------------
//
List<OPFHandler> opfHandlers = new LinkedList<OPFHandler>();
for (URL packageDoc : packageDocs)
{
ValidationContextBuilder opfContext = state.context().url(packageDoc)
.mimetype(MIMEType.PACKAGE_DOC.toString()).featureReport(new FeatureReport());

opfContext.container(container);
opfContext.pubTypes(state.getPublicationTypes(packageDoc));
opfContext.container(container);
opfContext.pubTypes(state.getPublicationTypes(packageDoc));

Checker opfChecker = CheckerFactory.newChecker(opfContext.build());
assert opfChecker instanceof OPFChecker;
opfChecker.check();
opfHandlers.add(((OPFChecker) opfChecker).getOPFHandler());
}
Checker opfChecker = CheckerFactory.newChecker(opfContext.build());
assert opfChecker instanceof OPFChecker;
opfChecker.check();
opfHandlers.add(((OPFChecker) opfChecker).getOPFHandler());
}

//
// Check container consistency with Package Documents content
// ----------------------------------------------------------
//
//
// Check container consistency with Package Documents content
// ----------------------------------------------------------
//

for (final URL resource : container.getResources())
{
String path = resource.path().substring(1);
// if the entry is not in the whitelist (META-INF/* + mimetype)
// and not declared in (one of) the OPF document(s)

// FIXME 2022 add a method to register known files in state, to fix #1115
// (in this case, only the last mapping document is considered known)
if (!path.startsWith("META-INF/") && !path.startsWith("META-INF\\")
&& !path.equals("mimetype") && !state.isDeclared(resource)
&& !Iterables.tryFind(opfHandlers, new Predicate<OPFHandler>()
{
@Override
public boolean apply(OPFHandler opfHandler)
{
// found if declared as an OPF item
// or in an EPUB 3 link element
return opfHandler.getItemByURL(resource).isPresent()
|| (validationVersion == EPUBVersion.VERSION_3
&& ((OPFHandler30) opfHandler).getLinkedResources().hasResource(resource));
}
}).isPresent())
for (final URL resource : container.getResources())
{
report.message(MessageId.OPF_003, EPUBLocation.of(context), path);
}
String path = resource.path().substring(1);
// if the entry is not in the whitelist (META-INF/* + mimetype)
// and not declared in (one of) the OPF document(s)

// FIXME 2022 add a method to register known files in state, to fix
// #1115
// (in this case, only the last mapping document is considered known)
if (!path.startsWith("META-INF/") && !path.startsWith("META-INF\\")
&& !path.equals("mimetype") && !state.isDeclared(resource)
&& !Iterables.tryFind(opfHandlers, new Predicate<OPFHandler>()
{
@Override
public boolean apply(OPFHandler opfHandler)
{
// found if declared as an OPF item
// or in an EPUB 3 link element
return opfHandler.getItemByURL(resource).isPresent()
|| (validationVersion == EPUBVersion.VERSION_3
&& ((OPFHandler30) opfHandler).getLinkedResources().hasResource(resource));
}
}).isPresent())
{
report.message(MessageId.OPF_003, EPUBLocation.of(context), path);
}

// check obfuscated resource are Font Core Media Types
if (state.isObfuscated(resource))
{
for (OPFHandler opf : opfHandlers)
// check obfuscated resource are Font Core Media Types
if (state.isObfuscated(resource))
{
// try to find the first Package Document where the entry is
// declared
Optional<OPFItem> item = opf.getItemByURL(resource);
if (item.isPresent())
for (OPFHandler opf : opfHandlers)
{
// report if it is not a font core media type
if (!OPFChecker30.isBlessedFontType(item.get().getMimeType()))
// try to find the first Package Document where the entry is
// declared
Optional<OPFItem> item = opf.getItemByURL(resource);
if (item.isPresent())
{
report.message(MessageId.PKG_026, state.getObfuscationLocation(resource),
item.get().getMimeType(), opf.getPath());
// report if it is not a font core media type
if (!OPFChecker30.isBlessedFontType(item.get().getMimeType()))
{
report.message(MessageId.PKG_026, state.getObfuscationLocation(resource),
item.get().getMimeType(), opf.getPath());
}
break;
}
break;
}
}
}
}

//
// Check other file properties
// ---------------------------
//
checkFileExtension(state);

// Close zip file to free resource
if (state.getZipResources() != null)
//
// Check other file properties
// ---------------------------
//
checkFileExtension(state);
} finally
{
try
// Close resources
if (state.getResources() != null)
{
state.getZipResources().close();
}
catch (Exception e)
{
// FIXME 2023 - Inability to close zip file should be handled
try
{
state.getResources().close();
} catch (IOException e)
{
throw new RuntimeException(e);
}
}
}

}

private boolean checkContainerFile(OCFCheckerState state)
Expand Down Expand Up @@ -278,14 +285,15 @@ private boolean checkContainerStructure(OCFCheckerState state)
// FIXME 2022 build resourcesProvider depending on MIME type
// Get a container
OCFZipResources resourcesProvider = new OCFZipResources(context.url);
// Store the OCFZipResources object so it can be closed later
state.setZipResources(resourcesProvider);
// Set to store the normalized paths for duplicate checks
final Set<String> normalizedPaths = new HashSet<>();
// Lists to store the container entries for later empty directory check
final List<String> filePaths = new LinkedList<>();
final List<String> directoryPaths = new LinkedList<>();

// Store the OCFZipResources object so it can be closed later
state.setResources(resourcesProvider);

// Loop through the entries
for (OCFResource resource : resourcesProvider)
{
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/com/adobe/epubcheck/ocf/OCFCheckerState.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class OCFCheckerState
private final ImmutableList.Builder<URL> packageDocuments = ImmutableList.builder();
private URL mappingDocument;

private OCFZipResources zipResources = null;
private OCFResources resources = null;

private final Map<URL, EPUBLocation> obfuscated = new HashMap<>();
private final Map<URL, Set<PublicationType>> publicationTypes = new LinkedHashMap<>();
Expand Down Expand Up @@ -86,14 +86,14 @@ public void addResource(OCFResource resource)
containerNeedsRebuild = true;
}

public OCFZipResources getZipResources()
public OCFResources getResources()
{
return zipResources;
return resources;
}

public void setZipResources(OCFZipResources zipResources)
public void setResources(OCFResources resources)
{
this.zipResources = zipResources;
this.resources = resources;
}

public void addRootfile(String mediaType, URL resource)
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/com/adobe/epubcheck/ocf/OCFResources.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.adobe.epubcheck.ocf;

import java.io.IOException;

public interface OCFResources extends Iterable<OCFResource>
{
public void close()
throws IOException;
}
2 changes: 1 addition & 1 deletion src/main/java/com/adobe/epubcheck/ocf/OCFZipResources.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import io.mola.galimatias.URL;

public class OCFZipResources implements Iterable<OCFResource>
public class OCFZipResources implements OCFResources
{
private final ZipFile zip;

Expand Down

0 comments on commit 0dae4f2

Please sign in to comment.