File: | lapiz/lapiz-document-output-stream.c |
Warning: | line 331, column 26 Out of bound memory access (access exceeds upper limit of memory block) |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * lapiz-document-output-stream.c | |||
3 | * This file is part of lapiz | |||
4 | * | |||
5 | * Copyright (C) 2010 - Ignacio Casal Quinteiro | |||
6 | * | |||
7 | * lapiz is free software; you can redistribute it and/or modify | |||
8 | * it under the terms of the GNU General Public License as published by | |||
9 | * the Free Software Foundation; either version 2 of the License, or | |||
10 | * (at your option) any later version. | |||
11 | * | |||
12 | * lapiz is distributed in the hope that it will be useful, | |||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
15 | * GNU General Public License for more details. | |||
16 | * | |||
17 | * You should have received a copy of the GNU General Public License | |||
18 | * along with lapiz; if not, write to the Free Software | |||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, | |||
20 | * Boston, MA 02110-1301 USA | |||
21 | */ | |||
22 | ||||
23 | #include "config.h" | |||
24 | ||||
25 | #include <string.h> | |||
26 | #include <glib.h> | |||
27 | #include <glib/gi18n.h> | |||
28 | #include <gio/gio.h> | |||
29 | #include "lapiz-document-output-stream.h" | |||
30 | ||||
31 | /* NOTE: never use async methods on this stream, the stream is just | |||
32 | * a wrapper around CtkTextBuffer api so that we can use GIO Stream | |||
33 | * methods, but the undelying code operates on a CtkTextBuffer, so | |||
34 | * there is no I/O involved and should be accessed only by the main | |||
35 | * thread */ | |||
36 | ||||
37 | #define MAX_UNICHAR_LEN6 6 | |||
38 | ||||
39 | struct _LapizDocumentOutputStreamPrivate | |||
40 | { | |||
41 | LapizDocument *doc; | |||
42 | CtkTextIter pos; | |||
43 | ||||
44 | gchar *buffer; | |||
45 | gsize buflen; | |||
46 | ||||
47 | guint is_initialized : 1; | |||
48 | guint is_closed : 1; | |||
49 | }; | |||
50 | ||||
51 | enum | |||
52 | { | |||
53 | PROP_0, | |||
54 | PROP_DOCUMENT | |||
55 | }; | |||
56 | ||||
57 | G_DEFINE_TYPE_WITH_PRIVATE (LapizDocumentOutputStream, lapiz_document_output_stream, G_TYPE_OUTPUT_STREAM)static void lapiz_document_output_stream_init (LapizDocumentOutputStream *self); static void lapiz_document_output_stream_class_init ( LapizDocumentOutputStreamClass *klass); static GType lapiz_document_output_stream_get_type_once (void); static gpointer lapiz_document_output_stream_parent_class = ((void*)0); static gint LapizDocumentOutputStream_private_offset ; static void lapiz_document_output_stream_class_intern_init ( gpointer klass) { lapiz_document_output_stream_parent_class = g_type_class_peek_parent (klass); if (LapizDocumentOutputStream_private_offset != 0) g_type_class_adjust_private_offset (klass, &LapizDocumentOutputStream_private_offset ); lapiz_document_output_stream_class_init ((LapizDocumentOutputStreamClass *) klass); } __attribute__ ((__unused__)) static inline gpointer lapiz_document_output_stream_get_instance_private (LapizDocumentOutputStream *self) { return (((gpointer) ((guint8*) (self) + (glong) (LapizDocumentOutputStream_private_offset )))); } GType lapiz_document_output_stream_get_type (void) { static GType static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer) , "Expression evaluates to false"); (void) (0 ? (gpointer) * ( &static_g_define_type_id) : ((void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (*(&static_g_define_type_id)) gapg_temp_newval; __typeof__ ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id ); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5) ; gapg_temp_newval; })) && g_once_init_enter_pointer ( &static_g_define_type_id)); })) ) { GType g_define_type_id = lapiz_document_output_stream_get_type_once (); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); 0 ? (void ) (*(&static_g_define_type_id) = (g_define_type_id)) : (void ) 0; g_once_init_leave_pointer ((&static_g_define_type_id ), (gpointer) (guintptr) (g_define_type_id)); })) ; } return static_g_define_type_id ; } __attribute__ ((__noinline__)) static GType lapiz_document_output_stream_get_type_once (void) { GType g_define_type_id = g_type_register_static_simple ((g_output_stream_get_type ()), g_intern_static_string ("LapizDocumentOutputStream" ), sizeof (LapizDocumentOutputStreamClass), (GClassInitFunc)( void (*)(void)) lapiz_document_output_stream_class_intern_init , sizeof (LapizDocumentOutputStream), (GInstanceInitFunc)(void (*)(void)) lapiz_document_output_stream_init, (GTypeFlags) 0 ); { {{ LapizDocumentOutputStream_private_offset = g_type_add_instance_private (g_define_type_id, sizeof (LapizDocumentOutputStreamPrivate) ); };} } return g_define_type_id; } | |||
58 | ||||
59 | static gssize lapiz_document_output_stream_write (GOutputStream *stream, | |||
60 | const void *buffer, | |||
61 | gsize count, | |||
62 | GCancellable *cancellable, | |||
63 | GError **error); | |||
64 | ||||
65 | static gboolean lapiz_document_output_stream_flush (GOutputStream *stream, | |||
66 | GCancellable *cancellable, | |||
67 | GError **error); | |||
68 | ||||
69 | static gboolean lapiz_document_output_stream_close (GOutputStream *stream, | |||
70 | GCancellable *cancellable, | |||
71 | GError **error); | |||
72 | ||||
73 | static void | |||
74 | lapiz_document_output_stream_set_property (GObject *object, | |||
75 | guint prop_id, | |||
76 | const GValue *value, | |||
77 | GParamSpec *pspec) | |||
78 | { | |||
79 | LapizDocumentOutputStream *stream = LAPIZ_DOCUMENT_OUTPUT_STREAM (object)((((LapizDocumentOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((object)), ((lapiz_document_output_stream_get_type ())))))); | |||
80 | ||||
81 | switch (prop_id) | |||
82 | { | |||
83 | case PROP_DOCUMENT: | |||
84 | stream->priv->doc = LAPIZ_DOCUMENT (g_value_get_object (value))((((LapizDocument*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((g_value_get_object (value))), ((lapiz_document_get_type( ))))))); | |||
85 | break; | |||
86 | ||||
87 | default: | |||
88 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "lapiz-document-output-stream.c", 88, ("property"), _glib__property_id , _glib__pspec->name, g_type_name ((((((GTypeClass*) (((GTypeInstance *) (_glib__pspec))->g_class))->g_type)))), (g_type_name ((((((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); | |||
89 | break; | |||
90 | } | |||
91 | } | |||
92 | ||||
93 | static void | |||
94 | lapiz_document_output_stream_get_property (GObject *object, | |||
95 | guint prop_id, | |||
96 | GValue *value, | |||
97 | GParamSpec *pspec) | |||
98 | { | |||
99 | LapizDocumentOutputStream *stream = LAPIZ_DOCUMENT_OUTPUT_STREAM (object)((((LapizDocumentOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((object)), ((lapiz_document_output_stream_get_type ())))))); | |||
100 | ||||
101 | switch (prop_id) | |||
102 | { | |||
103 | case PROP_DOCUMENT: | |||
104 | g_value_set_object (value, stream->priv->doc); | |||
105 | break; | |||
106 | ||||
107 | default: | |||
108 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "lapiz-document-output-stream.c", 108, ("property"), _glib__property_id , _glib__pspec->name, g_type_name ((((((GTypeClass*) (((GTypeInstance *) (_glib__pspec))->g_class))->g_type)))), (g_type_name ((((((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); | |||
109 | break; | |||
110 | } | |||
111 | } | |||
112 | ||||
113 | static void | |||
114 | lapiz_document_output_stream_finalize (GObject *object) | |||
115 | { | |||
116 | LapizDocumentOutputStream *stream = LAPIZ_DOCUMENT_OUTPUT_STREAM (object)((((LapizDocumentOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((object)), ((lapiz_document_output_stream_get_type ())))))); | |||
117 | ||||
118 | g_free (stream->priv->buffer); | |||
119 | ||||
120 | G_OBJECT_CLASS (lapiz_document_output_stream_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((lapiz_document_output_stream_parent_class)), (((GType) ( (20) << (2))))))))->finalize (object); | |||
121 | } | |||
122 | ||||
123 | static void | |||
124 | lapiz_document_output_stream_constructed (GObject *object) | |||
125 | { | |||
126 | LapizDocumentOutputStream *stream = LAPIZ_DOCUMENT_OUTPUT_STREAM (object)((((LapizDocumentOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((object)), ((lapiz_document_output_stream_get_type ())))))); | |||
127 | ||||
128 | if (!stream->priv->doc) | |||
129 | { | |||
130 | g_critical ("This should never happen, a problem happened constructing the Document Output Stream!"); | |||
131 | return; | |||
132 | } | |||
133 | ||||
134 | /* Init the undoable action */ | |||
135 | ctk_source_buffer_begin_not_undoable_action (CTK_SOURCE_BUFFER (stream->priv->doc)((((CtkSourceBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((stream->priv->doc)), ((ctk_source_buffer_get_type ( )))))))); | |||
136 | /* clear the buffer */ | |||
137 | ctk_text_buffer_set_text (CTK_TEXT_BUFFER (stream->priv->doc)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((stream->priv->doc)), ((ctk_text_buffer_get_type () )))))), | |||
138 | "", 0); | |||
139 | ctk_text_buffer_set_modified (CTK_TEXT_BUFFER (stream->priv->doc)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((stream->priv->doc)), ((ctk_text_buffer_get_type () )))))), | |||
140 | FALSE(0)); | |||
141 | ||||
142 | ctk_source_buffer_end_not_undoable_action (CTK_SOURCE_BUFFER (stream->priv->doc)((((CtkSourceBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((stream->priv->doc)), ((ctk_source_buffer_get_type ( )))))))); | |||
143 | } | |||
144 | ||||
145 | static void | |||
146 | lapiz_document_output_stream_class_init (LapizDocumentOutputStreamClass *klass) | |||
147 | { | |||
148 | GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), (((GType) ((20) << (2)))))))); | |||
149 | GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass)((((GOutputStreamClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), ((g_output_stream_get_type ())))))); | |||
150 | ||||
151 | object_class->get_property = lapiz_document_output_stream_get_property; | |||
152 | object_class->set_property = lapiz_document_output_stream_set_property; | |||
153 | object_class->finalize = lapiz_document_output_stream_finalize; | |||
154 | object_class->constructed = lapiz_document_output_stream_constructed; | |||
155 | ||||
156 | stream_class->write_fn = lapiz_document_output_stream_write; | |||
157 | stream_class->flush = lapiz_document_output_stream_flush; | |||
158 | stream_class->close_fn = lapiz_document_output_stream_close; | |||
159 | ||||
160 | g_object_class_install_property (object_class, | |||
161 | PROP_DOCUMENT, | |||
162 | g_param_spec_object ("document", | |||
163 | "Document", | |||
164 | "The document which is written", | |||
165 | LAPIZ_TYPE_DOCUMENT(lapiz_document_get_type()), | |||
166 | G_PARAM_READWRITE | | |||
167 | G_PARAM_CONSTRUCT_ONLY)); | |||
168 | } | |||
169 | ||||
170 | static void | |||
171 | lapiz_document_output_stream_init (LapizDocumentOutputStream *stream) | |||
172 | { | |||
173 | stream->priv = lapiz_document_output_stream_get_instance_private (stream); | |||
174 | ||||
175 | stream->priv->buffer = NULL((void*)0); | |||
176 | stream->priv->buflen = 0; | |||
177 | ||||
178 | stream->priv->is_initialized = FALSE(0); | |||
179 | stream->priv->is_closed = FALSE(0); | |||
180 | } | |||
181 | ||||
182 | static LapizDocumentNewlineType | |||
183 | get_newline_type (CtkTextIter *end) | |||
184 | { | |||
185 | LapizDocumentNewlineType res; | |||
186 | CtkTextIter copy; | |||
187 | gunichar c; | |||
188 | ||||
189 | copy = *end; | |||
190 | c = ctk_text_iter_get_char (©); | |||
191 | ||||
192 | if (g_unichar_break_type (c) == G_UNICODE_BREAK_CARRIAGE_RETURN) | |||
193 | { | |||
194 | if (ctk_text_iter_forward_char (©) && | |||
195 | g_unichar_break_type (ctk_text_iter_get_char (©)) == G_UNICODE_BREAK_LINE_FEED) | |||
196 | { | |||
197 | res = LAPIZ_DOCUMENT_NEWLINE_TYPE_CR_LF; | |||
198 | } | |||
199 | else | |||
200 | { | |||
201 | res = LAPIZ_DOCUMENT_NEWLINE_TYPE_CR; | |||
202 | } | |||
203 | } | |||
204 | else | |||
205 | { | |||
206 | res = LAPIZ_DOCUMENT_NEWLINE_TYPE_LF; | |||
207 | } | |||
208 | ||||
209 | return res; | |||
210 | } | |||
211 | ||||
212 | GOutputStream * | |||
213 | lapiz_document_output_stream_new (LapizDocument *doc) | |||
214 | { | |||
215 | return G_OUTPUT_STREAM (g_object_new (LAPIZ_TYPE_DOCUMENT_OUTPUT_STREAM,((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((g_object_new ((lapiz_document_output_stream_get_type ()) , "document", doc, ((void*)0)))), ((g_output_stream_get_type ( ))))))) | |||
216 | "document", doc, NULL))((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((g_object_new ((lapiz_document_output_stream_get_type ()) , "document", doc, ((void*)0)))), ((g_output_stream_get_type ( ))))))); | |||
217 | } | |||
218 | ||||
219 | LapizDocumentNewlineType | |||
220 | lapiz_document_output_stream_detect_newline_type (LapizDocumentOutputStream *stream) | |||
221 | { | |||
222 | LapizDocumentNewlineType type; | |||
223 | CtkTextIter iter; | |||
224 | ||||
225 | g_return_val_if_fail (LAPIZ_IS_DOCUMENT_OUTPUT_STREAM (stream),do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((stream)); GType __t = ((lapiz_document_output_stream_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "LAPIZ_IS_DOCUMENT_OUTPUT_STREAM (stream)" ); return (LAPIZ_DOCUMENT_NEWLINE_TYPE_LF); } } while (0) | |||
226 | LAPIZ_DOCUMENT_NEWLINE_TYPE_DEFAULT)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((stream)); GType __t = ((lapiz_document_output_stream_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "LAPIZ_IS_DOCUMENT_OUTPUT_STREAM (stream)" ); return (LAPIZ_DOCUMENT_NEWLINE_TYPE_LF); } } while (0); | |||
227 | ||||
228 | type = LAPIZ_DOCUMENT_NEWLINE_TYPE_DEFAULTLAPIZ_DOCUMENT_NEWLINE_TYPE_LF; | |||
229 | ||||
230 | ctk_text_buffer_get_start_iter (CTK_TEXT_BUFFER (stream->priv->doc)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((stream->priv->doc)), ((ctk_text_buffer_get_type () )))))), | |||
231 | &iter); | |||
232 | ||||
233 | if (ctk_text_iter_ends_line (&iter) || ctk_text_iter_forward_to_line_end (&iter)) | |||
234 | { | |||
235 | type = get_newline_type (&iter); | |||
236 | } | |||
237 | ||||
238 | return type; | |||
239 | } | |||
240 | ||||
241 | /* If the last char is a newline, remove it from the buffer (otherwise | |||
242 | CtkTextView shows it as an empty line). See bug #324942. */ | |||
243 | static void | |||
244 | remove_ending_newline (LapizDocumentOutputStream *stream) | |||
245 | { | |||
246 | CtkTextIter end; | |||
247 | CtkTextIter start; | |||
248 | ||||
249 | ctk_text_buffer_get_end_iter (CTK_TEXT_BUFFER (stream->priv->doc)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((stream->priv->doc)), ((ctk_text_buffer_get_type () )))))), &end); | |||
250 | start = end; | |||
251 | ||||
252 | ctk_text_iter_set_line_offset (&start, 0); | |||
253 | ||||
254 | if (ctk_text_iter_ends_line (&start) && | |||
255 | ctk_text_iter_backward_line (&start)) | |||
256 | { | |||
257 | if (!ctk_text_iter_ends_line (&start)) | |||
258 | { | |||
259 | ctk_text_iter_forward_to_line_end (&start); | |||
260 | } | |||
261 | ||||
262 | /* Delete the empty line which is from 'start' to 'end' */ | |||
263 | ctk_text_buffer_delete (CTK_TEXT_BUFFER (stream->priv->doc)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((stream->priv->doc)), ((ctk_text_buffer_get_type () )))))), | |||
264 | &start, | |||
265 | &end); | |||
266 | } | |||
267 | } | |||
268 | ||||
269 | static void | |||
270 | end_append_text_to_document (LapizDocumentOutputStream *stream) | |||
271 | { | |||
272 | remove_ending_newline (stream); | |||
273 | ||||
274 | ctk_text_buffer_set_modified (CTK_TEXT_BUFFER (stream->priv->doc)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((stream->priv->doc)), ((ctk_text_buffer_get_type () )))))), | |||
275 | FALSE(0)); | |||
276 | ||||
277 | ctk_source_buffer_end_not_undoable_action (CTK_SOURCE_BUFFER (stream->priv->doc)((((CtkSourceBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((stream->priv->doc)), ((ctk_source_buffer_get_type ( )))))))); | |||
278 | } | |||
279 | ||||
280 | static gssize | |||
281 | lapiz_document_output_stream_write (GOutputStream *stream, | |||
282 | const void *buffer, | |||
283 | gsize count, | |||
284 | GCancellable *cancellable, | |||
285 | GError **error) | |||
286 | { | |||
287 | LapizDocumentOutputStream *ostream; | |||
288 | gchar *text; | |||
289 | gsize len; | |||
290 | gboolean freetext = FALSE(0); | |||
291 | const gchar *end; | |||
292 | gboolean valid; | |||
293 | ||||
294 | if (g_cancellable_set_error_if_cancelled (cancellable, error)) | |||
295 | return -1; | |||
296 | ||||
297 | ostream = LAPIZ_DOCUMENT_OUTPUT_STREAM (stream)((((LapizDocumentOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((stream)), ((lapiz_document_output_stream_get_type ())))))); | |||
298 | ||||
299 | if (!ostream->priv->is_initialized) | |||
300 | { | |||
301 | /* Init the undoable action */ | |||
302 | ctk_source_buffer_begin_not_undoable_action (CTK_SOURCE_BUFFER (ostream->priv->doc)((((CtkSourceBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ostream->priv->doc)), ((ctk_source_buffer_get_type ()))))))); | |||
303 | ||||
304 | ctk_text_buffer_get_start_iter (CTK_TEXT_BUFFER (ostream->priv->doc)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ostream->priv->doc)), ((ctk_text_buffer_get_type ( ))))))), | |||
305 | &ostream->priv->pos); | |||
306 | ostream->priv->is_initialized = TRUE(!(0)); | |||
307 | } | |||
308 | ||||
309 | if (ostream->priv->buflen > 0) | |||
310 | { | |||
311 | len = ostream->priv->buflen + count; | |||
312 | text = g_new (gchar , len + 1)((gchar *) g_malloc_n ((len + 1), sizeof (gchar))); | |||
313 | memcpy (text, ostream->priv->buffer, ostream->priv->buflen); | |||
314 | memcpy (text + ostream->priv->buflen, buffer, count); | |||
315 | text[len] = '\0'; | |||
316 | g_free (ostream->priv->buffer); | |||
317 | ostream->priv->buffer = NULL((void*)0); | |||
318 | ostream->priv->buflen = 0; | |||
319 | freetext = TRUE(!(0)); | |||
320 | } | |||
321 | else | |||
322 | { | |||
323 | text = (gchar *) buffer; | |||
324 | len = count; | |||
325 | } | |||
326 | ||||
327 | /* validate */ | |||
328 | valid = g_utf8_validate (text, len, &end); | |||
329 | ||||
330 | /* Avoid keeping a CRLF across two buffers. */ | |||
331 | if (valid && len > 1 && end[-1] == '\r') | |||
| ||||
332 | { | |||
333 | valid = FALSE(0); | |||
334 | end--; | |||
335 | } | |||
336 | ||||
337 | if (!valid) | |||
338 | { | |||
339 | gsize nvalid = end - text; | |||
340 | gsize remainder = len - nvalid; | |||
341 | gunichar ch; | |||
342 | ||||
343 | if ((remainder < MAX_UNICHAR_LEN6) && | |||
344 | ((ch = g_utf8_get_char_validated (text + nvalid, remainder)) == (gunichar)-2 || | |||
345 | ch == (gunichar)'\r')) | |||
346 | { | |||
347 | ostream->priv->buffer = g_strndup (end, remainder); | |||
348 | ostream->priv->buflen = remainder; | |||
349 | len -= remainder; | |||
350 | } | |||
351 | else | |||
352 | { | |||
353 | /* TODO: we could escape invalid text and tag it in red | |||
354 | * and make the doc readonly. | |||
355 | */ | |||
356 | g_set_error (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_INVALID_DATA, | |||
357 | _("Invalid UTF-8 sequence in input")gettext ("Invalid UTF-8 sequence in input")); | |||
358 | ||||
359 | if (freetext) | |||
360 | g_free (text); | |||
361 | ||||
362 | return -1; | |||
363 | } | |||
364 | } | |||
365 | ||||
366 | ctk_text_buffer_insert (CTK_TEXT_BUFFER (ostream->priv->doc)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ostream->priv->doc)), ((ctk_text_buffer_get_type ( ))))))), | |||
367 | &ostream->priv->pos, text, len); | |||
368 | ||||
369 | if (freetext) | |||
370 | g_free (text); | |||
371 | ||||
372 | return count; | |||
373 | } | |||
374 | ||||
375 | static gboolean | |||
376 | lapiz_document_output_stream_flush (GOutputStream *stream, | |||
377 | GCancellable *cancellable, | |||
378 | GError **error) | |||
379 | { | |||
380 | LapizDocumentOutputStream *ostream = LAPIZ_DOCUMENT_OUTPUT_STREAM (stream)((((LapizDocumentOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((stream)), ((lapiz_document_output_stream_get_type ())))))); | |||
381 | ||||
382 | /* Flush deferred data if some. */ | |||
383 | if (!ostream->priv->is_closed && ostream->priv->is_initialized && | |||
| ||||
384 | ostream->priv->buflen > 0 && | |||
385 | lapiz_document_output_stream_write (stream, "", 0, cancellable, | |||
386 | error) == -1) | |||
387 | return FALSE(0); | |||
388 | ||||
389 | return TRUE(!(0)); | |||
390 | } | |||
391 | ||||
392 | static gboolean | |||
393 | lapiz_document_output_stream_close (GOutputStream *stream, | |||
394 | GCancellable *cancellable G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
395 | GError **error) | |||
396 | { | |||
397 | LapizDocumentOutputStream *ostream = LAPIZ_DOCUMENT_OUTPUT_STREAM (stream)((((LapizDocumentOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((stream)), ((lapiz_document_output_stream_get_type ())))))); | |||
398 | ||||
399 | if (!ostream->priv->is_closed && ostream->priv->is_initialized) | |||
400 | { | |||
401 | end_append_text_to_document (ostream); | |||
402 | ostream->priv->is_closed = TRUE(!(0)); | |||
403 | } | |||
404 | ||||
405 | if (ostream->priv->buflen > 0) | |||
406 | { | |||
407 | g_set_error (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_INVALID_DATA, | |||
408 | _("Incomplete UTF-8 sequence in input")gettext ("Incomplete UTF-8 sequence in input")); | |||
409 | return FALSE(0); | |||
410 | } | |||
411 | ||||
412 | return TRUE(!(0)); | |||
413 | } |