Add files from gst-rtmp
[platform/upstream/gstreamer.git] / gst / rtmp2 / rtmp / rtmputils.c
1 /* GStreamer RTMP Library
2  * Copyright (C) 2013 David Schleef <ds@schleef.org>
3  * Copyright (C) 2017 Make.TV, Inc. <info@make.tv>
4  *   Contact: Jan Alexander Steffens (heftig) <jsteffens@make.tv>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
19  * Boston, MA 02110-1335, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "rtmputils.h"
27 #include <string.h>
28
29 static void read_all_bytes_done (GObject * source, GAsyncResult * result,
30     gpointer user_data);
31 static void write_all_bytes_done (GObject * source, GAsyncResult * result,
32     gpointer user_data);
33
34 void
35 gst_rtmp_byte_array_append_bytes (GByteArray * bytearray, GBytes * bytes)
36 {
37   const guint8 *data;
38   gsize size;
39   guint offset;
40
41   g_return_if_fail (bytearray);
42
43   offset = bytearray->len;
44   data = g_bytes_get_data (bytes, &size);
45
46   g_return_if_fail (data);
47
48   g_byte_array_set_size (bytearray, offset + size);
49   memcpy (bytearray->data + offset, data, size);
50 }
51
52 void
53 gst_rtmp_input_stream_read_all_bytes_async (GInputStream * stream, gsize count,
54     int io_priority, GCancellable * cancellable, GAsyncReadyCallback callback,
55     gpointer user_data)
56 {
57   GTask *task;
58   GByteArray *ba;
59
60   g_return_if_fail (G_IS_INPUT_STREAM (stream));
61
62   task = g_task_new (stream, cancellable, callback, user_data);
63
64   ba = g_byte_array_sized_new (count);
65   g_byte_array_set_size (ba, count);
66   g_task_set_task_data (task, ba, (GDestroyNotify) g_byte_array_unref);
67
68   g_input_stream_read_all_async (stream, ba->data, count, io_priority,
69       cancellable, read_all_bytes_done, task);
70 }
71
72 static void
73 read_all_bytes_done (GObject * source, GAsyncResult * result,
74     gpointer user_data)
75 {
76   GInputStream *is = G_INPUT_STREAM (source);
77   GTask *task = user_data;
78   GByteArray *ba = g_task_get_task_data (task);
79   GError *error = NULL;
80   gboolean res;
81   gsize bytes_read;
82   GBytes *bytes;
83
84   res = g_input_stream_read_all_finish (is, result, &bytes_read, &error);
85   if (!res) {
86     g_task_return_error (task, error);
87     g_object_unref (task);
88     return;
89   }
90
91   g_byte_array_set_size (ba, bytes_read);
92   bytes = g_byte_array_free_to_bytes (g_byte_array_ref (ba));
93
94   g_task_return_pointer (task, bytes, (GDestroyNotify) g_bytes_unref);
95   g_object_unref (task);
96 }
97
98 GBytes *
99 gst_rtmp_input_stream_read_all_bytes_finish (GInputStream * stream,
100     GAsyncResult * result, GError ** error)
101 {
102   g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
103   return g_task_propagate_pointer (G_TASK (result), error);
104 }
105
106 void
107 gst_rtmp_output_stream_write_all_bytes_async (GOutputStream * stream,
108     GBytes * bytes, int io_priority, GCancellable * cancellable,
109     GAsyncReadyCallback callback, gpointer user_data)
110 {
111   GTask *task;
112   const void *data;
113   gsize size;
114
115   g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
116   g_return_if_fail (bytes);
117
118   data = g_bytes_get_data (bytes, &size);
119   g_return_if_fail (data);
120
121   task = g_task_new (stream, cancellable, callback, user_data);
122   g_task_set_task_data (task, g_bytes_ref (bytes),
123       (GDestroyNotify) g_bytes_unref);
124
125   g_output_stream_write_all_async (stream, data, size, io_priority,
126       cancellable, write_all_bytes_done, task);
127 }
128
129 static void
130 write_all_bytes_done (GObject * source, GAsyncResult * result,
131     gpointer user_data)
132 {
133   GOutputStream *os = G_OUTPUT_STREAM (source);
134   GTask *task = user_data;
135   GError *error = NULL;
136   gboolean res;
137
138   res = g_output_stream_write_all_finish (os, result, NULL, &error);
139   if (!res) {
140     g_task_return_error (task, error);
141     g_object_unref (task);
142     return;
143   }
144
145   g_task_return_boolean (task, TRUE);
146   g_object_unref (task);
147 }
148
149 gboolean
150 gst_rtmp_output_stream_write_all_bytes_finish (GOutputStream * stream,
151     GAsyncResult * result, GError ** error)
152 {
153   g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
154   return g_task_propagate_boolean (G_TASK (result), error);
155 }
156
157 static const gchar ascii_table[128] = {
158   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
159   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
160   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
161   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
162   ' ', '!', 0x0, '#', '$', '%', '&', '\'',
163   '(', ')', '*', '+', ',', '-', '.', '/',
164   '0', '1', '2', '3', '4', '5', '6', '7',
165   '8', '9', ':', ';', '<', '=', '>', '?',
166   '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
167   'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
168   'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
169   'X', 'Y', 'Z', '[', 0x0, ']', '^', '_',
170   '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
171   'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
172   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
173   'x', 'y', 'z', '{', '|', '}', '~', 0x0,
174 };
175
176 static const gchar ascii_escapes[128] = {
177   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 'a',
178   'b', 't', 'n', 'v', 'f', 'r', 0x0, 0x0,
179   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
180   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
181   0x0, 0x0, '"', 0x0, 0x0, 0x0, 0x0, 0x0,
182   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
183   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
184   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
185   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
186   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
187   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
188   0x0, 0x0, 0x0, 0x0, '\\', 0x0, 0x0, 0x0,
189   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
190   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
191   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
192   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
193 };
194
195 void
196 gst_rtmp_string_print_escaped (GString * string, const gchar * data,
197     gssize size)
198 {
199   gssize i;
200
201   g_return_if_fail (string);
202
203   if (!data) {
204     g_string_append (string, "(NULL)");
205     return;
206   }
207
208   g_string_append_c (string, '"');
209
210   for (i = 0; size < 0 ? data[i] != 0 : i < size; i++) {
211     guchar c = data[i];
212
213     if (G_LIKELY (c < G_N_ELEMENTS (ascii_table))) {
214       if (ascii_table[c]) {
215         g_string_append_c (string, c);
216         continue;
217       }
218
219       if (ascii_escapes[c]) {
220         g_string_append_c (string, '\\');
221         g_string_append_c (string, ascii_escapes[c]);
222         continue;
223       }
224     } else {
225       gunichar uc = g_utf8_get_char_validated (data + i,
226           size < 0 ? -1 : size - i);
227       if (uc != (gunichar) (-2) && uc != (gunichar) (-1)) {
228         if (g_unichar_isprint (uc)) {
229           g_string_append_unichar (string, uc);
230         } else if (uc <= G_MAXUINT16) {
231           g_string_append_printf (string, "\\u%04X", uc);
232         } else {
233           g_string_append_printf (string, "\\U%08X", uc);
234         }
235
236         i += g_utf8_skip[c] - 1;
237         continue;
238       }
239     }
240
241     g_string_append_printf (string, "\\x%02X", c);
242   }
243
244   g_string_append_c (string, '"');
245
246 }