From ff122556ead7895560c8309a2456424b875426f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Menu?= Date: Thu, 13 Jun 2024 15:37:00 +0200 Subject: [PATCH] Only normalize when comparing --- .../java/org/readium/r2/lcp/LcpDecryptor.kt | 3 ++- .../navigator/epub/EpubNavigatorFragment.kt | 4 ++-- .../r2/navigator/extensions/Publication.kt | 6 +++--- .../org/readium/r2/shared/publication/Href.kt | 2 +- .../org/readium/r2/shared/publication/Link.kt | 2 +- .../readium/r2/shared/publication/Manifest.kt | 2 +- .../java/org/readium/r2/shared/util/Url.kt | 21 ++++++++++++++++--- .../readium/r2/shared/util/data/Caching.kt | 3 ++- .../util/resource/SingleResourceContainer.kt | 2 +- .../r2/shared/util/format/TestContainer.kt | 3 ++- .../r2/streamer/parser/audio/AudioParser.kt | 5 ++++- .../streamer/parser/epub/EpubDeobfuscator.kt | 5 ++++- .../r2/streamer/parser/image/ImageParser.kt | 3 ++- 13 files changed, 43 insertions(+), 18 deletions(-) diff --git a/readium/lcp/src/main/java/org/readium/r2/lcp/LcpDecryptor.kt b/readium/lcp/src/main/java/org/readium/r2/lcp/LcpDecryptor.kt index 0032b014fe..0f7d70c0c7 100644 --- a/readium/lcp/src/main/java/org/readium/r2/lcp/LcpDecryptor.kt +++ b/readium/lcp/src/main/java/org/readium/r2/lcp/LcpDecryptor.kt @@ -22,6 +22,7 @@ import org.readium.r2.shared.util.Try import org.readium.r2.shared.util.Url import org.readium.r2.shared.util.data.ReadError import org.readium.r2.shared.util.flatMap +import org.readium.r2.shared.util.getEquivalent import org.readium.r2.shared.util.getOrElse import org.readium.r2.shared.util.resource.FailureResource import org.readium.r2.shared.util.resource.Resource @@ -38,7 +39,7 @@ internal class LcpDecryptor( fun transform(url: Url, resource: Resource): Resource { return resource.flatMap { - val encryption = encryptionData[url] + val encryption = encryptionData.getEquivalent(url) // Checks if the resource is encrypted and whether the encryption schemes of the resource // and the DRM license are the same. diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/epub/EpubNavigatorFragment.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/epub/EpubNavigatorFragment.kt index 9d9428266d..ebeb6965f2 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/epub/EpubNavigatorFragment.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/epub/EpubNavigatorFragment.kt @@ -615,13 +615,13 @@ public class EpubNavigatorFragment internal constructor( listener?.onJumpToLocator(locator) - val href = locator.href.removeFragment().normalize() + val href = locator.href.removeFragment() fun setCurrent(resources: List) { val page = resources.withIndex().firstOrNull { (_, res) -> when (res) { is PageResource.EpubReflowable -> - res.link.url() == href + res.link.url().isEquivalent(href) is PageResource.EpubFxl -> res.leftUrl?.toString()?.endsWith(href.toString()) == true || res.rightUrl?.toString()?.endsWith( href.toString() diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/extensions/Publication.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/extensions/Publication.kt index 0d678b617a..c6bb63a78f 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/extensions/Publication.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/extensions/Publication.kt @@ -36,12 +36,12 @@ public fun Publication.normalizeLocator(locator: Locator): Locator { return if (self == null) { // Packaged publication locator.copy( - href = Url(locator.href.toString().removePrefix("/"))?.normalize() + href = Url(locator.href.toString().removePrefix("/")) ?: return locator ) } else { // Remote publication - // Check that the locator HREF relative to `self` exists int he manifest. - val relativeHref = self.relativize(locator.href).normalize() + // Check that the locator HREF relative to `self` exists in the manifest. + val relativeHref = self.relativize(locator.href) if (linkWithHref(relativeHref) != null) { locator.copy(href = relativeHref) } else { diff --git a/readium/shared/src/main/java/org/readium/r2/shared/publication/Href.kt b/readium/shared/src/main/java/org/readium/r2/shared/publication/Href.kt index 7183bb37ca..1287ac2b50 100644 --- a/readium/shared/src/main/java/org/readium/r2/shared/publication/Href.kt +++ b/readium/shared/src/main/java/org/readium/r2/shared/publication/Href.kt @@ -48,7 +48,7 @@ public class Href private constructor(private val href: Url) : Parcelable { public fun resolve( base: SharedUrl? = null, parameters: Map = emptyMap() - ): SharedUrl = href.resolve(base, parameters).normalize() + ): SharedUrl = href.resolve(base, parameters) /** * Indicates whether this HREF is templated. diff --git a/readium/shared/src/main/java/org/readium/r2/shared/publication/Link.kt b/readium/shared/src/main/java/org/readium/r2/shared/publication/Link.kt index c016899f46..864cbc3c6b 100644 --- a/readium/shared/src/main/java/org/readium/r2/shared/publication/Link.kt +++ b/readium/shared/src/main/java/org/readium/r2/shared/publication/Link.kt @@ -92,7 +92,7 @@ public data class Link( public fun url( base: Url? = null, parameters: Map = emptyMap() - ): Url = href.resolve(base, parameters).normalize() + ): Url = href.resolve(base, parameters) /** * List of URI template parameter keys, if the [Link] is templated. diff --git a/readium/shared/src/main/java/org/readium/r2/shared/publication/Manifest.kt b/readium/shared/src/main/java/org/readium/r2/shared/publication/Manifest.kt index d3b11e19e9..6237fa21dc 100644 --- a/readium/shared/src/main/java/org/readium/r2/shared/publication/Manifest.kt +++ b/readium/shared/src/main/java/org/readium/r2/shared/publication/Manifest.kt @@ -69,7 +69,7 @@ public data class Manifest( public fun linkWithHref(href: Url): Link? { fun List.deepLinkWithHref(href: Url): Link? { for (l in this) { - if (l.url() == href) { + if (l.url().normalize() == href) { return l } else { l.alternates.deepLinkWithHref(href)?.let { return it } diff --git a/readium/shared/src/main/java/org/readium/r2/shared/util/Url.kt b/readium/shared/src/main/java/org/readium/r2/shared/util/Url.kt index ac00af82db..3c4dda8518 100644 --- a/readium/shared/src/main/java/org/readium/r2/shared/util/Url.kt +++ b/readium/shared/src/main/java/org/readium/r2/shared/util/Url.kt @@ -210,6 +210,12 @@ public sealed class Url : Parcelable { return true } + /** + * Returns whether the receiver is equivalent to the given `url` after normalization. + */ + public fun isEquivalent(url: Url): Boolean = + normalize() == url.normalize() + override fun hashCode(): Int = uri.toString().hashCode() @@ -347,9 +353,8 @@ public fun Url.Companion.fromLegacyHref(href: String): Url? = * if we can't parse the URL. */ @InternalReadiumApi -public fun Url.Companion.fromEpubHref(href: String): Url? { - return (Url(href) ?: fromDecodedPath(href))?.normalize() -} +public fun Url.Companion.fromEpubHref(href: String): Url? = + Url(href) ?: fromDecodedPath(href) public fun File.toUrl(): AbsoluteUrl = checkNotNull(AbsoluteUrl(Uri.fromFile(this))) @@ -414,3 +419,13 @@ public value class FileExtension( */ public fun FileExtension?.appendToFilename(filename: String): String = this?.let { "$filename.$value" } ?: filename + +/** + * Returns the value of the first key matching `key` after normalization. + */ +public fun Map.getEquivalent(key: Url): T? = + get(key) ?: run { + val url = key.normalize() + keys.firstOrNull { it.normalize() == url } + ?.let { get(it) } + } diff --git a/readium/shared/src/main/java/org/readium/r2/shared/util/data/Caching.kt b/readium/shared/src/main/java/org/readium/r2/shared/util/data/Caching.kt index 04a15bbddd..85918b8840 100644 --- a/readium/shared/src/main/java/org/readium/r2/shared/util/data/Caching.kt +++ b/readium/shared/src/main/java/org/readium/r2/shared/util/data/Caching.kt @@ -8,6 +8,7 @@ package org.readium.r2.shared.util.data import org.readium.r2.shared.util.Try import org.readium.r2.shared.util.Url +import org.readium.r2.shared.util.getEquivalent internal class CachingReadable( private val source: Readable @@ -69,7 +70,7 @@ internal class CachingContainer( mutableMapOf() override fun get(url: Url): Readable? { - cache[url]?.let { return it } + cache.getEquivalent(url)?.let { return it } val entry = container[url] ?: return null diff --git a/readium/shared/src/main/java/org/readium/r2/shared/util/resource/SingleResourceContainer.kt b/readium/shared/src/main/java/org/readium/r2/shared/util/resource/SingleResourceContainer.kt index bdee552b5c..200a712ac2 100644 --- a/readium/shared/src/main/java/org/readium/r2/shared/util/resource/SingleResourceContainer.kt +++ b/readium/shared/src/main/java/org/readium/r2/shared/util/resource/SingleResourceContainer.kt @@ -18,7 +18,7 @@ public class SingleResourceContainer( override val entries: Set = setOf(entryUrl) override fun get(url: Url): Resource? { - if (url.removeFragment().removeQuery() != entryUrl) { + if (!url.removeFragment().removeQuery().isEquivalent(entryUrl)) { return null } diff --git a/readium/shared/src/test/java/org/readium/r2/shared/util/format/TestContainer.kt b/readium/shared/src/test/java/org/readium/r2/shared/util/format/TestContainer.kt index 2f39757888..539a1a807f 100644 --- a/readium/shared/src/test/java/org/readium/r2/shared/util/format/TestContainer.kt +++ b/readium/shared/src/test/java/org/readium/r2/shared/util/format/TestContainer.kt @@ -8,6 +8,7 @@ package org.readium.r2.shared.util.format import org.readium.r2.shared.util.Url import org.readium.r2.shared.util.data.Container +import org.readium.r2.shared.util.getEquivalent import org.readium.r2.shared.util.resource.Resource import org.readium.r2.shared.util.resource.StringResource @@ -25,7 +26,7 @@ class TestContainer( resources.keys override fun get(url: Url): Resource? = - resources[url]?.let { StringResource(it) } + resources.getEquivalent(url)?.let { StringResource(it) } override fun close() {} } diff --git a/readium/streamer/src/main/java/org/readium/r2/streamer/parser/audio/AudioParser.kt b/readium/streamer/src/main/java/org/readium/r2/streamer/parser/audio/AudioParser.kt index 59d16e642a..853ac3df01 100644 --- a/readium/streamer/src/main/java/org/readium/r2/streamer/parser/audio/AudioParser.kt +++ b/readium/streamer/src/main/java/org/readium/r2/streamer/parser/audio/AudioParser.kt @@ -6,6 +6,7 @@ package org.readium.r2.streamer.parser.audio +import org.readium.r2.shared.InternalReadiumApi import org.readium.r2.shared.publication.Link import org.readium.r2.shared.publication.LocalizedString import org.readium.r2.shared.publication.Manifest @@ -22,6 +23,7 @@ import org.readium.r2.shared.util.data.Container import org.readium.r2.shared.util.data.ReadError import org.readium.r2.shared.util.format.Format import org.readium.r2.shared.util.format.Specification +import org.readium.r2.shared.util.getEquivalent import org.readium.r2.shared.util.getOrElse import org.readium.r2.shared.util.logging.WarningLogger import org.readium.r2.shared.util.resource.Resource @@ -66,6 +68,7 @@ public class AudioParser( return finalizeParsing(container, readingOrderWithFormat, null) } + @OptIn(InternalReadiumApi::class) private suspend fun parseContainerAsset( asset: ContainerAsset ): Try { @@ -79,7 +82,7 @@ public class AudioParser( val readingOrderWithFormat = asset.container - .mapNotNull { url -> entryFormats[url]?.let { url to it } } + .mapNotNull { url -> entryFormats.getEquivalent(url)?.let { url to it } } .filter { (_, format) -> format.specification.specifications.any { it in audioSpecifications } } .sortedBy { it.first.toString() } diff --git a/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscator.kt b/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscator.kt index a1e5783505..d8e3538505 100644 --- a/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscator.kt +++ b/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscator.kt @@ -7,11 +7,13 @@ package org.readium.r2.streamer.parser.epub import kotlin.experimental.xor +import org.readium.r2.shared.InternalReadiumApi import org.readium.r2.shared.publication.encryption.Encryption import org.readium.r2.shared.util.Try import org.readium.r2.shared.util.Url import org.readium.r2.shared.util.data.ReadError import org.readium.r2.shared.util.data.ReadTry +import org.readium.r2.shared.util.getEquivalent import org.readium.r2.shared.util.resource.Resource import org.readium.r2.shared.util.resource.TransformingResource import org.readium.r2.shared.util.resource.flatMap @@ -26,10 +28,11 @@ internal class EpubDeobfuscator( private val encryptionData: Map ) { + @OptIn(InternalReadiumApi::class) @Suppress("Unused_parameter") fun transform(url: Url, resource: Resource): Resource = resource.flatMap { - val algorithm = encryptionData[url]?.algorithm + val algorithm = encryptionData.getEquivalent(url)?.algorithm if (algorithm != null && algorithm2length.containsKey(algorithm)) { DeobfuscatingResource(resource, algorithm) } else { diff --git a/readium/streamer/src/main/java/org/readium/r2/streamer/parser/image/ImageParser.kt b/readium/streamer/src/main/java/org/readium/r2/streamer/parser/image/ImageParser.kt index a65efef755..536f7e4eab 100644 --- a/readium/streamer/src/main/java/org/readium/r2/streamer/parser/image/ImageParser.kt +++ b/readium/streamer/src/main/java/org/readium/r2/streamer/parser/image/ImageParser.kt @@ -23,6 +23,7 @@ import org.readium.r2.shared.util.data.Container import org.readium.r2.shared.util.data.ReadError import org.readium.r2.shared.util.format.Format import org.readium.r2.shared.util.format.Specification +import org.readium.r2.shared.util.getEquivalent import org.readium.r2.shared.util.getOrElse import org.readium.r2.shared.util.logging.WarningLogger import org.readium.r2.shared.util.mediatype.MediaType @@ -81,7 +82,7 @@ public class ImageParser( val readingOrderWithFormat = asset.container - .mapNotNull { url -> entryFormats[url]?.let { url to it } } + .mapNotNull { url -> entryFormats.getEquivalent(url)?.let { url to it } } .filter { (_, format) -> format.specification.specifications.any { it in bitmapSpecifications } } .sortedBy { it.first.toString() }