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 +}