diff -r f07de07b90c4 -r a645b4ebb054 core/src/iosMain/kotlin/licenseplist/LicensePlistParser.kt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/iosMain/kotlin/licenseplist/LicensePlistParser.kt Wed Mar 12 20:17:28 2025 -0400
@@ -0,0 +1,107 @@
+/*
+ * AboutOss is an utility library to retrieve and display
+ * opensource licenses in Android applications.
+ *
+ * Copyright (C) 2023 by Frederic-Charles Barthelery.
+ *
+ * This file is part of AboutOss.
+ *
+ * AboutOss is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AboutOss is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AboutOss. If not, see .
+ */
+package com.geekorum.aboutoss.core.licenseplist
+
+import kotlinx.cinterop.BetaInteropApi
+import kotlinx.cinterop.ExperimentalForeignApi
+import kotlinx.cinterop.ObjCObjectVar
+import kotlinx.cinterop.alloc
+import kotlinx.cinterop.memScoped
+import kotlinx.cinterop.ptr
+import kotlinx.cinterop.value
+import platform.Foundation.NSBundle
+import platform.Foundation.NSData
+import platform.Foundation.NSError
+import platform.Foundation.NSPropertyListMutableContainers
+import platform.Foundation.NSPropertyListSerialization
+import platform.Foundation.NSURL
+import platform.Foundation.dataWithContentsOfURL
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlin.coroutines.suspendCoroutine
+
+class LicensePlistParser {
+
+ @Suppress("UNCHECKED_CAST")
+ suspend fun parseLicenses(
+ licensePlistInput: NSURL
+ ): Map {
+ val fileContent = getContent(licensePlistInput)
+ val plist = fileContent.toPropertyList() as Map>>
+ val paneLists = plist["PreferenceSpecifiers"]!!
+ .filter {
+ it["Type"] == "PSChildPaneSpecifier"
+ }
+ val directoryUrl = licensePlistInput.URLByDeletingLastPathComponent()!!
+ return paneLists.associate { pane ->
+ val paneFile = pane["File"]!!
+ val libraryName = pane["Title"]!!
+ val paneUrl = buildPaneUrl(directoryUrl, paneFile)
+ val paneFileContent = getContent(paneUrl)
+ val paneFilePlist = paneFileContent.toPropertyList() as Map>>
+ val license = getLicenseFromPaneFilePlist(paneFilePlist)
+ libraryName to license
+ }
+ }
+
+ private fun buildPaneUrl(directoryUrl: NSURL, paneName: String) = directoryUrl.URLByAppendingPathComponent(paneName)!!.URLByAppendingPathExtension("plist")!!
+
+ private fun getLicenseFromPaneFilePlist(paneFilePList: Map>>): String {
+ val specifiers = paneFilePList["PreferenceSpecifiers"]!!
+ val licenses = specifiers.map {
+ it["FooterText"]!!
+ }
+ return licenses.joinToString("\n\n")
+ }
+
+ private fun getContent(url: NSURL): NSData {
+ return checkNotNull(NSData.dataWithContentsOfURL(url))
+ }
+
+ @OptIn(ExperimentalForeignApi::class, BetaInteropApi::class)
+ private suspend fun NSData.toPropertyList(): Any? = suspendCoroutine { cont ->
+ val parsed = memScoped {
+ val error: ObjCObjectVar = alloc()
+ val result = NSPropertyListSerialization.propertyListWithData(this@toPropertyList,
+ options = NSPropertyListMutableContainers,
+ format = null,
+ error.ptr
+ )
+ if (error.value != null) {
+ cont.resumeWithException(Exception(error.value!!.description))
+ }
+ result
+ }
+ cont.resume(parsed!!)
+ }
+
+ companion object {
+ fun getDefaultLicensePlistUrl(): NSURL {
+ val path = NSBundle.mainBundle.pathForResource(
+ "com.mono0926.LicensePlist",
+ ofType = "plist",
+ inDirectory = "licenseplist"
+ )
+ return NSURL.fileURLWithPath(path!!)
+ }
+ }
+}
\ No newline at end of file