|
1 /* |
|
2 * AboutOss is an utility library to retrieve and display |
|
3 * opensource licenses in Android applications. |
|
4 * |
|
5 * Copyright (C) 2023 by Frederic-Charles Barthelery. |
|
6 * |
|
7 * This file is part of AboutOss. |
|
8 * |
|
9 * AboutOss is free software: you can redistribute it and/or modify |
|
10 * it under the terms of the GNU General Public License as published by |
|
11 * the Free Software Foundation, either version 3 of the License, or |
|
12 * (at your option) any later version. |
|
13 * |
|
14 * AboutOss is distributed in the hope that it will be useful, |
|
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
17 * GNU General Public License for more details. |
|
18 * |
|
19 * You should have received a copy of the GNU General Public License |
|
20 * along with AboutOss. If not, see <http://www.gnu.org/licenses/>. |
|
21 */ |
|
22 package com.geekorum.aboutoss.core.licenseplist |
|
23 |
|
24 import kotlinx.cinterop.BetaInteropApi |
|
25 import kotlinx.cinterop.ExperimentalForeignApi |
|
26 import kotlinx.cinterop.ObjCObjectVar |
|
27 import kotlinx.cinterop.alloc |
|
28 import kotlinx.cinterop.memScoped |
|
29 import kotlinx.cinterop.ptr |
|
30 import kotlinx.cinterop.value |
|
31 import platform.Foundation.NSBundle |
|
32 import platform.Foundation.NSData |
|
33 import platform.Foundation.NSError |
|
34 import platform.Foundation.NSPropertyListMutableContainers |
|
35 import platform.Foundation.NSPropertyListSerialization |
|
36 import platform.Foundation.NSURL |
|
37 import platform.Foundation.dataWithContentsOfURL |
|
38 import kotlin.coroutines.resume |
|
39 import kotlin.coroutines.resumeWithException |
|
40 import kotlin.coroutines.suspendCoroutine |
|
41 |
|
42 class LicensePlistParser { |
|
43 |
|
44 @Suppress("UNCHECKED_CAST") |
|
45 suspend fun parseLicenses( |
|
46 licensePlistInput: NSURL |
|
47 ): Map<String, String> { |
|
48 val fileContent = getContent(licensePlistInput) |
|
49 val plist = fileContent.toPropertyList() as Map<String, List<Map<String, String>>> |
|
50 val paneLists = plist["PreferenceSpecifiers"]!! |
|
51 .filter { |
|
52 it["Type"] == "PSChildPaneSpecifier" |
|
53 } |
|
54 val directoryUrl = licensePlistInput.URLByDeletingLastPathComponent()!! |
|
55 return paneLists.associate { pane -> |
|
56 val paneFile = pane["File"]!! |
|
57 val libraryName = pane["Title"]!! |
|
58 val paneUrl = buildPaneUrl(directoryUrl, paneFile) |
|
59 val paneFileContent = getContent(paneUrl) |
|
60 val paneFilePlist = paneFileContent.toPropertyList() as Map<String, List<Map<String, String>>> |
|
61 val license = getLicenseFromPaneFilePlist(paneFilePlist) |
|
62 libraryName to license |
|
63 } |
|
64 } |
|
65 |
|
66 private fun buildPaneUrl(directoryUrl: NSURL, paneName: String) = directoryUrl.URLByAppendingPathComponent(paneName)!!.URLByAppendingPathExtension("plist")!! |
|
67 |
|
68 private fun getLicenseFromPaneFilePlist(paneFilePList: Map<String, List<Map<String, String>>>): String { |
|
69 val specifiers = paneFilePList["PreferenceSpecifiers"]!! |
|
70 val licenses = specifiers.map { |
|
71 it["FooterText"]!! |
|
72 } |
|
73 return licenses.joinToString("\n\n") |
|
74 } |
|
75 |
|
76 private fun getContent(url: NSURL): NSData { |
|
77 return checkNotNull(NSData.dataWithContentsOfURL(url)) |
|
78 } |
|
79 |
|
80 @OptIn(ExperimentalForeignApi::class, BetaInteropApi::class) |
|
81 private suspend fun NSData.toPropertyList(): Any? = suspendCoroutine { cont -> |
|
82 val parsed = memScoped { |
|
83 val error: ObjCObjectVar<NSError?> = alloc() |
|
84 val result = NSPropertyListSerialization.propertyListWithData(this@toPropertyList, |
|
85 options = NSPropertyListMutableContainers, |
|
86 format = null, |
|
87 error.ptr |
|
88 ) |
|
89 if (error.value != null) { |
|
90 cont.resumeWithException(Exception(error.value!!.description)) |
|
91 } |
|
92 result |
|
93 } |
|
94 cont.resume(parsed!!) |
|
95 } |
|
96 |
|
97 companion object { |
|
98 fun getDefaultLicensePlistUrl(): NSURL { |
|
99 val path = NSBundle.mainBundle.pathForResource( |
|
100 "com.mono0926.LicensePlist", |
|
101 ofType = "plist", |
|
102 inDirectory = "licenseplist" |
|
103 ) |
|
104 return NSURL.fileURLWithPath(path!!) |
|
105 } |
|
106 } |
|
107 } |