/
githubmirror
/
libxmlb
Обзор
Документация
Войти
/
githubmirror
/
libxmlb
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
0.3.21
src/xb-common.c
143 строки
4 KB
Richard Hughes
Don't assume .txt files are application/xml
24 июн 2024, 10:39
24 июн 2024, 10:39
acb337c
Код
Авторство
О чём код?
/* * Copyright 2020 Richard Hughes <richard@hughsie.com> * * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbCommon" #include "config.h" #include <string.h> #include "xb-common-private.h" static const gchar * xb_content_type_guess_from_fn(const gchar *filename) { gchar *ext; /* no ownership */ g_return_val_if_fail(filename != NULL, NULL); /* get file extension with dot */ ext = g_strrstr(filename, "."); if (ext == NULL) return NULL; /* map Windows "mime-type" to a content type */ if (g_strcmp0(ext, ".gz") == 0) return "application/gzip"; if (g_strcmp0(ext, ".xz") == 0) return "application/x-xz"; if (g_strcmp0(ext, ".zst") == 0) return "application/zstd"; if (g_strcmp0(ext, ".xml") == 0) return "application/xml"; if (g_strcmp0(ext, ".desktop") == 0) return "application/x-desktop"; if (g_strcmp0(ext, ".quirk") == 0) return "text/plain"; return NULL; } static gboolean xb_content_type_match(const guchar *buf, gsize bufsz, gsize offset, const gchar *magic, gsize magic_size) { /* document too small */ if (offset + magic_size > bufsz) return FALSE; return memcmp(buf + offset, magic, magic_size) == 0; } /** * xb_content_type_guess: (skip) * @filename: (nullable): filename * @buf: (nullable): file data buffer * @bufsz: size of file data buffer * * Guesses the content type based on example data. Either @filename or @buf may * be %NULL, in which case the guess will be based solely on the other argument. * * Returns: a string indicating a guessed content type **/ gchar * xb_content_type_guess(const gchar *filename, const guchar *buf, gsize bufsz) { g_autofree gchar *content_type = NULL; /* check for bad results, e.g. from Chrome OS */ content_type = g_content_type_guess(filename, buf, bufsz, NULL); if (g_strstr_len(content_type, -1, "/") == NULL || g_strcmp0(content_type, "application/octet-stream") == 0 || g_strcmp0(content_type, "text/plain") == 0) { /* magic */ if (bufsz > 0) { if (xb_content_type_match(buf, bufsz, 0x0, "\x1f\x8b", 2)) return g_strdup("application/gzip"); if (xb_content_type_match(buf, bufsz, 0x0, "\xfd\x37\x7a\x58\x5a\x00", 6)) return g_strdup("application/x-xz"); if (xb_content_type_match(buf, bufsz, 0x0, "\x28\xb5\x2f\xfd", 4)) return g_strdup("application/zstd"); if (xb_content_type_match(buf, bufsz, 0x0, "<?xml", 5)) return g_strdup("application/xml"); if (xb_content_type_match(buf, bufsz, 0x0, "[Desktop Entry]", 15)) return g_strdup("application/x-desktop"); } /* file extensions */ if (filename != NULL) { const gchar *tmp = xb_content_type_guess_from_fn(filename); if (tmp != NULL) return g_strdup(tmp); } } #ifdef _WIN32 /* fall back harder as there is no mime data at all */ if (filename != NULL) { const gchar *tmp = xb_content_type_guess_from_fn(filename); if (tmp != NULL) return g_strdup(tmp); } #endif return g_steal_pointer(&content_type); } /** * xb_file_set_contents: (skip) * @file: (nullable): file to write * @buf: (nullable): data buffer * @bufsz: size of @buf * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Writes data to a file. * * Returns: %TRUE for success **/ gboolean xb_file_set_contents(GFile *file, const guint8 *buf, gsize bufsz, GCancellable *cancellable, GError **error) { g_return_val_if_fail(G_IS_FILE(file), FALSE); g_return_val_if_fail(buf != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); return g_file_replace_contents(file, (const gchar *)buf, (gsize)bufsz, NULL, FALSE, G_FILE_CREATE_NONE, NULL, cancellable, error); }