UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
text.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2014-2023 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#include "config_unix.h"
41#include "config_win32.h"
42#endif
43
44#include <string.h>
45
46#include "debug.h"
47#include "utils/bitmap_font.h"
48#include "utils/color_out.h" // prune_ansi_sequences_inplace_cstr
49#include "utils/fs.h"
50#include "utils/pam.h"
51#include "utils/string.h"
52#include "utils/text.h"
53
55{
56 return isalnum(c) || c == '*' || c == '-' || c == '.' || c == '_';
57}
58
60{
61 return isalnum(c) || c == '~' || c == '-' || c == '.' || c == '_';
62}
63
81size_t urlencode(char *out, size_t max_len, const char *in, int (*eval_pass)(int c),
82 bool space_plus_replace)
83{
84 if (max_len == 0 || max_len >= INT_MAX) { // prevent overflow
85 return 0;
86 }
87 size_t len = 0;
88 while (*in && len < max_len - 1) {
89 if (*in == ' ' && space_plus_replace) {
90 *out++ = '+';
91 in++;
92 } else if (eval_pass(*in) != 0) {
93 *out++ = *in++;
94 len++;
95 } else {
96 if ((int) len < (int) max_len - 3 - 1) {
97 int ret = sprintf(out, "%%%02X", *in++);
98 out += ret;
99 len += ret;
100 } else {
101 break;
102 }
103 }
104 }
105 *out = '\0';
106 len++;
107
108 return len;
109}
110
111static inline int ishex(int x)
112{
113 return (x >= '0' && x <= '9') ||
114 (x >= 'a' && x <= 'f') ||
115 (x >= 'A' && x <= 'F');
116}
117
129size_t urldecode(char *out, size_t max_len, const char *in)
130{
131 if (max_len == 0) { // avoid (uint) -1 cast
132 return 0;
133 }
134 size_t len = 0;
135 while (*in && len < max_len - 1) {
136 if (*in == '+') {
137 *out++ = ' ';
138 in++;
139 } else if (*in != '%') {
140 *out++ = *in++;
141 } else {
142 in++; // skip '%'
143 if (!ishex(in[0]) || !ishex(in[1])) {
144 return 0;
145 }
146 unsigned int c = 0;
147 if (sscanf(in, "%2x", &c) != 1) {
148 return 0;
149 }
150 *out++ = c;
151 in += 2;
152 }
153 len++;
154 }
155 *out = '\0';
156 len++;
157
158 return len;
159}
160
168unsigned char *base64_decode(const char *in, unsigned int *length) {
169 unsigned int allocated = 128;
170 unsigned char *out = (unsigned char *) malloc(allocated);
171 *length = 0;
172
173 int T[256];
174 for (unsigned int i = 0; i < sizeof T / sizeof T[0]; i++) {
175 T[i] = -1;
176 }
177 for (int i=0; i<64; i++) T[(int) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
178
179 int val=0, valb=-8;
180 unsigned char c = 0;
181 while ((c = *in++) != '\0') {
182 if (T[c] == -1) break;
183 val = (val << 6) + T[c];
184 valb += 6;
185 if (valb >= 0) {
186 if (allocated == *length) {
187 allocated *= 2;
188 out = (unsigned char *) realloc(out, allocated);
189 assert(out != NULL);
190 }
191 out[(*length)++] = (val>>valb)&0xFF;
192 valb -= 8;
193 }
194 }
195 return out;
196}
197
203char *
204wrap_paragraph(char *text)
205{
206 char *pos = text;
207 char *last_space = NULL;
208
209 char *next = NULL;
210 int line_len = 0;
211 while ((next = strpbrk(pos, " \n")) != NULL) {
212 int len_raw = next - pos;
213 char str_in[len_raw + 1];
214 memcpy(str_in, pos, len_raw);
215 str_in[len_raw] = '\0';
216 int len_net = strlen(prune_ansi_sequences_inplace_cstr(str_in));
217 if (line_len + len_net > 80) {
218 if (line_len == 0) { // |word|>80 starting a line
219 *next = '\n';
220 pos = next + 1;
221 } else {
222 *last_space = '\n';
223 pos = last_space + 1;
224 }
225 line_len = 0;
226 continue;
227 }
228 if (next[0] == '\n') {
229 pos = next + 1;
230 line_len = 0;
231 continue;
232 }
233 last_space = next;
234 pos += len_raw + 1;
235 line_len += len_net + 1;
236 }
237 return text;
238}
239
240// since the data are already in memory, it would be also possible to use
241// pointer directly to font array (skipping or deleting PBM header)
242static bool draw_line_init(unsigned char *out) {
243 const char *filename = NULL;
244 FILE *f = get_temp_file(&filename);
245 if (!f) {
246 log_msg(LOG_LEVEL_ERROR, "Cannot get temporary file!\n");
247 return false;
248 }
249 fwrite(font, sizeof font, 1, f);
250 rewind(f);
251 struct pam_metadata info;
252 unsigned char *font_data = NULL;
253
254 bool ret = pam_read(filename, &info, &font_data, malloc);
255 fclose(f);
256 unlink(filename);
257 if (!ret) {
258 log_msg(LOG_LEVEL_ERROR, "Cannot read PAM!\n");
259 return false;
260 }
261 assert(info.width == FONT_W * FONT_COUNT && info.height == FONT_H && info.maxval == 1 && info.bitmap_pbm);
262
263 memcpy(out, font_data, (info.width + 7) / 8 * info.height);
264 free(font_data);
265 return true;
266}
267
271bool draw_line(char *buf, int pitch, const char *text, uint32_t color, bool solid) {
272 static unsigned char font_data[(FONT_W * FONT_COUNT + 7) / 8 * FONT_H];
273 static bool font_data_initialized = false;
274 if (!font_data_initialized) {
275 if (!draw_line_init(font_data)) {
276 return false;
277 }
278 font_data_initialized = true;
279 }
280 int idx = 0;
281 enum {
282 WIDTH = FONT_W + 1,
283 };
284 while (*text) {
285 char c = *text;
286 if (c < ' ' || c > '~') {
287 c = '?';
288 }
289 c -= ' ';
290 for (int j = 0; j < FONT_H; ++j) {
291 for (int i = 0; i < FONT_W; ++i) {
292 int pos_x = (FONT_W * c + i) / 8;
293 int mask = 1 << (FONT_W - ((FONT_W * c + i) % 8));
294 int offset = (FONT_W * FONT_COUNT + 7) / 8 * j;
295 if (font_data[offset + pos_x] & mask) {
296 buf[j * pitch + 4 * (i + idx * WIDTH)] = color & 0xFFU;
297 buf[j * pitch + 4 * (i + idx * WIDTH) + 1] = (color >> 8U) & 0xFFU;
298 buf[j * pitch + 4 * (i + idx * WIDTH) + 2] = (color >> 16U) & 0xFFU;
299 buf[j * pitch + 4 * (i + idx * WIDTH) + 3] = (color >> 24U) & 0xFFU;
300 } else if (solid) {
301 buf[j * pitch + 4 * (i + idx * WIDTH)] =
302 buf[j * pitch + 4 * (i + idx * WIDTH) + 1] =
303 buf[j * pitch + 4 * (i + idx * WIDTH) + 2] = 0;
304 buf[j * pitch + 4 * (i + idx * WIDTH) + 3] = 0xFFU;
305 }
306 }
307 if (solid) { // fill space between characters
308 buf[j * pitch + 4 * ((WIDTH-1) + idx * WIDTH)] =
309 buf[j * pitch + 4 * ((WIDTH-1) + idx * WIDTH) + 1] =
310 buf[j * pitch + 4 * ((WIDTH-1) + idx * WIDTH) + 2] = 0;
311 buf[j * pitch + 4 * ((WIDTH-1) + idx * WIDTH) + 3] = 0xFFU;
312 }
313 }
314 if ((++idx + 1) * WIDTH * 4 > pitch) {
315 return true;
316 }
317 ++text;
318 }
319
320 return true;
321}
322
int void * val
int void size_t * len
@ FONT_H
Definition bitmap_font.h:8
@ FONT_W
Definition bitmap_font.h:7
@ FONT_COUNT
Definition bitmap_font.h:9
static const unsigned char font[]
Definition bitmap_font.h:13
char * prune_ansi_sequences_inplace_cstr(char *cstr)
static __device__ const float offset
Definition cuda_dxt.cu:139
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
FILE * get_temp_file(const char **filename)
Definition fs.c:145
bool pam_read(const char *filename, struct pam_metadata *info, unsigned char **data, void *(*allocator)(size_t))
Definition pam.c:141
int urlencode_html5_eval(int c)
Definition text.c:54
bool draw_line(char *buf, int pitch, const char *text, uint32_t color, bool solid)
Definition text.c:271
static bool draw_line_init(unsigned char *out)
Definition text.c:242
unsigned char * base64_decode(const char *in, unsigned int *length)
Definition text.c:168
char * wrap_paragraph(char *text)
Definition text.c:204
int urlencode_rfc3986_eval(int c)
Definition text.c:59
size_t urldecode(char *out, size_t max_len, const char *in)
Definition text.c:129
static int ishex(int x)
Definition text.c:111
size_t urlencode(char *out, size_t max_len, const char *in, int(*eval_pass)(int c), bool space_plus_replace)
Definition text.c:81