Skip to content

Commit

Permalink
Revamp format specifications and other changes (#500)
Browse files Browse the repository at this point in the history
  • Loading branch information
qnga committed Apr 30, 2024
1 parent 5a6a239 commit 2cc906c
Show file tree
Hide file tree
Showing 20 changed files with 343 additions and 362 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ import org.readium.r2.shared.util.data.decodeRwpm
import org.readium.r2.shared.util.data.decodeXml
import org.readium.r2.shared.util.data.readDecodeOrElse
import org.readium.r2.shared.util.flatMap
import org.readium.r2.shared.util.format.EpubSpecification
import org.readium.r2.shared.util.format.LcpLicenseSpecification
import org.readium.r2.shared.util.format.LcpSpecification
import org.readium.r2.shared.util.format.Specification
import org.readium.r2.shared.util.getOrElse
import org.readium.r2.shared.util.resource.Resource
import org.readium.r2.shared.util.resource.TransformingContainer
Expand All @@ -57,7 +55,7 @@ internal class LcpContentProtection(
allowUserInteraction: Boolean
): Try<ContentProtection.OpenResult, ContentProtection.OpenError> {
if (
!asset.format.conformsTo(LcpSpecification)
!asset.format.conformsTo(Specification.Lcp)
) {
return Try.failure(ContentProtection.OpenError.AssetNotSupported())
}
Expand Down Expand Up @@ -91,7 +89,7 @@ internal class LcpContentProtection(

val encryptionData =
when {
asset.format.conformsTo(EpubSpecification) -> parseEncryptionDataEpub(
asset.format.conformsTo(Specification.Epub) -> parseEncryptionDataEpub(
asset.container
)
else -> parseEncryptionDataRpf(asset.container)
Expand Down Expand Up @@ -151,7 +149,7 @@ internal class LcpContentProtection(
credentials: String?,
allowUserInteraction: Boolean
): Try<ContentProtection.OpenResult, ContentProtection.OpenError> {
if (!licenseAsset.format.conformsTo(LcpLicenseSpecification)) {
if (!licenseAsset.format.conformsTo(Specification.LcpLicense)) {
return Try.failure(ContentProtection.OpenError.AssetNotSupported())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ import org.readium.r2.shared.util.asset.Asset
import org.readium.r2.shared.util.asset.ContainerAsset
import org.readium.r2.shared.util.asset.ResourceAsset
import org.readium.r2.shared.util.data.Container
import org.readium.r2.shared.util.format.EpubSpecification
import org.readium.r2.shared.util.format.FormatSpecification
import org.readium.r2.shared.util.format.LcpLicenseSpecification
import org.readium.r2.shared.util.format.Specification
import org.readium.r2.shared.util.resource.Resource

private val LICENSE_IN_EPUB = Url("META-INF/license.lcpl")!!
Expand All @@ -44,11 +43,11 @@ internal fun createLicenseContainer(
formatSpecification: FormatSpecification
): WritableLicenseContainer =
when {
formatSpecification.conformsTo(EpubSpecification) -> FileZipLicenseContainer(
formatSpecification.conformsTo(Specification.Epub) -> FileZipLicenseContainer(
file.path,
LICENSE_IN_EPUB
)
formatSpecification.conformsTo(LcpLicenseSpecification) -> LcplLicenseContainer(file)
formatSpecification.conformsTo(Specification.LcpLicense) -> LcplLicenseContainer(file)
// Assuming it's a Readium WebPub package (e.g. audiobook, LCPDF, etc.) as a fallback
else -> FileZipLicenseContainer(file.path, LICENSE_IN_RPF)
}
Expand All @@ -70,7 +69,7 @@ internal fun createLicenseContainer(
resource: Resource,
formatSpecification: FormatSpecification
): LicenseContainer {
if (!formatSpecification.conformsTo(LcpLicenseSpecification)) {
if (!formatSpecification.conformsTo(Specification.LcpLicense)) {
throw LcpException(LcpError.Container.OpenFailed)
}

Expand All @@ -88,7 +87,7 @@ internal fun createLicenseContainer(
formatSpecification: FormatSpecification
): LicenseContainer {
val licensePath = when {
formatSpecification.conformsTo(EpubSpecification) -> LICENSE_IN_EPUB
formatSpecification.conformsTo(Specification.Epub) -> LICENSE_IN_EPUB
// Assuming it's a Readium WebPub package (e.g. audiobook, LCPDF, etc.) as a fallback
else -> LICENSE_IN_RPF
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,10 @@ import org.readium.r2.shared.util.FileExtension
import org.readium.r2.shared.util.Try
import org.readium.r2.shared.util.asset.Asset
import org.readium.r2.shared.util.asset.AssetRetriever
import org.readium.r2.shared.util.format.EpubSpecification
import org.readium.r2.shared.util.format.Format
import org.readium.r2.shared.util.format.FormatHints
import org.readium.r2.shared.util.format.FormatSpecification
import org.readium.r2.shared.util.format.LcpSpecification
import org.readium.r2.shared.util.format.ZipSpecification
import org.readium.r2.shared.util.format.Specification
import org.readium.r2.shared.util.getOrElse
import org.readium.r2.shared.util.mediatype.MediaType
import timber.log.Timber
Expand All @@ -71,14 +69,23 @@ internal class LicensesService(
licenseDocument: LicenseDocument,
publicationFile: File
): Try<Unit, LcpError> {
val hashIsCorrect = licenseDocument.publicationLink.hash
?.let { publicationFile.checkSha256(it) }

if (hashIsCorrect == false) {
return Try.failure(
LcpError.Network(Exception("Digest mismatch: download looks corrupted."))
)
}

val mediaType = licenseDocument.publicationLink.mediaType
val format = assetRetriever.sniffFormat(publicationFile, FormatHints(mediaType))
.getOrElse {
Format(
specification = FormatSpecification(
ZipSpecification,
EpubSpecification,
LcpSpecification
Specification.Zip,
Specification.Epub,
Specification.Lcp
),
mediaType = MediaType.EPUB,
fileExtension = FileExtension("epub")
Expand Down Expand Up @@ -152,13 +159,14 @@ internal class LicensesService(
onProgress = onProgress
)

license.publicationLink.hash
?.takeIf { destination.checkSha256(it) == false }
?.run {
throw LcpException(
LcpError.Network(Exception("Digest mismatch: download looks corrupted."))
)
}
val hashIsCorrect = license.publicationLink.hash
?.let { destination.checkSha256(it) }

if (hashIsCorrect == false) {
throw LcpException(
LcpError.Network(Exception("Digest mismatch: download looks corrupted."))
)
}

val format =
assetRetriever.sniffFormat(
Expand All @@ -179,9 +187,9 @@ internal class LicensesService(
is AssetRetriever.RetrieveError.FormatNotSupported -> {
Format(
specification = FormatSpecification(
ZipSpecification,
EpubSpecification,
LcpSpecification
Specification.Zip,
Specification.Epub,
Specification.Lcp
),
mediaType = MediaType.EPUB,
fileExtension = FileExtension("epub")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import org.readium.r2.shared.util.Error
import org.readium.r2.shared.util.Try
import org.readium.r2.shared.util.asset.Asset
import org.readium.r2.shared.util.asset.ContainerAsset
import org.readium.r2.shared.util.format.AdeptSpecification
import org.readium.r2.shared.util.format.LcpSpecification
import org.readium.r2.shared.util.format.Specification

/**
* [ContentProtection] implementation used as a fallback when detecting known DRMs
Expand All @@ -35,9 +34,9 @@ public class FallbackContentProtection : ContentProtection {
}

val protectionServiceFactory = when {
asset.format.conformsTo(LcpSpecification) ->
asset.format.conformsTo(Specification.Lcp) ->
Service.createFactory(Scheme.Lcp, "Readium LCP")
asset.format.conformsTo(AdeptSpecification) ->
asset.format.conformsTo(Specification.Adept) ->
Service.createFactory(Scheme.Adept, "Adobe ADEPT")
else ->
return Try.failure(ContentProtection.OpenError.AssetNotSupported())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ package org.readium.r2.shared.publication.services

import android.graphics.Bitmap
import android.util.Size
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.readium.r2.shared.extensions.scaleToFit
import org.readium.r2.shared.publication.Link
import org.readium.r2.shared.publication.Publication
Expand Down Expand Up @@ -76,15 +78,16 @@ internal class ResourceCoverService(
private val container: Container<Resource>
) : CoverService {

override suspend fun cover(): Bitmap? {
val resource = container[coverUrl]
?: return null
override suspend fun cover(): Bitmap? =
withContext(Dispatchers.IO) {
val resource = container[coverUrl]
?: return@withContext null

return resource
.read()
.flatMap { it.decodeBitmap() }
.getOrNull()
}
return@withContext resource
.read()
.flatMap { it.decodeBitmap() }
.getOrNull()
}

companion object {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,91 +61,93 @@ public value class FormatSpecification(public val specifications: Set<Specificat
specifications.containsAll(other.specifications)
}

public interface Specification

/*
* Archive specifications
*/
public object ZipSpecification : Specification
public object RarSpecification : Specification

/*
* Syntax specifications
*/
public object JsonSpecification : Specification
public object XmlSpecification : Specification

/*
* Publication manifest specifications
*/
public object W3cPubManifestSpecification : Specification
public object RwpmSpecification : Specification

/*
* Technical document specifications
*/
public object ProblemDetailsSpecification : Specification
public object LcpLicenseSpecification : Specification

/*
* Media format specifications
*/
public object PdfSpecification : Specification
public object HtmlSpecification : Specification

/*
* Drm specifications
*/
public object LcpSpecification : Specification
public object AdeptSpecification : Specification

/*
* Bitmap specifications
*/
public object AvifSpecification : Specification
public object BmpSpecification : Specification
public object GifSpecification : Specification
public object JpegSpecification : Specification
public object JxlSpecification : Specification
public object PngSpecification : Specification
public object TiffSpecification : Specification
public object WebpSpecification : Specification

/*
* Audio specifications
*/
public object AacSpecification : Specification
public object AiffSpecification : Specification
public object FlacSpecification : Specification
public object Mp4Specification : Specification
public object Mp3Specification : Specification
public object OggSpecification : Specification
public object OpusSpecification : Specification
public object WavSpecification : Specification
public object WebmSpecification : Specification

/*
* Publication package specifications
*/
public object EpubSpecification : Specification
public object RpfSpecification : Specification
public object LpfSpecification : Specification
public object InformalAudiobookSpecification : Specification
public object InformalComicSpecification : Specification

/*
* Opds specifications
*/
public object Opds1CatalogSpecification : Specification
public object Opds1EntrySpecification : Specification
public object Opds2CatalogSpecification : Specification
public object Opds2PublicationSpecification : Specification
public object OpdsAuthenticationSpecification : Specification

/*
* Language specifications
*/

public object JavaScriptSpecification : Specification

public object CssSpecification : Specification
public interface Specification {

public companion object {}

/*
* Archive specifications
*/
public object Zip : Specification
public object Rar : Specification

/*
* Syntax specifications
*/
public object Json : Specification
public object Xml : Specification

/*
* Publication manifest specifications
*/
public object W3cPubManifest : Specification
public object Rwpm : Specification

/*
* Technical document specifications
*/
public object ProblemDetails : Specification
public object LcpLicense : Specification

/*
* Media format specifications
*/
public object Pdf : Specification
public object Html : Specification

/*
* Drm specifications
*/
public object Lcp : Specification
public object Adept : Specification

/*
* Bitmap specifications
*/
public object Avif : Specification
public object Bmp : Specification
public object Gif : Specification
public object Jpeg : Specification
public object Jxl : Specification
public object Png : Specification
public object Tiff : Specification
public object Webp : Specification

/*
* Audio specifications
*/
public object Aac : Specification
public object Aiff : Specification
public object Flac : Specification
public object Mp4 : Specification
public object Mp3 : Specification
public object Ogg : Specification
public object Opus : Specification
public object Wav : Specification
public object Webm : Specification

/*
* Publication package specifications
*/
public object Epub : Specification
public object Rpf : Specification
public object Lpf : Specification
public object InformalAudiobook : Specification
public object InformalComic : Specification

/*
* Opds specifications
*/
public object Opds1Catalog : Specification
public object Opds1Entry : Specification
public object Opds2Catalog : Specification
public object Opds2Publication : Specification
public object OpdsAuthentication : Specification

/*
* Language specifications
*/

public object JavaScript : Specification
public object Css : Specification
}
Loading

0 comments on commit 2cc906c

Please sign in to comment.