1
/* ipuz-misc.c
2
 *
3
 * Copyright 2022 Jonathan Blandford <jrb@gnome.org>
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18
 *
19
 * SPDX-License-Identifier: (LGPL-2.1-or-later OR MIT)
20
 */
21

            
22
#include <libipuz.h>
23

            
24
static void html_to_markup_start_element (GMarkupParseContext  *context,
25
                                          const gchar          *element_name,
26
                                          const gchar         **attribute_names,
27
                                          const gchar         **attribute_values,
28
                                          gpointer              user_data,
29
                                          GError              **error);
30
static void html_to_markup_end_element   (GMarkupParseContext  *context,
31
                                          const gchar          *element_name,
32
                                          gpointer              user_data,
33
                                          GError              **error);
34
static void html_to_markup_text          (GMarkupParseContext  *context,
35
                                          const gchar          *text,
36
                                          gsize                 text_len,
37
                                          gpointer              user_data,
38
                                          GError              **error);
39

            
40

            
41
static GMarkupParser parser =
42
{
43
  .start_element = html_to_markup_start_element,
44
  .end_element = html_to_markup_end_element,
45
  .text = html_to_markup_text,
46
};
47

            
48
/* We support the following elements (from the ipuz spec)
49
 * <b> ... </b> — Bold
50
 * <i> ... </i> — Italic
51
 * <s> ... </s> — Strikeout
52
 * <u> ... </u> — Underline
53
 * <em> ... </em> — Emphasis
54
 * <strong> ... </strong> — Stronger emphasis
55
 * <big> ... </big> — Bigger text
56
 * <small> ... </small> — Smaller text
57
 * <sup> ... </sup> — Superscript text
58
 * <sub> ... </sub> — Subscript text
59
 * <br> or <br/> — newline
60
 */
61
static void
62
854
html_to_markup_start_element (GMarkupParseContext  *context,
63
                              const gchar          *element_name,
64
                              const gchar         **attribute_names,
65
                              const gchar         **attribute_values,
66
                              gpointer              user_data,
67
                              GError              **error)
68
{
69
854
  GString *string = user_data;
70

            
71
854
  if (!g_strcmp0 (element_name, "clue"))
72
829
    return;
73
  /* Do we support pango-style attributes from outside? I think not,
74
   * but maybe there's a reason..? */
75
25
  else if (!g_strcmp0 (element_name, "span"))
76
    return;
77
25
  else if (!g_strcmp0 (element_name, "b"))
78
    g_string_append (string, "<b>");
79
26
  else if (!g_strcmp0 (element_name, "i")||
80
1
           !g_strcmp0 (element_name, "em"))
81
24
    g_string_append (string, "<i>");
82
1
  else if (!g_strcmp0 (element_name, "strong"))
83
1
    g_string_append (string, "<b><i>");
84
  else if (!g_strcmp0 (element_name, "s"))
85
    g_string_append (string, "<s>");
86
  else if (!g_strcmp0 (element_name, "u"))
87
    g_string_append (string, "<u>");
88
  else if (!g_strcmp0 (element_name, "big"))
89
    g_string_append (string, "<big>");
90
  else if (!g_strcmp0 (element_name, "small"))
91
    g_string_append (string, "<small>");
92
  else if (!g_strcmp0 (element_name, "sup"))
93
    g_string_append (string, "<sup>");
94
  else if (!g_strcmp0 (element_name, "sub"))
95
    g_string_append (string, "<sub>");
96
  else if (!g_strcmp0 (element_name, "br"))
97
    g_string_append (string, "\n");
98

            
99
  /* all other tags we just ignore. There's nothing much we can do
100
   * with them */
101
}
102

            
103
static void
104
853
html_to_markup_end_element (GMarkupParseContext  *context,
105
                            const gchar          *element_name,
106
                            gpointer              user_data,
107
                            GError              **error)
108
{
109
853
  GString *string = user_data;
110

            
111
853
  if (!g_strcmp0 (element_name, "clue"))
112
828
    return;
113
25
  else if (!g_strcmp0 (element_name, "span"))
114
    return;
115
25
  else if (!g_strcmp0 (element_name, "b"))
116
    g_string_append (string, "</b>");
117
26
  else if (!g_strcmp0 (element_name, "i")||
118
1
           !g_strcmp0 (element_name, "em"))
119
24
    g_string_append (string, "</i>");
120
1
  else if (!g_strcmp0 (element_name, "strong"))
121
1
    g_string_append (string, "</i></b>");
122
  else if (!g_strcmp0 (element_name, "s"))
123
    g_string_append (string, "</s>");
124
  else if (!g_strcmp0 (element_name, "u"))
125
    g_string_append (string, "</u>");
126
  else if (!g_strcmp0 (element_name, "big"))
127
    g_string_append (string, "</big>");
128
  else if (!g_strcmp0 (element_name, "small"))
129
    g_string_append (string, "</small>");
130
  else if (!g_strcmp0 (element_name, "sup"))
131
    g_string_append (string, "</sup>");
132
  else if (!g_strcmp0 (element_name, "sub"))
133
    g_string_append (string, "</sub>");
134
}
135

            
136
static void
137
878
html_to_markup_text (GMarkupParseContext  *context,
138
                     const gchar          *text,
139
                     gsize                 text_len,
140
                     gpointer              user_data,
141
                     GError              **error)
142
{
143
878
  g_autofree gchar *markup_text = NULL;
144
878
  GString *string = user_data;
145

            
146
878
  markup_text = g_markup_escape_text (text, text_len);
147
878
  g_string_append (string, markup_text);
148
878
}
149

            
150
gchar *
151
829
ipuz_html_to_markup (const gchar *src)
152
{
153
829
  g_autoptr (GMarkupParseContext) context = NULL;
154
829
  g_autoptr (GError) error = NULL;
155
829
  g_autofree gchar *html_src = NULL;
156
  GString *string;
157

            
158
  /* short circuit empty strings */
159
829
  if (src == NULL || src[0] == '\0')
160
    return g_strdup (src);
161

            
162
829
  string = g_string_new (NULL);
163
  /* Most of the text we get isn't in xml tags, so we put it in a span
164
   * we can ignore. */
165
829
  html_src = g_strdup_printf ("<clue>%s</clue>", src);
166
829
  context = g_markup_parse_context_new (&parser, G_MARKUP_PREFIX_ERROR_POSITION, string, NULL);
167
829
  if (! g_markup_parse_context_parse (context, html_src, strlen (html_src), &error))
168
1
    goto error;
169
828
  if (! g_markup_parse_context_end_parse (context, &error))
170
    goto error;
171

            
172
828
  return g_string_free (string, FALSE);
173

            
174
1
 error:
175
1
  g_string_free (string, TRUE);
176
1
  return g_markup_escape_text (src, strlen (src));
177
}
178

            
179
GType
180
ipuz_puzzle_kind_to_gtype (IPuzPuzzleKind kind)
181
{
182
  switch (kind)
183
    {
184
    case IPUZ_PUZZLE_ACROSTIC:
185
      return IPUZ_TYPE_ACROSTIC;
186
    case IPUZ_PUZZLE_ARROWWORD:
187
      return IPUZ_TYPE_ARROWWORD;
188
    case IPUZ_PUZZLE_BARRED:
189
      return IPUZ_TYPE_BARRED;
190
    case IPUZ_PUZZLE_CROSSWORD:
191
      return IPUZ_TYPE_CROSSWORD;
192
    case IPUZ_PUZZLE_CRYPTIC:
193
      return IPUZ_TYPE_CRYPTIC;
194
    case IPUZ_PUZZLE_FILIPPINE:
195
      return IPUZ_TYPE_FILIPPINE;
196
    case IPUZ_PUZZLE_UNKNOWN:
197
    default:
198
      return G_TYPE_NONE;
199
    }
200
}
201

            
202
IPuzPuzzleKind
203
ipuz_puzzle_kind_from_gtype (GType gtype)
204
{
205
  if (gtype == IPUZ_TYPE_ACROSTIC)
206
    return IPUZ_PUZZLE_ACROSTIC;
207
  if (gtype == IPUZ_TYPE_ARROWWORD)
208
    return IPUZ_PUZZLE_ARROWWORD;
209
  if (gtype == IPUZ_TYPE_BARRED)
210
    return IPUZ_PUZZLE_BARRED;
211
  if (gtype == IPUZ_TYPE_CROSSWORD)
212
    return IPUZ_PUZZLE_CROSSWORD;
213
  if (gtype == IPUZ_TYPE_CRYPTIC)
214
    return IPUZ_PUZZLE_CRYPTIC;
215
  if (gtype == IPUZ_TYPE_FILIPPINE)
216
    return IPUZ_PUZZLE_FILIPPINE;
217

            
218
  return IPUZ_PUZZLE_UNKNOWN;
219
}