core/src/commonMain/kotlin/gms/OssLicenseParser.kt
changeset 24 f07de07b90c4
child 30 763a6573b900
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/commonMain/kotlin/gms/OssLicenseParser.kt	Wed Mar 12 19:49:58 2025 -0400
@@ -0,0 +1,105 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+package com.geekorum.aboutoss.core.gms
+
+import okio.ByteString
+import okio.Source
+import okio.buffer
+import okio.use
+
+/**
+ * Parse licences data generated by the "com.google.android.gms.oss-licenses-plugin" gradle plugin.
+ */
+class OssLicenseParser {
+
+    /**
+     * Parse licenses
+     * @param [thirdPartyLicensesInput] is usually res/raw/third_party_licenses file
+     * @param [thirdPartyLicensesMetadataInput] is usually res/raw/third_party_license_metadata file
+     */
+    fun parseLicenses(
+        thirdPartyLicensesInput: Source, thirdPartyLicensesMetadataInput: Source
+    ): Map<String, String> {
+        val licenses = readLicensesFile(thirdPartyLicensesInput)
+        return buildLicenseInfo(licenses, thirdPartyLicensesMetadataInput)
+    }
+
+    private fun readLicensesFile(thirdPartyLicensesInput: Source): ByteString {
+        return thirdPartyLicensesInput.buffer().use {
+            it.readByteString()
+        }
+    }
+
+    private fun buildLicenseInfo(license: ByteString, thirdPartyLicensesMetadataInput: Source): Map<String, String> {
+        return thirdPartyLicensesMetadataInput.buffer().use {
+            buildMap {
+                while (true) {
+                    val line = it.readUtf8Line() ?: break
+                    if (line.isNotBlank()) {
+                        with(line.toLineParser()) {
+                            val start = readStartIdx()
+                            val length = readLength()
+                            val dependency = readName()
+                            val licenseTxt = license.substring(
+                                beginIndex = start,
+                                endIndex = start + length + 1
+                            ).utf8()
+                            put(dependency, licenseTxt)
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    companion object
+}
+
+private class LicenseMetadataLineParser(
+    private val line: String
+) {
+
+    private var idx = 0
+
+    fun readStartIdx(): Int {
+        val end = line.indexOf(':', startIndex = idx)
+        val result = line.substring(idx, end).toInt()
+        idx = end + 1
+        return result
+    }
+
+    fun readLength(): Int {
+        val end = line.indexOf(' ', startIndex = idx)
+        val result = line.substring(idx, end).toInt()
+        idx = end + 1
+        return result
+    }
+
+    fun readName(): String {
+        val result = line.substring(idx)
+        idx = line.length + 1
+        return result
+    }
+
+}
+
+private fun String.toLineParser() = LicenseMetadataLineParser(this)
\ No newline at end of file