commit 6ede649

default  ·  2023-08-17 15:38:39 +0000 UTC
parent b3b4a4e
Convert 'Link' attachments that have a media extension to something more useful.
5 files changed,  +112, -51
M html.c
M html.c
+10, -0
 1@@ -1313,6 +1313,16 @@ xs_str *html_entry(snac *user, xs_str *os, const xs_dict *msg, int local,
 2             if (xs_is_null(url))
 3                 continue;
 4 
 5+            /* if it's a plain Link, check if it can be "rewritten" */
 6+            if (strcmp(t, "Link") == 0) {
 7+                const char *mt = xs_mime_by_ext(url);
 8+
 9+                if (xs_startswith(mt, "image/") ||
10+                    xs_startswith(mt, "audio/") ||
11+                    xs_startswith(mt, "video/"))
12+                    t = mt;
13+            }
14+
15             const char *name = xs_dict_get(v, "name");
16             if (xs_is_null(name))
17                 name = xs_dict_get(msg, "name");
+50, -40
  1@@ -6,57 +6,67 @@
  2 
  3 const char *xs_mime_by_ext(const char *file);
  4 
  5+extern const char *xs_mime_types[];
  6+
  7 #ifdef XS_IMPLEMENTATION
  8 
  9 /* intentionally brain-dead simple */
 10-struct _mime_info {
 11-    const char *type;
 12-    const char *ext;
 13-} mime_info[] = {
 14-    { "application/json",   ".json" },
 15-    { "image/gif",          ".gif" },
 16-    { "image/jpeg",         ".jpeg" },
 17-    { "image/jpeg",         ".jpg" },
 18-    { "image/png",          ".png" },
 19-    { "image/webp",         ".webp" },
 20-    { "video/mp4",          ".mp4" },
 21-    { "video/mp4",          ".mpg4" },
 22-    { "video/mp4",          ".m4v" },
 23-    { "video/webm",         ".webm" },
 24-    { "video/quicktime",    ".mov" },
 25-    { "video/3gpp",         ".3gp" },
 26-    { "video/ogg",          ".ogv" },
 27-    { "video/flv",          ".flv" },
 28-    { "audio/mp3",          ".mp3" },
 29-    { "audio/ogg",          ".ogg" },
 30-    { "audio/ogg",          ".oga" },
 31-    { "audio/ogg",          ".opus" },
 32-    { "audio/flac",         ".flac" },
 33-    { "audio/wav",          ".wav" },
 34-    { "audio/wma",          ".wma" },
 35-    { "audio/aac",          ".aac" },
 36-    { "audio/aac",          ".m4a" },
 37-    { "text/css",           ".css" },
 38-    { "text/html",          ".html" },
 39-    { "text/plain",         ".txt" },
 40-    { "text/xml",           ".xml" },
 41-    { "text/markdown",      ".md" },
 42-    { "text/gemini",        ".gmi" },
 43-    { NULL, NULL }
 44+/* CAUTION: sorted */
 45+
 46+const char *xs_mime_types[] = {
 47+    "3gp",      "video/3gpp",
 48+    "aac",      "audio/aac",
 49+    "css",      "text/css",
 50+    "flac",     "audio/flac",
 51+    "flv",      "video/flv",
 52+    "gif",      "image/gif",
 53+    "gmi",      "text/gemini",
 54+    "html",     "text/html",
 55+    "jpeg",     "image/jpeg",
 56+    "jpg",      "image/jpeg",
 57+    "json",     "application/json",
 58+    "m4a",      "audio/aac",
 59+    "m4v",      "video/mp4",
 60+    "md",       "text/markdown",
 61+    "mov",      "video/quicktime",
 62+    "mp3",      "audio/mp3",
 63+    "mp4",      "video/mp4",
 64+    "mpg4",     "video/mp4",
 65+    "oga",      "audio/ogg",
 66+    "ogg",      "audio/ogg",
 67+    "ogv",      "video/ogg",
 68+    "opus",     "audio/ogg",
 69+    "png",      "image/png",
 70+    "txt",      "text/plain",
 71+    "wav",      "audio/wav",
 72+    "webm",     "video/webm",
 73+    "webp",     "image/webp",
 74+    "wma",      "audio/wma",
 75+    "xml",      "text/xml",
 76+    NULL,       NULL,
 77 };
 78 
 79 
 80 const char *xs_mime_by_ext(const char *file)
 81 /* returns the MIME type by file extension */
 82 {
 83-    struct _mime_info *mi = mime_info;
 84-    xs *lfile = xs_tolower_i(xs_dup(file));
 85+    const char *ext = strrchr(file, '.');
 86+
 87+    if (ext) {
 88+        const char **p = xs_mime_types;
 89+        xs *uext       = xs_tolower_i(xs_dup(ext + 1));
 90+
 91+        while (**p) {
 92+            int c;
 93 
 94-    while (mi->type != NULL) {
 95-        if (xs_endswith(lfile, mi->ext))
 96-            return mi->type;
 97+            if ((c = strcmp(*p, uext)) == 0)
 98+                return p[1];
 99+            else
100+            if (c > 0)
101+                break;
102 
103-        mi++;
104+            p += 2;
105+        }
106     }
107 
108     return "application/octet-stream";
+7, -3
 1@@ -8,8 +8,10 @@ xs_list *xs_regex_split_n(const char *str, const char *rx, int count);
 2 #define xs_regex_split(str, rx) xs_regex_split_n(str, rx, XS_ALL)
 3 xs_list *xs_regex_match_n(const char *str, const char *rx, int count);
 4 #define xs_regex_match(str, rx) xs_regex_match_n(str, rx, XS_ALL)
 5-xs_list *xs_regex_replace_n(const char *str, const char *rx, const char *rep, int count);
 6-#define xs_regex_replace(str, rx, rep) xs_regex_replace_n(str, rx, rep, XS_ALL)
 7+xs_list *xs_regex_replace_in(xs_str *str, const char *rx, const char *rep, int count);
 8+#define xs_regex_replace_i(str, rx, rep) xs_regex_replace_in(str, rx, rep, XS_ALL)
 9+#define xs_regex_replace_n(str, rx, rep, count) xs_regex_replace_in(xs_dup(str), rx, rep, count)
10+#define xs_regex_replace(str, rx, rep) xs_regex_replace_in(xs_dup(str), rx, rep, XS_ALL)
11 
12 #ifdef XS_IMPLEMENTATION
13 
14@@ -78,7 +80,7 @@ xs_list *xs_regex_match_n(const char *str, const char *rx, int count)
15 }
16 
17 
18-xs_list *xs_regex_replace_n(const char *str, const char *rx, const char *rep, int count)
19+xs_list *xs_regex_replace_in(xs_str *str, const char *rx, const char *rep, int count)
20 /* replaces all matches with the rep string. If it contains unescaped &,
21    they are replaced with the match */
22 {
23@@ -121,6 +123,8 @@ xs_list *xs_regex_replace_n(const char *str, const char *rx, const char *rep, in
24         n++;
25     }
26 
27+    xs_free(str);
28+
29     return s;
30 }
31 
+44, -7
 1@@ -4,8 +4,10 @@
 2 
 3 #define _XS_UNICODE_H
 4 
 5+ int _xs_utf8_enc(char buf[4], unsigned int cpoint);
 6  xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint);
 7  unsigned int xs_utf8_dec(char **str);
 8+ int xs_unicode_width(unsigned int cpoint);
 9  unsigned int *_xs_unicode_upper_search(unsigned int cpoint);
10  unsigned int *_xs_unicode_lower_search(unsigned int cpoint);
11  #define xs_unicode_is_upper(cpoint) (!!_xs_unicode_upper_search(cpoint))
12@@ -18,8 +20,8 @@
13 #ifdef XS_IMPLEMENTATION
14 
15 
16-char *_xs_utf8_enc(char buf[4], unsigned int cpoint)
17-/* encodes an Unicode codepoint to utf-8 into buf and returns the new position */
18+int _xs_utf8_enc(char buf[4], unsigned int cpoint)
19+/* encodes an Unicode codepoint to utf-8 into buf and returns the size in bytes */
20 {
21     unsigned char *p = (unsigned char *)buf;
22 
23@@ -42,18 +44,18 @@ char *_xs_utf8_enc(char buf[4], unsigned int cpoint)
24         *p++ = 0x80 | (cpoint & 0x3f);
25     }
26 
27-    return (char *)p;
28+    return p - (unsigned char *)buf;
29 }
30 
31 
32 xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint)
33 /* encodes an Unicode codepoint to utf-8 into str */
34 {
35-    char tmp[4], *p;
36+    char tmp[4];
37 
38-    p = _xs_utf8_enc(tmp, cpoint);
39+    int c = _xs_utf8_enc(tmp, cpoint);
40 
41-    return xs_append_m(str, tmp, p - tmp);
42+    return xs_append_m(str, tmp, c);
43 }
44 
45 
46@@ -99,9 +101,44 @@ unsigned int xs_utf8_dec(char **str)
47 }
48 
49 
50+/* intentionally dead simple */
51+
52+static unsigned int xs_unicode_width_table[] = {
53+    0x300,      0x36f,      0,      /* diacritics */
54+    0x1100,     0x11ff,     2,      /* Hangul */
55+    0x2e80,     0xa4cf,     2,      /* CJK */
56+    0xac00,     0xd7a3,     2,      /* more Hangul */
57+    0xe000,     0xf8ff,     0,      /* private use */
58+    0xf900,     0xfaff,     2,      /* CJK compatibility */
59+    0xff00,     0xff60,     2,      /* full width things */
60+    0xffdf,     0xffe6,     2,      /* full width things */
61+    0x1f200,    0x1ffff,    2,      /* emojis */
62+    0x20000,    0x2fffd,    2       /* more CJK */
63+};
64+
65+int xs_unicode_width(unsigned int cpoint)
66+/* returns the width in columns of a Unicode codepoint (somewhat simplified) */
67+{
68+    unsigned int *p = xs_unicode_width_table;
69+    unsigned int *e = p + sizeof(xs_unicode_width_table) / sizeof(unsigned int);
70+
71+    while (p < e) {
72+        if (cpoint < p[0])
73+            return 1;
74+
75+        if (cpoint >= p[0] && cpoint <= p[1])
76+            return p[2];
77+
78+        p += 3;
79+    }
80+
81+    return 0;
82+}
83+
84+
85 #ifdef _XS_UNICODE_TBL_H
86 
87-/* include xs_unicode_tbl.h before to use these functions */
88+/* include xs_unicode_tbl.h before this one to use these functions */
89 
90 static int int_cmp(const void *p1, const void *p2)
91 {
+1, -1
1@@ -1 +1 @@
2-/* b7e9713d90382d8da0b58023f4c78416e6ca1bc5 */
3+/* e85f257dd8fcb2980fd21aa37c1594c1461ddf48 */