/* SPDX-FileCopyrightText: 2026 Project Tick * SPDX-FileContributor: Project Tick * SPDX-License-Identifier: GPL-3.0-or-later * * MeshMC - A Custom Launcher for Minecraft * Copyright (C) 2026 Project Tick * * This program 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. * * This program 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 this program. If not, see . */ #pragma once #include #include #include #include "DefaultVariable.h" struct GradleSpecifier { GradleSpecifier() { m_valid = false; } GradleSpecifier(QString value) { operator=(value); } GradleSpecifier& operator=(const QString& value) { /* org.gradle.test.classifiers : service : 1.0 : jdk15 @ jar 0 "org.gradle.test.classifiers:service:1.0:jdk15@jar" 1 "org.gradle.test.classifiers" 2 "service" 3 "1.0" 4 "jdk15" 5 "jar" */ QRegularExpression matcher("^([^:@]+):([^:@]+):([^:@]+)" "(?::([^:@]+))?" "(?:@([^:@]+))?$"); auto match = matcher.match(value); m_valid = match.hasMatch(); if (!m_valid) { m_invalidValue = value; return *this; } m_groupId = match.captured(1); m_artifactId = match.captured(2); m_version = match.captured(3); m_classifier = match.captured(4); auto ext = match.captured(5); if (!ext.isEmpty()) { m_extension = ext; } return *this; } QString serialize() const { if (!m_valid) { return m_invalidValue; } QString retval = m_groupId + ":" + m_artifactId + ":" + m_version; if (!m_classifier.isEmpty()) { retval += ":" + m_classifier; } if (m_extension.isExplicit()) { retval += "@" + m_extension; } return retval; } QString getFileName() const { if (!m_valid) { return QString(); } QString filename = m_artifactId + '-' + m_version; if (!m_classifier.isEmpty()) { filename += "-" + m_classifier; } filename += "." + m_extension; return filename; } QString toPath(const QString& filenameOverride = QString()) const { if (!m_valid) { return QString(); } QString filename; if (filenameOverride.isEmpty()) { filename = getFileName(); } else { filename = filenameOverride; } QString path = m_groupId; path.replace('.', '/'); path += '/' + m_artifactId + '/' + m_version + '/' + filename; return path; } inline bool valid() const { return m_valid; } inline QString version() const { return m_version; } inline QString groupId() const { return m_groupId; } inline QString artifactId() const { return m_artifactId; } inline void setClassifier(const QString& classifier) { m_classifier = classifier; } inline QString classifier() const { return m_classifier; } inline QString extension() const { return m_extension; } inline QString artifactPrefix() const { return m_groupId + ":" + m_artifactId; } bool matchName(const GradleSpecifier& other) const { // Classifiers differentiate otherwise identical coordinates (e.g. the // base lwjgl-glfw:3.3.2 jar vs lwjgl-glfw:3.3.2:natives-linux). Two // entries with different classifiers must be treated as distinct // library entries. return other.artifactId() == artifactId() && other.groupId() == groupId() && other.m_classifier == m_classifier; } bool operator==(const GradleSpecifier& other) const { if (m_groupId != other.m_groupId) return false; if (m_artifactId != other.m_artifactId) return false; if (m_version != other.m_version) return false; if (m_classifier != other.m_classifier) return false; if (m_extension != other.m_extension) return false; return true; } private: QString m_invalidValue; QString m_groupId; QString m_artifactId; QString m_version; QString m_classifier; DefaultVariable m_extension = DefaultVariable("jar"); bool m_valid = false; };