1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
/* gst-matcher.cpp - Match GStreamer packages
*
* Copyright (c) 2010-2016 Daniel Nicoletti <dantti12@gmail.com>
*
* 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 2 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; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gst-matcher.h"
#include "apt-utils.h"
#include <regex.h>
#include <gst/gst.h>
static bool inited = false;
GstMatcher::GstMatcher(gchar **values)
{
if (!inited) {
gst_init(NULL, NULL);
inited = true;
}
// The search term from PackageKit daemon:
// gstreamer0.10(urisource-foobar)
// gstreamer0.10(decoder-audio/x-wma)(wmaversion=3)
const char *pkreg =
"^gstreamer\\(0.10\\|1\\)\\(\\.0\\)\\?"
"(\\(encoder\\|decoder\\|urisource\\|urisink\\|element\\)-\\([^)]\\+\\))"
"\\((.*)\\)\\?";
regex_t pkre;
if (regcomp(&pkre, pkreg, 0) != 0) {
g_debug("Regex compilation error: %s", pkreg);
return;
}
gchar *value;
for (uint i = 0; i < g_strv_length(values); ++i) {
value = values[i];
regmatch_t matches[6];
if (regexec(&pkre, value, 6, matches, 0) != REG_NOMATCH) {
Match mvals;
string version, type, data, opt;
bool native = false;
// Appends the version "0.10"
version = "\nGstreamer-Version: ";
version.append(string(value, matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so));
// type (encode|decoder...)
type = string(value, matches[3].rm_so, matches[3].rm_eo - matches[3].rm_so);
// data "audio/x-wma"
data = string(value, matches[4].rm_so, matches[4].rm_eo - matches[4].rm_so);
// opt "wmaversion=3"
if (matches[5].rm_so != -1) {
// remove the '(' ')' that the regex matched
opt = string(value, matches[5].rm_so + 1, matches[5].rm_eo - matches[5].rm_so - 2);
if (!opt.empty()) {
size_t start_pos = 0;
// This is hardcoded in pk-gstreamer-install, so we also hardcode it here
const string arch_64 = ")(64bit";
if (ends_with(opt.c_str(), arch_64.c_str())) {
/* The ()(64bit) suffix is an RPM artifact, where it is used to distinguish
* between the primary and secondary architecture in a 2-arch system.
* It doesn't translate precisely to DPKG, where multi-arch is not limited
* to one secondary architecture. Let's use it the same way RPM would and
* only match the native arch.
*/
native = true;
opt.erase(opt.end() - arch_64.length(), opt.end());
}
// Replace all ")(" with "," - convert from input to serialized caps format
while ((start_pos = opt.find(")(", start_pos)) != string::npos) {
if (start_pos == opt.length() - 2) {
// Avoid trailing comma
opt.erase(start_pos, 2);
break;
}
opt.replace(start_pos, 2, ",");
start_pos++;
}
}
}
if (type.compare("encoder") == 0) {
type = "Gstreamer-Encoders: ";
} else if (type.compare("decoder") == 0) {
type = "Gstreamer-Decoders: ";
} else if (type.compare("urisource") == 0) {
type = "Gstreamer-Uri-Sources: ";
} else if (type.compare("urisink") == 0) {
type = "Gstreamer-Uri-Sinks: ";
} else if (type.compare("element") == 0) {
type = "Gstreamer-Elements: ";
}
gchar *capsString;
if (opt.empty()) {
capsString = g_strdup_printf("%s", data.c_str());
} else {
capsString = g_strdup_printf("%s, %s", data.c_str(), opt.c_str());
}
GstCaps *caps = gst_caps_from_string(capsString);
g_free(capsString);
if (caps == NULL) {
continue;
}
mvals.version = version;
mvals.type = type;
mvals.data = data;
mvals.opt = opt;
mvals.caps = caps;
mvals.native = native;
m_matches.push_back(mvals);
} else {
g_debug("gstmatcher: Did not match: %s", value);
}
}
regfree(&pkre);
}
GstMatcher::~GstMatcher()
{
for (const Match &match : m_matches) {
gst_caps_unref(static_cast<GstCaps *>(match.caps));
}
}
bool GstMatcher::matches(string record, bool native)
{
for (const Match &match : m_matches) {
// Tries to find "Gstreamer-version: xxx"
if (record.find(match.version) != string::npos) {
size_t found;
if (match.native && !native)
continue;
found = record.find(match.type);
// Tries to find the type "Gstreamer-Uri-Sinks: "
if (found != string::npos) {
found += match.type.size(); // skips the "Gstreamer-Uri-Sinks: " string
size_t endOfLine;
endOfLine = record.find('\n', found);
GstCaps *caps;
caps = gst_caps_from_string(record.substr(found, endOfLine - found).c_str());
if (caps == NULL) {
continue;
}
// if the record is capable of intersect them we found the package
bool provides = gst_caps_can_intersect(static_cast<GstCaps *>(match.caps), caps);
gst_caps_unref(caps);
if (provides) {
return true;
}
}
}
}
return false;
}
bool GstMatcher::hasMatches() const
{
return !m_matches.empty();
}
|