diff --git a/platform/android/build.gradle b/platform/android/build.gradle
index 10e11e7..04c9b4a 100644
--- a/platform/android/build.gradle
+++ b/platform/android/build.gradle
@@ -1,46 +1,71 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-buildscript {
- repositories {
- jcenter()
- }
- dependencies {
- Properties properties = new Properties()
- properties.load(rootProject.file('local.properties').newDataInputStream())
+Properties properties = new Properties()
+properties.load(rootProject.file('local.properties').newDataInputStream())
- def ndkClang = properties.getProperty('readium.ndk_clang', "false")
- ndkClang = (ndkClang == "true") ? true : false;
- rootProject.ext.set('readium_ndk_clang', ndkClang)
+def ndkClang = properties.getProperty('readium.ndk_clang', "false")
+ndkClang = (ndkClang == "true") ? true : false;
+rootProject.ext.set('readium_ndk_clang', ndkClang)
- def ndkSkipX86 = properties.getProperty('readium.ndk_skipX86', "false")
- ndkSkipX86 = (ndkSkipX86 == "true") ? true : false;
- rootProject.ext.set('readium_ndk_skipX86', ndkSkipX86)
+def ndkSkipX86 = properties.getProperty('readium.ndk_skipX86', "false")
+ndkSkipX86 = (ndkSkipX86 == "true") ? true : false;
+rootProject.ext.set('readium_ndk_skipX86', ndkSkipX86)
- def ndkSkipARM = properties.getProperty('readium.ndk_skipARM', "false")
- ndkSkipARM = (ndkSkipARM == "true") ? true : false;
- rootProject.ext.set('readium_ndk_skipARM', ndkSkipARM)
+def ndkSkipARM = properties.getProperty('readium.ndk_skipARM', "false")
+ndkSkipARM = (ndkSkipARM == "true") ? true : false;
+rootProject.ext.set('readium_ndk_skipARM', ndkSkipARM)
- def extraCmake = properties.getProperty('readium.extra_cmake', null)
- rootProject.ext.set('readium_extra_cmake', extraCmake)
+def extraCmake = properties.getProperty('readium.extra_cmake', null)
+rootProject.ext.set('readium_extra_cmake', extraCmake)
- def readiumSdkLibDir = properties.getProperty('readium.sdk_lib_dir', null)
- rootProject.ext.set('readium_sdk_lib_dir', readiumSdkLibDir)
+def readiumSdkLibDir = properties.getProperty('readium.sdk_lib_dir', null)
+rootProject.ext.set('readium_sdk_lib_dir', readiumSdkLibDir)
- def readiumSdkIncludeDir = properties.getProperty('readium.sdk_include_dir', null)
- rootProject.ext.set('readium_sdk_include_dir', readiumSdkIncludeDir)
+def readiumSdkIncludeDir = properties.getProperty('readium.sdk_include_dir', null)
+rootProject.ext.set('readium_sdk_include_dir', readiumSdkIncludeDir)
- if (readiumSdkLibDir != null && readiumSdkIncludeDir != null) {
- rootProject.ext.set('readium_lcp_build_content_filter', true)
- } else {
- rootProject.ext.set('readium_lcp_build_content_filter', false)
- }
+def lcpBuildContentFilter = false
+if (readiumSdkLibDir != null && readiumSdkIncludeDir != null) {
+ lcpBuildContentFilter = true
+ rootProject.ext.set('readium_lcp_build_content_filter', true)
+} else {
+ rootProject.ext.set('readium_lcp_build_content_filter', false)
+}
- //https://bintray.com/android/android-tools/com.android.tools.build.gradle/view
- classpath "com.android.tools.build:gradle:2.3.3"
+// println "[[${project.name}]] (ROOT) Gradle Experimental: ${ndkExperimental}"
+println "[[${project.name}]] (ROOT) Skip ARM: ${ndkSkipARM}"
+println "[[${project.name}]] (ROOT) Skip x86: ${ndkSkipX86}"
+println "[[${project.name}]] (ROOT) Clang: ${ndkClang}"
+println "[[${project.name}]] (ROOT) readiumSdkLibDir: ${readiumSdkLibDir}"
+println "[[${project.name}]] (ROOT) readiumSdkIncludeDir: ${readiumSdkIncludeDir}"
+println "[[${project.name}]] (ROOT) extraCmake: ${extraCmake}"
+
+if (lcpBuildContentFilter) {
+ // include ':epub3'
+ // project(':epub3').projectDir = new File(rootProject.projectDir, './epub3')
+}
+
+buildscript {
+ repositories {
+ google()
+ maven {
+ url "https://maven.google.com"
+ }
+ mavenCentral()
+ jcenter()
+ }
+ dependencies {
+ // https://bintray.com/android/android-tools/com.android.tools.build.gradle/view
+ // https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google
+ classpath "com.android.tools.build:gradle:3.4.1"
}
}
allprojects {
repositories {
+ google()
+ maven {
+ url "https://maven.google.com"
+ }
+ mavenCentral()
jcenter()
}
}
diff --git a/platform/android/clean.sh b/platform/android/clean.sh
old mode 100644
new mode 100755
index e155c5b..eb2548c
--- a/platform/android/clean.sh
+++ b/platform/android/clean.sh
@@ -1,6 +1,9 @@
#!/bin/sh
rm -rf build
+rm -rf dist
+rm -rf lib/libs
+rm -rf lib/jniLibs
rm -rf lib/build
rm -rf lib/.externalNativeBuild
diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties
index a1347d8..256d859 100644
--- a/platform/android/gradle/wrapper/gradle-wrapper.properties
+++ b/platform/android/gradle/wrapper/gradle-wrapper.properties
@@ -3,7 +3,7 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-#https://services.gradle.org/distributions
-# GRADLE EXPERIMENTAL requires 3.3
-# GRADLE STABLE works with latest (4.4)
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
+# https://services.gradle.org/distributions
+# GRADLE EXPERIMENTAL requires 3.3 (the 4.1 + 0.11.1 combo fails, see https://stackoverflow.com/questions/47057160/ )
+# GRADLE STABLE works with latest 5.4.1
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
diff --git a/platform/android/lib/build.gradle b/platform/android/lib/build.gradle
index 02af41a..aa317f4 100644
--- a/platform/android/lib/build.gradle
+++ b/platform/android/lib/build.gradle
@@ -1,6 +1,10 @@
apply plugin: 'com.android.library'
repositories {
+ google()
+ maven {
+ url "https://maven.google.com"
+ }
mavenCentral()
jcenter()
}
@@ -34,34 +38,47 @@ if (rootProject.hasProperty("readium_sdk_include_dir")) {
if (rootProject.hasProperty("readium_lcp_build_content_filter")) {
lcpBuildContentFilter = rootProject.readium_lcp_build_content_filter
}
-println("extraCmake ${extraCmake}")
+
+// println "[[${project.name}]] (LIB) Gradle Experimental: ${ndk_experimental}"
+println "[[${project.name}]] (LIB) Skip ARM: ${ndk_skipARM}"
+println "[[${project.name}]] (LIB) Skip x86: ${ndk_skipX86}"
+println "[[${project.name}]] (LIB) Clang: ${ndk_clang}"
+println "[[${project.name}]] (LIB) extraCmake: ${extraCmake}"
+
def toolchain = ndk_clang ? "clang" : "gcc"
def stl = ndk_clang ? "c++_shared" : "gnustl_shared"
if (!lcpBuildContentFilter) {
try {
def epub3Dir = project(':epub3').projectDir
- readiumSdkLibDir = "${epub3Dir}/libs"
+ readiumSdkLibDir = "${epub3Dir}/jniLibs"
readiumSdkIncludeDir = "${epub3Dir}/include"
lcpBuildContentFilter = true
- println("Build with rsdk *")
+ println "[[${project.name}]] (LIB) lcpBuildContentFilter 2: ${lcpBuildContentFilter}"
} catch (UnknownProjectException e) {
- // No epub3 project is defined
- println("Build without rsdk")
+ println "[[${project.name}]] (LIB) lcpBuildContentFilter 3: ${lcpBuildContentFilter}"
}
} else {
- println("Build with rsdk")
+ println "[[${project.name}]] (LIB) lcpBuildContentFilter 1: ${lcpBuildContentFilter}"
}
-println "${lcpBuildContentFilter}"
-println "${readiumSdkLibDir}"
-println "${readiumSdkIncludeDir}"
+
+println "[[${project.name}]] (LIB) readiumSdkLibDir: ${readiumSdkLibDir}"
+println "[[${project.name}]] (LIB) readiumSdkIncludeDir: ${readiumSdkIncludeDir}"
+
+def currentBuildType
android {
- compileSdkVersion 26
- buildToolsVersion "27.0.3"
+ libraryVariants.all { variant ->
+ println "[[${project.name}]] (LIB) libraryVariant buildType: ${variant.buildType.name}"
+
+ // currentBuildType = variant.buildType.name
+ }
+
+ compileSdkVersion 28
+ buildToolsVersion "28.0.3"
defaultConfig {
minSdkVersion 19
- targetSdkVersion 26
+ targetSdkVersion 28
versionCode 1
versionName "1.0"
@@ -70,7 +87,8 @@ android {
if (lcpBuildContentFilter) {
targets "clientlib", "contentfilter", "lcp"
- arguments "-DFEATURES_READIUM=1",
+ arguments "-DCMAKE_JOB_POOLS:STRING=compile=6;link=6",
+ "-DFEATURES_READIUM=1",
"-DANDROID_PLATFORM=android-19",
"-DANDROID_TOOLCHAIN=${toolchain}",
"-DANDROID_STL=${stl}",
@@ -80,13 +98,23 @@ android {
} else {
targets "clientlib", "lcp-min"
- arguments "-DANDROID_PLATFORM=android-19",
+ arguments "-DCMAKE_JOB_POOLS:STRING=compile=6;link=6",
+ "-DANDROID_PLATFORM=android-19",
"-DANDROID_TOOLCHAIN=${toolchain}",
"-DANDROID_STL=${stl}",
- "-DRSDK_INCLUDE_DIR=${readiumSdkIncludeDir}",
- "-DRSDK_LIB_DIR=${readiumSdkLibDir}",
"-DEXTRA_CMAKE=${extraCmake}"
}
+
+ if (!ndk_skipARM && !ndk_skipX86) {
+ abiFilters = ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64']
+ } else {
+ if (!ndk_skipARM) {
+ abiFilters = ['armeabi-v7a', 'arm64-v8a']
+ }
+ if (!ndk_skipX86) {
+ abiFilters = ['x86', 'x86_64']
+ }
+ }
}
}
}
@@ -136,101 +164,109 @@ android {
}
}
+ flavorDimensions "version"
productFlavors {
- if (!ndk_skipARM) {
- arm7 {
+ if (!ndk_skipARM && !ndk_skipX86) {
+ 'armeabi-v7a--arm64-v8a--x86--x86_64' {
+ dimension "version"
ndk {
- abiFilter 'armeabi-v7a'
+ abiFilters = ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64']
}
}
- }
- if (!ndk_skipX86) {
- x86 {
- ndk {
- abiFilter 'x86'
+ } else {
+ if (!ndk_skipARM) {
+ 'armeabi-v7a--arm64-v8a' {
+ dimension "version"
+ ndk {
+ abiFilters = ['armeabi-v7a', 'arm64-v8a']
+ }
}
}
- }
- /*arm8 {
- ndk {
- abiFilters 'arm64-v8a'
- }
- }
- arm {
- ndk {
- abiFilter 'armeabi'
+ if (!ndk_skipX86) {
+ 'x86--x86_64' {
+ dimension "version"
+ ndk {
+ abiFilters = ['x86', 'x86_64']
+ }
+ }
}
}
- x86_64 {
- ndk {
- abiFilter 'x86_64'
- }
- }*/
}
-}
-build.doLast {
- println("Copy libs to dist directory")
- android.productFlavors.all { flavor ->
- android.buildTypes.all { buildType ->
- def abiFilter = flavor.ndk.abiFilters.first()
- def dstDirPath = "${project.projectDir}/../dist/${buildType.name.toLowerCase()}/${abiFilter}"
+ variantFilter { variant ->
+ println "[[${project.name}]] (LIB) variantFilter buildType: ${variant.buildType.name}"
- // Copy static libs
- def srcDirPath = "${project.projectDir}/.externalNativeBuild/cmake/${flavor.name}${buildType.name.capitalize()}/${abiFilter}"
-
- copy {
- from("${srcDirPath}") {
- include("*.a")
- }
- into("${dstDirPath}")
- }
-
- // Copy shared libs
- srcDirPath = "${project.projectDir}/build/intermediates/cmake/${flavor.name}/${buildType.name}/obj/${abiFilter}"
-
- copy {
- from("${srcDirPath}") {
- include("*.so")
- }
- into("${dstDirPath}")
- }
-
- // Copy aar
- srcDirPath = "${project.projectDir}/build/outputs/aar"
- def srcFilename = "lib-${flavor.name}-${buildType.name}.aar"
-
- copy {
- from("${srcDirPath}") {
- include(srcFilename)
- }
- into("${dstDirPath}")
- rename(srcFilename, "liblcp.aar")
- }
- }
+ // def names = variant.flavors*.name
+ // if (names.contains("xxx")) {
+ // setIgnore(true)
+ // }
}
}
clean.doFirst {
- println("Clean dist directory")
+ println "[[${project.name}]] (LIB) Remove *.so *.aar"
+
def dstDirPath = "${project.projectDir}/../dist/"
delete dstDirPath
+
+ dstDirPath = "${project.projectDir}/jniLibs/"
+ delete dstDirPath
}
task copyLibs {
doLast {
- println ("Copy shared library to libs")
+ println "[[${project.name}]] (LIB) Copy *.so *.aar (${currentBuildType})"
+
android.productFlavors.all { flavor ->
+ println " [[${project.name}]] (LIB) productFlavor (${flavor.name})"
+
android.buildTypes.all { buildType ->
- def abiFilter = flavor.ndk.abiFilters.first()
- def srcDirPath = "${project.projectDir}/build/intermediates/cmake/${flavor.name}/${buildType.name}/obj/${abiFilter}"
- def dstDirPath = "${project.projectDir}/libs/${abiFilter}"
+ println " [[${project.name}]] (LIB) buildType (${buildType.name})"
+
+ if (currentBuildType == buildType.name) {
- copy {
- from("${srcDirPath}") {
- include("liblcp.so")
+ def srcDirPath_AAR = "${project.projectDir}/build/outputs/aar"
+ def dstDirPath_AAR = "${project.projectDir}/../dist/${buildType.name.toUpperCase()}"
+ copy {
+ from("${srcDirPath_AAR}") {
+ include("lib-${flavor.name}-${buildType.name}.aar")
+ }
+ into("${dstDirPath_AAR}")
+ }
+
+ // def srcFilename = "lib-${flavor.name}-${buildType.name}.aar"
+ // copy {
+ // from("${srcDirPath_AAR}") {
+ // include(srcFilename)
+ // }
+ // into("${dstDirPath_AAR}")
+ // rename(srcFilename, "liblcp.aar")
+ // }
+
+ flavor.ndk.abiFilters.each { abiFilter ->
+ println " [[${project.name}]] (LIB) abiFilter (${abiFilter})"
+
+ def srcDirPath_LIBS = "${project.projectDir}/build/intermediates/cmake/${flavor.name}/${buildType.name}/obj/${abiFilter}"
+ def dstDirPath_LIBS = "${project.projectDir}/jniLibs/${buildType.name.toUpperCase()}/${abiFilter}"
+
+ copy {
+ from("${srcDirPath_LIBS}") {
+ include("*.so", "*.a")
+ }
+ into("${dstDirPath_LIBS}")
+ }
+
+ if (lcpBuildContentFilter) {
+ srcDirPath_LIBS = "${readiumSdkLibDir}/${buildType.name.toUpperCase()}/${abiFilter}"
+
+ copy {
+ from("${srcDirPath_LIBS}") {
+ include("*.so")
+ }
+ into("${dstDirPath_LIBS}")
+ }
+ }
}
- into("${dstDirPath}")
}
}
}
@@ -238,7 +274,64 @@ task copyLibs {
}
tasks.whenTaskAdded { task ->
- if (task.name.startsWith('assemble')) {
- task.dependsOn copyLibs
+ println "[[${project.name}]] (LIB) TaskAdded: ${task.name} (${currentBuildType})"
+
+ if (task.name.startsWith('compile')) {
+ if (lcpBuildContentFilter) {
+ // task.dependsOn ":epub3:buildMk"
+ if (task.name.toLowerCase().contains("debug")) {
+ task.dependsOn ":rsdk:assembleDebug"
+ } else {
+ task.dependsOn ":rsdk:assembleRelease"
+ }
+ }
+ }
+ if (task.name.startsWith("assemble")) {
+ task.finalizedBy copyLibs
}
}
+gradle.buildFinished { buildResult ->
+ println "[[${project.name}]] (LIB) buildFinished (${currentBuildType})"
+}
+
+gradle.taskGraph.whenReady { taskGraph ->
+ println "[[${project.name}]] (LIB) taskGraph ready"
+
+ // taskGraph.getAllTasks().last().finalizedBy copyLibs
+ taskGraph.getAllTasks().last().doLast {
+ println "[[${project.name}]] (LIB) last TASK (${currentBuildType})"
+ } // .dependsOn copyLibs
+
+ if (taskGraph.hasTask(buildRelease)) {
+ println "[[${project.name}]] (LIB) taskGraph RELEASE (build)"
+
+ currentBuildType = "release"
+ } else if (taskGraph.hasTask(buildDebug)) {
+ println "[[${project.name}]] (LIB) taskGraph DEBUG (build)"
+
+ currentBuildType = "debug"
+ } else {
+ if (taskGraph.hasTask(assembleRelease)) {
+ println "[[${project.name}]] (LIB) taskGraph RELEASE (assemble)"
+
+ currentBuildType = "release"
+ }
+ if (taskGraph.hasTask(assembleDebug)) {
+ println "[[${project.name}]] (LIB) taskGraph DEBUG (assemble)"
+
+ currentBuildType = "debug"
+ }
+ }
+}
+
+task buildRelease(type: GradleBuild, dependsOn: build) {
+}
+
+task buildDebug(type: GradleBuild, dependsOn: build) {
+}
+
+// task assembleRelease(type: GradleBuild, dependsOn: assemble) {
+// }
+
+// task assembleDebug(type: GradleBuild, dependsOn: assemble) {
+// }
diff --git a/platform/android/lib/src/main/AndroidManifest.xml b/platform/android/lib/src/main/AndroidManifest.xml
index 156d6aa..dae828e 100644
--- a/platform/android/lib/src/main/AndroidManifest.xml
+++ b/platform/android/lib/src/main/AndroidManifest.xml
@@ -20,8 +20,8 @@
android:versionCode="1"
android:versionName="0.1" >
-
+
+
+
diff --git a/platform/android/settings.gradle b/platform/android/settings.gradle
index 8c2a2e0..731f76f 100644
--- a/platform/android/settings.gradle
+++ b/platform/android/settings.gradle
@@ -1 +1,19 @@
include ':lib'
+
+Properties properties = new Properties()
+properties.load(new File('./local.properties').newDataInputStream())
+
+def readiumSdkLibDir = properties.getProperty('readium.sdk_lib_dir', null)
+def readiumSdkIncludeDir = properties.getProperty('readium.sdk_include_dir', null)
+
+def lcpBuildContentFilter = readiumSdkLibDir != null && readiumSdkIncludeDir != null
+
+println "[[LCP]] (SETTINGS) readiumSdkLibDir: ${readiumSdkLibDir}"
+println "[[LCP]] (SETTINGS) readiumSdkIncludeDir: ${readiumSdkIncludeDir}"
+
+if (lcpBuildContentFilter) {
+ include ':epub3'
+ project(':epub3').projectDir = new File(readiumSdkIncludeDir, '../')
+ include ':rsdk'
+ project(':rsdk').projectDir = new File(readiumSdkIncludeDir, '../../lib/')
+}
\ No newline at end of file
diff --git a/platform/apple/LCP Client.xcodeproj/project.pbxproj b/platform/apple/LCP Client.xcodeproj/project.pbxproj
index f6c011e..baea62c 100644
--- a/platform/apple/LCP Client.xcodeproj/project.pbxproj
+++ b/platform/apple/LCP Client.xcodeproj/project.pbxproj
@@ -723,6 +723,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
+ English,
en,
);
mainGroup = 5ACE2E021BF21D7900AC0585;
@@ -884,6 +885,7 @@
baseConfigurationReference = 5ACE2E7D1BF21EBE00AC0585 /* LCP Client.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
@@ -938,6 +940,7 @@
baseConfigurationReference = 5ACE2E7D1BF21EBE00AC0585 /* LCP Client.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
@@ -986,11 +989,13 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 5A2496AE1C620ECA00EABFFC /* LCP Client (iOS).xcconfig */;
buildSettings = {
- IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/third-parties/cryptopp/lib",
);
+ ONLY_ACTIVE_ARCH = YES;
+ OTHER_CFLAGS = "-fembed-bitcode";
OTHER_LDFLAGS = "-ObjC";
SKIP_INSTALL = YES;
};
@@ -1000,11 +1005,12 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 5A2496AE1C620ECA00EABFFC /* LCP Client (iOS).xcconfig */;
buildSettings = {
- IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/third-parties/cryptopp/lib",
);
+ OTHER_CFLAGS = "-fembed-bitcode";
OTHER_LDFLAGS = "-ObjC";
SKIP_INSTALL = YES;
};
diff --git a/platform/apple/xcframework.sh b/platform/apple/xcframework.sh
new file mode 100755
index 0000000..1746b94
--- /dev/null
+++ b/platform/apple/xcframework.sh
@@ -0,0 +1,45 @@
+#######
+#xcode-select --install
+#sudo xcode-select --switch /Library/Developer/CommandLineTools
+#sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
+#######
+
+rm -rf "./archives/LCP Client (iOS) DEVICE"
+rm -rf "./archives/LCP Client (iOS) SIMULATOR"
+
+xcodebuild archive \
+-project "LCP Client.xcodeproj" \
+-scheme "LCP Client (iOS)" \
+-destination "generic/platform=iOS" \
+-archivePath "./archives/LCP Client (iOS) DEVICE" \
+SKIP_INSTALL=NO \
+BUILD_LIBRARY_FOR_DISTRIBUTION=YES
+
+xcodebuild archive \
+-project "LCP Client.xcodeproj" \
+-scheme "LCP Client (iOS)" \
+-destination "generic/platform=iOS Simulator" \
+-archivePath "./archives/LCP Client (iOS) SIMULATOR" \
+SKIP_INSTALL=NO \
+BUILD_LIBRARY_FOR_DISTRIBUTION=YES
+
+rm -rf "./archives/LCP_iOS.xcframework"
+
+mkdir "./archives/headers"
+ls -als "../../src/lcp-content-filter/public" | grep "\\.h[p]*"
+ls -als "../../src/lcp-client-lib/public" | grep "\\.h[p]*"
+ls -als "./src" | grep "\\.h[p]*"
+cp ../../src/lcp-content-filter/public/*.h "./archives/headers/"
+cp ../../src/lcp-client-lib/public/*.h "./archives/headers/"
+cp ./src/*.h "./archives/headers/"
+rm "./archives/headers/lcp.h"
+ls -als "./archives/headers"
+
+xcodebuild -create-xcframework \
+-library "./archives/LCP Client (iOS) DEVICE.xcarchive/Products/usr/local/lib/libLCP-client-iOS.a" \
+-headers "./archives/headers" \
+-library "./archives/LCP Client (iOS) SIMULATOR.xcarchive/Products/usr/local/lib/libLCP-client-iOS.a" \
+-headers "./archives/headers" \
+-output "./archives/LCP_iOS.xcframework"
+
+ls -alsR "./archives/LCP_iOS.xcframework"
diff --git a/platform/cross-platform/build.py b/platform/cross-platform/build.py
old mode 100644
new mode 100755
index 9316a49..6d7f5e9
--- a/platform/cross-platform/build.py
+++ b/platform/cross-platform/build.py
@@ -9,8 +9,10 @@
if SYSTEM == "linux":
# Use clang on linux
# print "Use clang compiler"
- # os.environ["CC"] = "clang"
- # os.environ["CXX"] = "clang++"
+ # sudo apt-get install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
+ # sudo apt-get install libc6-armel-cross libc6-dev-armel-cross binutils-arm-linux-gnueabi libncurses5-dev
+ # os.environ["CC"] = "arm-linux-gnueabi-gcc"
+ # os.environ["CXX"] = "arm-linux-gnueabi-g++"
# os.environ["GYP_DEFINES"] = "clang=1"
GYP_OS = "linux"
elif SYSTEM == "windows":
@@ -42,4 +44,4 @@
if SYSTEM == "windows":
cmd = ["vcvarsall.bat", "&&"] + cmd
-utils.execute_command(cmd)
\ No newline at end of file
+utils.execute_command(cmd)
diff --git a/platform/cross-platform/filenames.gypi b/platform/cross-platform/filenames.gypi
index 0298447..c02f048 100644
--- a/platform/cross-platform/filenames.gypi
+++ b/platform/cross-platform/filenames.gypi
@@ -183,6 +183,7 @@
'lcp_client_lib_sources': [
'<(lcp_client_lib_dir)/Acquisition.cpp',
'<(lcp_client_lib_dir)/AesCbcSymmetricAlgorithm.cpp',
+ '<(lcp_client_lib_dir)/AesGcmSymmetricAlgorithm.cpp',
'<(lcp_client_lib_dir)/AlgorithmNames.cpp',
'<(lcp_client_lib_dir)/Certificate.cpp',
'<(lcp_client_lib_dir)/CertificateExtension.cpp',
@@ -193,6 +194,7 @@
'<(lcp_client_lib_dir)/CryptoppCryptoProvider.cpp',
'<(lcp_client_lib_dir)/CryptoppUtils.cpp',
'<(lcp_client_lib_dir)/DateTime.cpp',
+ '<(lcp_client_lib_dir)/EcdsaSha256SignatureAlgorithm.cpp',
'<(lcp_client_lib_dir)/EncryptionProfileNames.cpp',
'<(lcp_client_lib_dir)/EncryptionProfilesManager.cpp',
'<(lcp_client_lib_dir)/JsonCanonicalizer.cpp',
diff --git a/platform/cross-platform/lcp.gyp b/platform/cross-platform/lcp.gyp
old mode 100644
new mode 100755
index 13aba20..721e90e
--- a/platform/cross-platform/lcp.gyp
+++ b/platform/cross-platform/lcp.gyp
@@ -16,6 +16,7 @@
'-g', # Debug mode
],
'defines': [
+ 'ENABLE_NET_PROVIDER_ACQUISITION=1',
'BUILDING_EPUB3'
]
},
@@ -23,8 +24,11 @@
{
'target_name': 'lcp_content_filter',
'type': 'static_library',
+ 'standalone_static_library': 1,
'cflags_cc': [
- '-std=c++11'
+ '-std=c++11',
+ '-frtti',
+ '-fexceptions',
],
'sources': [
'<@(lcp_content_filter_sources)'
@@ -33,6 +37,7 @@
{
'target_name': 'lcp_client_lib',
'type': 'static_library',
+ 'standalone_static_library': 1,
'dependencies': [
'cryptopp',
'zip_lib',
@@ -53,6 +58,7 @@
{
'target_name': 'cryptopp',
'type': 'static_library',
+ 'standalone_static_library': 1,
'cflags_cc': [
'-std=c++11',
'-fpermissive',
@@ -66,6 +72,7 @@
{
'target_name': 'zip_lib',
'type': 'static_library',
+ 'standalone_static_library': 1,
'dependencies': [
'zlib',
'bzip2'
@@ -83,6 +90,7 @@
{
'target_name': 'zlib',
'type': 'static_library',
+ 'standalone_static_library': 1,
'sources': [
'<@(zlib_sources)'
]
@@ -90,6 +98,7 @@
{
'target_name': 'bzip2',
'type': 'static_library',
+ 'standalone_static_library': 1,
'sources': [
'<@(bzip2_sources)'
]
@@ -97,6 +106,7 @@
{
'target_name': 'time64',
'type': 'static_library',
+ 'standalone_static_library': 1,
'sources': [
'<@(time64_sources)'
]
@@ -160,6 +170,10 @@
'cflags': [
'-m64',
'-march=x86-64',
+# '-march=armv7-a',
+# '-mthumb',
+# '-mfpu=neon',
+# '-mfloat-abi=hard',
],
'cflags_cc': [
],
diff --git a/src/lcp-client-lib/AesCbcSymmetricAlgorithm.cpp b/src/lcp-client-lib/AesCbcSymmetricAlgorithm.cpp
index 9f28986..2917ed9 100644
--- a/src/lcp-client-lib/AesCbcSymmetricAlgorithm.cpp
+++ b/src/lcp-client-lib/AesCbcSymmetricAlgorithm.cpp
@@ -108,23 +108,29 @@ namespace lcp
throw std::out_of_range("Invalid encrypted file, size is out of range");
}
+ // we read the last two 16-bytes AES blocks (first one is IV for second)
size_t readPosition = static_cast(stream->Size()) - (CryptoPP::AES::BLOCKSIZE + CryptoPP::AES::BLOCKSIZE);
stream->SetReadPosition(readPosition);
std::vector inBuffer(CryptoPP::AES::BLOCKSIZE + CryptoPP::AES::BLOCKSIZE);
- std::vector outBuffer(inBuffer.size());
stream->Read(&inBuffer.at(0), inBuffer.size());
+ std::vector outBuffer(CryptoPP::AES::BLOCKSIZE); // we only decrypt the last 16-bytes AES block
size_t outSize = this->InnerDecrypt(
&inBuffer.at(0),
inBuffer.size(),
&outBuffer.at(0),
outBuffer.size(),
- BlockPaddingSchemeDef::W3C_PADDING // Note that handling of W3C padding scheme during decryption also handles PKCS#7 (which is BlockPaddingSchemeDef::PKCS_PADDING in CryptoPP, with AES CBC Block Size > 8 (not PKCS#5))
+ BlockPaddingSchemeDef::NO_PADDING // if W3C_PADDING and padding length == full-length 16-bytes AES padding block, then outSize is ZERO
);
+ // BlockPaddingSchemeDef::W3C_PADDING => ZERO for all unused bytes in the 16-bytes AES block, except for the last one which corresponds to the padding length.
+ // BlockPaddingSchemeDef::PKCS_PADDING (PKCS#7) => stores the padding length in ALL unused bytes in the 16-bytes AES block.
+ // Even when padding is not needed (because encrypted data is exactly a multiple of 16-bytes AES block size), there is a trailing padding block with the sole purpose of informing the presence of this full-length 16-bytes padding block.
+ size_t paddingSize = static_cast(outBuffer[outBuffer.size() - 1]);
+
return static_cast(stream->Size())
- CryptoPP::AES::BLOCKSIZE // minus IV or previous block
- - (CryptoPP::AES::BLOCKSIZE - outSize) % CryptoPP::AES::BLOCKSIZE; // minus padding part
+ - paddingSize;
}
void AesCbcSymmetricAlgorithm::Decrypt(
@@ -166,23 +172,24 @@ namespace lcp
blocksCount++;
}
- // Figure out what padding scheme to use
- BlockPaddingSchemeDef::BlockPaddingScheme padding = BlockPaddingSchemeDef::NO_PADDING;
- size_t sizeWithoutPaddedBlock = plainTextSize - (plainTextSize % CryptoPP::AES::BLOCKSIZE);
- if (rangeInfo.position + rangeInfo.length > sizeWithoutPaddedBlock)
- {
- padding = BlockPaddingSchemeDef::W3C_PADDING; // Note that handling of W3C padding scheme during decryption also handles PKCS#7 (which is BlockPaddingSchemeDef::PKCS_PADDING in CryptoPP, with AES CBC Block Size > 8 (not PKCS#5))
- }
-
// Read data from the stream
stream->SetReadPosition(readPosition);
std::vector inBuffer(blocksCount * CryptoPP::AES::BLOCKSIZE);
std::vector outBuffer(inBuffer.size());
- if (readPosition + inBuffer.size() > stream->Size())
+ int64_t total = readPosition + inBuffer.size();
+ int64_t ssize = stream->Size();
+ if (total > ssize)
{
throw std::out_of_range("encrypted stream is out of range");
}
stream->Read(&inBuffer.at(0), inBuffer.size());
+
+ // Figure out what padding scheme to use
+ BlockPaddingSchemeDef::BlockPaddingScheme padding = BlockPaddingSchemeDef::NO_PADDING;
+ if (total > (ssize - CryptoPP::AES::BLOCKSIZE))
+ {
+ padding = BlockPaddingSchemeDef::W3C_PADDING; // Note that handling of W3C padding scheme during decryption also handles PKCS#7 (which is BlockPaddingSchemeDef::PKCS_PADDING in CryptoPP, with AES CBC Block Size > 8 (not PKCS#5))
+ }
// Decrypt and copy necessary data
size_t outSize = this->InnerDecrypt(
diff --git a/src/lcp-client-lib/CryptoppCryptoProvider.cpp b/src/lcp-client-lib/CryptoppCryptoProvider.cpp
index 5db7485..0d915bd 100644
--- a/src/lcp-client-lib/CryptoppCryptoProvider.cpp
+++ b/src/lcp-client-lib/CryptoppCryptoProvider.cpp
@@ -263,9 +263,16 @@ namespace lcp
std::unique_ptr contentKeyAlgorithm(profile->CreateContentKeyAlgorithm(userKey2, algorithm));
std::string id = contentKeyAlgorithm->Decrypt(license->Crypto()->UserKeyCheck());
- if (!EqualsUtf8(id, license->Id()))
+ try
+ {
+ if (!EqualsUtf8(id, license->Id()))
+ {
+ return Status(StatusCode::ErrorDecryptionUserPassphraseNotValid, "ErrorDecryptionUserPassphraseNotValid");
+ }
+ }
+ catch (const std::exception & exc) // utf8::invalid_utf8
{
- return Status(StatusCode::ErrorDecryptionUserPassphraseNotValid, "ErrorDecryptionUserPassphraseNotValid");
+ return Status(StatusCode::ErrorDecryptionUserPassphraseNotValid, "ErrorDecryptionUserPassphraseNotValid: " + std::string(exc.what()));
}
return Status(StatusCode::ErrorCommonSuccess);
}
@@ -295,8 +302,22 @@ namespace lcp
//http://www.w3.org/2009/xmlenc11#aes256-gcm
//http://www.w3.org/2001/04/xmlenc#aes256-cbc
- const std::string algorithm = license->Crypto()->ContentKeyAlgorithm();
+ const std::string algorithm_ = license->Crypto()->ContentKeyAlgorithm();
+ std::unique_ptr contentKeyAlgorithm_(profile->CreateContentKeyAlgorithm(userKey, algorithm_));
+ std::string id = contentKeyAlgorithm_->Decrypt(license->Crypto()->UserKeyCheck());
+ try
+ {
+ if (!EqualsUtf8(id, license->Id()))
+ {
+ return Status(StatusCode::ErrorDecryptionUserPassphraseNotValid, "ErrorDecryptionUserPassphraseNotValid");
+ }
+ }
+ catch (const std::exception & exc) // utf8::invalid_utf8
+ {
+ return Status(StatusCode::ErrorDecryptionUserPassphraseNotValid, "ErrorDecryptionUserPassphraseNotValid: " + std::string(exc.what()));
+ }
+ const std::string algorithm = license->Crypto()->ContentKeyAlgorithm();
std::unique_ptr contentKeyAlgorithm(profile->CreateContentKeyAlgorithm(userKey, algorithm));
std::string decryptedContentKey = contentKeyAlgorithm->Decrypt(license->Crypto()->ContentKey());
diff --git a/src/lcp-client-lib/JsonValueReader.cpp b/src/lcp-client-lib/JsonValueReader.cpp
index 7ffc771..9383e38 100644
--- a/src/lcp-client-lib/JsonValueReader.cpp
+++ b/src/lcp-client-lib/JsonValueReader.cpp
@@ -63,7 +63,13 @@ namespace lcp
{
return it->value;
}
- return rapidjson::Value(rapidjson::kNullType).Move();
+
+ // https://rapidjson.org/md_doc_tutorial.html#TemporaryValues
+ // https://github.com/Tencent/rapidjson/issues/387#issuecomment-122067853
+ // std::move() not needed (same as other returns, like it->value above)
+ // rapidjson::Value(rapidjson::kNullType).Move();
+ // rapidjson::Value().SetNull());
+ return rapidjson::Document().SetNull(); // THIS WORKS!! (allocator is preserved)
}
const rapidjson::Value & JsonValueReader::ReadArrayCheck(const std::string & name, const rapidjson::Value & jsonValue)
@@ -83,7 +89,13 @@ namespace lcp
{
return it->value;
}
- return rapidjson::Value(rapidjson::kNullType).Move();
+
+ // https://rapidjson.org/md_doc_tutorial.html#TemporaryValues
+ // https://github.com/Tencent/rapidjson/issues/387#issuecomment-122067853
+ // std::move() not needed (same as other returns, like it->value above)
+ // rapidjson::Value(rapidjson::kNullType).Move();
+ // rapidjson::Value().SetNull());
+ return rapidjson::Document().SetNull(); // THIS WORKS!! (allocator is preserved)
}
const rapidjson::Value & JsonValueReader::ReadObjectCheck(const std::string & name, const rapidjson::Value & jsonValue)
diff --git a/src/lcp-client-lib/LcpUtils.cpp b/src/lcp-client-lib/LcpUtils.cpp
index d6273cc..04b97c4 100644
--- a/src/lcp-client-lib/LcpUtils.cpp
+++ b/src/lcp-client-lib/LcpUtils.cpp
@@ -103,6 +103,9 @@ namespace lcp
bool EqualsUtf8(const std::string & left, const std::string & right)
{
+ ValidateUtf8(left);
+ ValidateUtf8(right);
+
Utf8ConstIt leftBeginIt(left.begin(), left.begin(), left.end());
Utf8ConstIt leftEndIt(left.end(), left.begin(), left.end());
Utf8ConstIt rightBeginIt(right.begin(), right.begin(), right.end());
@@ -112,6 +115,9 @@ namespace lcp
bool LexicographicalCompareUtf8(const std::string & left, const std::string & right)
{
+ ValidateUtf8(left);
+ ValidateUtf8(right);
+
Utf8ConstIt leftBeginIt(left.begin(), left.begin(), left.end());
Utf8ConstIt leftEndIt(left.end(), left.begin(), left.end());
Utf8ConstIt rightBeginIt(right.begin(), right.begin(), right.end());
@@ -119,4 +125,4 @@ namespace lcp
return std::lexicographical_compare(leftBeginIt, leftEndIt, rightBeginIt, rightEndIt);
}
-}
\ No newline at end of file
+}