# HG changeset patch # User Da Risk # Date 1741825048 14400 # Node ID a645b4ebb054731cb60e96210efcf870527ba986 # Parent f07de07b90c4bc9ec94415d7204229b26b197ce0 core: add ios LicensePlistParser 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