Bug Summary

File:_build/../ctksourceview/ctksourcebufferoutputstream.c
Warning:line 283, column 9
Access to field 'data' results in a dereference of a null pointer (loaded from field 'current_encoding')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctksourcebufferoutputstream.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/_build -fcoverage-compilation-dir=/rootdir/_build -resource-dir /usr/lib/llvm-19/lib/clang/19 -I ctksourceview/libctksourceview-4core.a.p -I ctksourceview -I ../ctksourceview -I . -I .. -I /usr/include/fribidi -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/libxml2 -D _FILE_OFFSET_BITS=64 -D HAVE_CONFIG_H -D CTK_SOURCE_COMPILATION -D G_LOG_DOMAIN="CtkSourceView" -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-cast-function-type -Wno-missing-field-initializers -Wno-sign-compare -Wno-unused-parameter -std=gnu99 -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-07-25-105035-13980-1 -x c ../ctksourceview/ctksourcebufferoutputstream.c
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
2/*
3 * This file is part of CtkSourceView
4 *
5 * Copyright (C) 2010 - Ignacio Casal Quinteiro
6 * Copyright (C) 2014 - Sébastien Wilmet <swilmet@gnome.org>
7 *
8 * CtkSourceView is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * CtkSourceView is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22#ifdef HAVE_CONFIG_H1
23#include <config.h>
24#endif
25
26#include "ctksourcebufferoutputstream.h"
27#include <string.h>
28#include <errno(*__errno_location ()).h>
29#include <glib/gi18n-lib.h>
30#include "ctksourcebuffer.h"
31#include "ctksourcebuffer-private.h"
32#include "ctksourceencoding.h"
33#include "ctksourcefileloader.h"
34
35/* NOTE: never use async methods on this stream, the stream is just
36 * a wrapper around CtkTextBuffer api so that we can use GIO Stream
37 * methods, but the underlying code operates on a CtkTextBuffer, so
38 * there is no I/O involved and should be accessed only by the main
39 * thread.
40 */
41
42/* NOTE2: welcome to a really big headache. At the beginning this was
43 * split in several classes, one for encoding detection, another
44 * for UTF-8 conversion and another for validation. The reason this is
45 * all together is because we need specific information from all parts
46 * in other to be able to mark characters as invalid if there was some
47 * specific problem on the conversion.
48 */
49
50/* The code comes from gedit, the class was GeditDocumentOutputStream. */
51
52#if 0
53#define DEBUG(x) (x)
54#else
55#define DEBUG(x)
56#endif
57
58#define MAX_UNICHAR_LEN6 6
59
60struct _CtkSourceBufferOutputStreamPrivate
61{
62 CtkSourceBuffer *source_buffer;
63 CtkTextIter pos;
64
65 gchar *buffer;
66 gsize buflen;
67
68 gchar *iconv_buffer;
69 gsize iconv_buflen;
70
71 /* Encoding detection */
72 GIConv iconv;
73 GCharsetConverter *charset_conv;
74
75 GSList *encodings;
76 GSList *current_encoding;
77
78 gint error_offset;
79 guint n_fallback_errors;
80
81 guint is_utf8 : 1;
82 guint use_first : 1;
83
84 guint is_initialized : 1;
85 guint is_closed : 1;
86
87 guint remove_trailing_newline : 1;
88};
89
90enum
91{
92 PROP_0,
93 PROP_BUFFER,
94 PROP_REMOVE_TRAILING_NEWLINE
95};
96
97G_DEFINE_TYPE_WITH_PRIVATE (CtkSourceBufferOutputStream, ctk_source_buffer_output_stream, G_TYPE_OUTPUT_STREAM)static void ctk_source_buffer_output_stream_init (CtkSourceBufferOutputStream
*self); static void ctk_source_buffer_output_stream_class_init
(CtkSourceBufferOutputStreamClass *klass); static GType ctk_source_buffer_output_stream_get_type_once
(void); static gpointer ctk_source_buffer_output_stream_parent_class
= ((void*)0); static gint CtkSourceBufferOutputStream_private_offset
; static void ctk_source_buffer_output_stream_class_intern_init
(gpointer klass) { ctk_source_buffer_output_stream_parent_class
= g_type_class_peek_parent (klass); if (CtkSourceBufferOutputStream_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &CtkSourceBufferOutputStream_private_offset
); ctk_source_buffer_output_stream_class_init ((CtkSourceBufferOutputStreamClass
*) klass); } __attribute__ ((__unused__)) static inline gpointer
ctk_source_buffer_output_stream_get_instance_private (CtkSourceBufferOutputStream
*self) { return (((gpointer) ((guint8*) (self) + (glong) (CtkSourceBufferOutputStream_private_offset
)))); } GType ctk_source_buffer_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
= ctk_source_buffer_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 ctk_source_buffer_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 ("CtkSourceBufferOutputStream"
), sizeof (CtkSourceBufferOutputStreamClass), (GClassInitFunc
)(void (*)(void)) ctk_source_buffer_output_stream_class_intern_init
, sizeof (CtkSourceBufferOutputStream), (GInstanceInitFunc)(void
(*)(void)) ctk_source_buffer_output_stream_init, (GTypeFlags
) 0); { {{ CtkSourceBufferOutputStream_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkSourceBufferOutputStreamPrivate
)); };} } return g_define_type_id; }
98
99static gssize ctk_source_buffer_output_stream_write (GOutputStream *stream,
100 const void *buffer,
101 gsize count,
102 GCancellable *cancellable,
103 GError **error);
104
105static gboolean ctk_source_buffer_output_stream_close (GOutputStream *stream,
106 GCancellable *cancellable,
107 GError **error);
108
109static gboolean ctk_source_buffer_output_stream_flush (GOutputStream *stream,
110 GCancellable *cancellable,
111 GError **error);
112
113static void
114ctk_source_buffer_output_stream_set_property (GObject *object,
115 guint prop_id,
116 const GValue *value,
117 GParamSpec *pspec)
118{
119 CtkSourceBufferOutputStream *stream = CTK_SOURCE_BUFFER_OUTPUT_STREAM (object)((((CtkSourceBufferOutputStream*) (void *) ((object)))));
120
121 switch (prop_id)
122 {
123 case PROP_BUFFER:
124 g_assert (stream->priv->source_buffer == NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_14
= 0; if (stream->priv->source_buffer == ((void*)0)) _g_boolean_var_14
= 1; _g_boolean_var_14; }), 1)) ; else g_assertion_message_expr
("CtkSourceView", "../ctksourceview/ctksourcebufferoutputstream.c"
, 124, ((const char*) (__func__)), "stream->priv->source_buffer == NULL"
); } while (0)
;
125 stream->priv->source_buffer = g_value_dup_object (value);
126 break;
127
128 case PROP_REMOVE_TRAILING_NEWLINE:
129 stream->priv->remove_trailing_newline = g_value_get_boolean (value);
130 break;
131
132 default:
133 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'"
, "../ctksourceview/ctksourcebufferoutputstream.c", 133, ("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)
;
134 break;
135 }
136}
137
138static void
139ctk_source_buffer_output_stream_get_property (GObject *object,
140 guint prop_id,
141 GValue *value,
142 GParamSpec *pspec)
143{
144 CtkSourceBufferOutputStream *stream = CTK_SOURCE_BUFFER_OUTPUT_STREAM (object)((((CtkSourceBufferOutputStream*) (void *) ((object)))));
145
146 switch (prop_id)
147 {
148 case PROP_BUFFER:
149 g_value_set_object (value, stream->priv->source_buffer);
150 break;
151
152 case PROP_REMOVE_TRAILING_NEWLINE:
153 g_value_set_boolean (value, stream->priv->remove_trailing_newline);
154 break;
155
156 default:
157 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'"
, "../ctksourceview/ctksourcebufferoutputstream.c", 157, ("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)
;
158 break;
159 }
160}
161
162static void
163ctk_source_buffer_output_stream_dispose (GObject *object)
164{
165 CtkSourceBufferOutputStream *stream = CTK_SOURCE_BUFFER_OUTPUT_STREAM (object)((((CtkSourceBufferOutputStream*) (void *) ((object)))));
166
167 g_clear_object (&stream->priv->source_buffer)do { _Static_assert (sizeof *((&stream->priv->source_buffer
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&stream->priv->source_buffer))) _pp = ((&stream
->priv->source_buffer)); __typeof__ (*((&stream->
priv->source_buffer))) _ptr = *_pp; *_pp = ((void*)0); if (
_ptr) (g_object_unref) (_ptr); } while (0)
;
168 g_clear_object (&stream->priv->charset_conv)do { _Static_assert (sizeof *((&stream->priv->charset_conv
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&stream->priv->charset_conv))) _pp = ((&stream
->priv->charset_conv)); __typeof__ (*((&stream->
priv->charset_conv))) _ptr = *_pp; *_pp = ((void*)0); if (
_ptr) (g_object_unref) (_ptr); } while (0)
;
169
170 G_OBJECT_CLASS (ctk_source_buffer_output_stream_parent_class)((((GObjectClass*) (void *) ((ctk_source_buffer_output_stream_parent_class
)))))
->dispose (object);
171}
172
173static void
174ctk_source_buffer_output_stream_finalize (GObject *object)
175{
176 CtkSourceBufferOutputStream *stream = CTK_SOURCE_BUFFER_OUTPUT_STREAM (object)((((CtkSourceBufferOutputStream*) (void *) ((object)))));
177
178 g_free (stream->priv->buffer);
179 g_free (stream->priv->iconv_buffer);
180 g_slist_free (stream->priv->encodings);
181
182 G_OBJECT_CLASS (ctk_source_buffer_output_stream_parent_class)((((GObjectClass*) (void *) ((ctk_source_buffer_output_stream_parent_class
)))))
->finalize (object);
183}
184
185static void
186ctk_source_buffer_output_stream_constructed (GObject *object)
187{
188 CtkSourceBufferOutputStream *stream = CTK_SOURCE_BUFFER_OUTPUT_STREAM (object)((((CtkSourceBufferOutputStream*) (void *) ((object)))));
189
190 if (stream->priv->source_buffer == NULL((void*)0))
191 {
192 g_critical ("This should never happen, a problem happened constructing the Buffer Output Stream!");
193 return;
194 }
195
196 ctk_source_buffer_begin_not_undoable_action (stream->priv->source_buffer);
197
198 ctk_text_buffer_set_text (CTK_TEXT_BUFFER (stream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((stream->priv->source_buffer
)))))
, "", 0);
199 ctk_text_buffer_set_modified (CTK_TEXT_BUFFER (stream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((stream->priv->source_buffer
)))))
, FALSE(0));
200
201 ctk_source_buffer_end_not_undoable_action (stream->priv->source_buffer);
202
203 G_OBJECT_CLASS (ctk_source_buffer_output_stream_parent_class)((((GObjectClass*) (void *) ((ctk_source_buffer_output_stream_parent_class
)))))
->constructed (object);
204}
205
206static void
207ctk_source_buffer_output_stream_class_init (CtkSourceBufferOutputStreamClass *klass)
208{
209 GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) ((klass)))));
210 GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass)((((GOutputStreamClass*) (void *) ((klass)))));
211
212 object_class->get_property = ctk_source_buffer_output_stream_get_property;
213 object_class->set_property = ctk_source_buffer_output_stream_set_property;
214 object_class->dispose = ctk_source_buffer_output_stream_dispose;
215 object_class->finalize = ctk_source_buffer_output_stream_finalize;
216 object_class->constructed = ctk_source_buffer_output_stream_constructed;
217
218 stream_class->write_fn = ctk_source_buffer_output_stream_write;
219 stream_class->close_fn = ctk_source_buffer_output_stream_close;
220 stream_class->flush = ctk_source_buffer_output_stream_flush;
221
222 g_object_class_install_property (object_class,
223 PROP_BUFFER,
224 g_param_spec_object ("buffer",
225 "CtkSourceBuffer",
226 "",
227 CTK_SOURCE_TYPE_BUFFER(ctk_source_buffer_get_type ()),
228 G_PARAM_READWRITE |
229 G_PARAM_CONSTRUCT_ONLY |
230 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
231
232 g_object_class_install_property (object_class,
233 PROP_REMOVE_TRAILING_NEWLINE,
234 g_param_spec_boolean ("remove-trailing-newline",
235 "Remove trailing newline",
236 "",
237 TRUE(!(0)),
238 G_PARAM_READWRITE |
239 G_PARAM_CONSTRUCT_ONLY |
240 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
241}
242
243static void
244ctk_source_buffer_output_stream_init (CtkSourceBufferOutputStream *stream)
245{
246 stream->priv = ctk_source_buffer_output_stream_get_instance_private (stream);
247
248 stream->priv->buffer = NULL((void*)0);
249 stream->priv->buflen = 0;
250
251 stream->priv->charset_conv = NULL((void*)0);
252 stream->priv->encodings = NULL((void*)0);
253 stream->priv->current_encoding = NULL((void*)0);
254
255 stream->priv->error_offset = -1;
256
257 stream->priv->is_initialized = FALSE(0);
258 stream->priv->is_closed = FALSE(0);
259 stream->priv->is_utf8 = FALSE(0);
260 stream->priv->use_first = FALSE(0);
261}
262
263static const CtkSourceEncoding *
264get_encoding (CtkSourceBufferOutputStream *stream)
265{
266 if (stream->priv->current_encoding == NULL((void*)0))
14
Assuming field 'current_encoding' is equal to NULL
15
Taking true branch
267 {
268 stream->priv->current_encoding = stream->priv->encodings;
269 }
270 else
271 {
272 stream->priv->current_encoding = g_slist_next (stream->priv->current_encoding)((stream->priv->current_encoding) ? (((GSList *)(stream
->priv->current_encoding))->next) : ((void*)0))
;
273 }
274
275 if (stream->priv->current_encoding
15.1
Field 'current_encoding' is equal to NULL
!= NULL((void*)0))
16
Taking false branch
276 {
277 return stream->priv->current_encoding->data;
278 }
279
280 stream->priv->use_first = TRUE(!(0));
281 stream->priv->current_encoding = stream->priv->encodings;
17
Null pointer value stored to field 'current_encoding'
282
283 return stream->priv->current_encoding->data;
18
Access to field 'data' results in a dereference of a null pointer (loaded from field 'current_encoding')
284}
285
286static gboolean
287try_convert (GCharsetConverter *converter,
288 const void *inbuf,
289 gsize inbuf_size)
290{
291 GError *err;
292 gsize bytes_read, nread;
293 gsize bytes_written, nwritten;
294 GConverterResult res;
295 gchar *out;
296 gboolean ret;
297 gsize out_size;
298
299 if (inbuf == NULL((void*)0) || inbuf_size == 0)
300 {
301 return FALSE(0);
302 }
303
304 err = NULL((void*)0);
305 nread = 0;
306 nwritten = 0;
307 out_size = inbuf_size * 4;
308 out = g_malloc (out_size);
309
310 do
311 {
312 res = g_converter_convert (G_CONVERTER (converter)((((GConverter*) (void *) ((converter))))),
313 (gchar *)inbuf + nread,
314 inbuf_size - nread,
315 (gchar *)out + nwritten,
316 out_size - nwritten,
317 G_CONVERTER_INPUT_AT_END,
318 &bytes_read,
319 &bytes_written,
320 &err);
321
322 nread += bytes_read;
323 nwritten += bytes_written;
324 } while (res != G_CONVERTER_FINISHED && res != G_CONVERTER_ERROR && err == NULL((void*)0));
325
326 if (err != NULL((void*)0))
327 {
328 if (err->code == G_CONVERT_ERROR_PARTIAL_INPUT)
329 {
330 /* FIXME We can get partial input while guessing the
331 encoding because we just take some amount of text
332 to guess from. */
333 ret = TRUE(!(0));
334 }
335 else
336 {
337 ret = FALSE(0);
338 }
339
340 g_error_free (err);
341 }
342 else
343 {
344 ret = TRUE(!(0));
345 }
346
347 /* FIXME: Check the remainder? */
348 if (ret == TRUE(!(0)) && !g_utf8_validate (out, nwritten, NULL((void*)0)))
349 {
350 ret = FALSE(0);
351 }
352
353 g_free (out);
354
355 return ret;
356}
357
358static GCharsetConverter *
359guess_encoding (CtkSourceBufferOutputStream *stream,
360 const void *inbuf,
361 gsize inbuf_size)
362{
363 GCharsetConverter *conv = NULL((void*)0);
364
365 if (inbuf == NULL((void*)0) || inbuf_size == 0)
7
Assuming 'inbuf' is not equal to NULL
8
Assuming 'inbuf_size' is not equal to 0
366 {
367 stream->priv->is_utf8 = TRUE(!(0));
368 return NULL((void*)0);
369 }
370
371 if (stream->priv->encodings != NULL((void*)0) &&
9
Assuming field 'encodings' is equal to NULL
372 stream->priv->encodings->next == NULL((void*)0))
373 {
374 stream->priv->use_first = TRUE(!(0));
375 }
376
377 /* We just check the first block */
378 while (TRUE(!(0)))
10
Loop condition is true. Entering loop body
379 {
380 const CtkSourceEncoding *enc;
381
382 g_clear_object (&conv)do { _Static_assert (sizeof *((&conv)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&conv)
)) _pp = ((&conv)); __typeof__ (*((&conv))) _ptr = *_pp
; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
11
Taking false branch
12
Loop condition is false. Exiting loop
383
384 /* We get an encoding from the list */
385 enc = get_encoding (stream);
13
Calling 'get_encoding'
386
387 /* if it is NULL we didn't guess anything */
388 if (enc == NULL((void*)0))
389 {
390 break;
391 }
392
393 DEBUG ({
394 g_print ("trying charset: %s\n",
395 ctk_source_encoding_get_charset (stream->priv->current_encoding->data));
396 });
397
398 if (enc == ctk_source_encoding_get_utf8 ())
399 {
400 gsize remainder;
401 const gchar *end;
402
403 if (g_utf8_validate (inbuf, inbuf_size, &end) ||
404 stream->priv->use_first)
405 {
406 stream->priv->is_utf8 = TRUE(!(0));
407 break;
408 }
409
410 /* Check if the end is less than one char */
411 remainder = inbuf_size - (end - (gchar *)inbuf);
412 if (remainder < 6)
413 {
414 stream->priv->is_utf8 = TRUE(!(0));
415 break;
416 }
417
418 continue;
419 }
420
421 conv = g_charset_converter_new ("UTF-8",
422 ctk_source_encoding_get_charset (enc),
423 NULL((void*)0));
424
425 /* If we tried all encodings we use the first one */
426 if (stream->priv->use_first)
427 {
428 break;
429 }
430
431 /* Try to convert */
432 if (try_convert (conv, inbuf, inbuf_size))
433 {
434 break;
435 }
436 }
437
438 if (conv != NULL((void*)0))
439 {
440 g_converter_reset (G_CONVERTER (conv)((((GConverter*) (void *) ((conv))))));
441 }
442
443 return conv;
444}
445
446static CtkSourceNewlineType
447get_newline_type (CtkTextIter *end)
448{
449 CtkSourceNewlineType res;
450 CtkTextIter copy;
451 gunichar c;
452
453 copy = *end;
454 c = ctk_text_iter_get_char (&copy);
455
456 if (g_unichar_break_type (c) == G_UNICODE_BREAK_CARRIAGE_RETURN)
457 {
458 if (ctk_text_iter_forward_char (&copy) &&
459 g_unichar_break_type (ctk_text_iter_get_char (&copy)) == G_UNICODE_BREAK_LINE_FEED)
460 {
461 res = CTK_SOURCE_NEWLINE_TYPE_CR_LF;
462 }
463 else
464 {
465 res = CTK_SOURCE_NEWLINE_TYPE_CR;
466 }
467 }
468 else
469 {
470 res = CTK_SOURCE_NEWLINE_TYPE_LF;
471 }
472
473 return res;
474}
475
476CtkSourceBufferOutputStream *
477ctk_source_buffer_output_stream_new (CtkSourceBuffer *buffer,
478 GSList *candidate_encodings,
479 gboolean remove_trailing_newline)
480{
481 CtkSourceBufferOutputStream *stream;
482
483 stream = g_object_new (CTK_SOURCE_TYPE_BUFFER_OUTPUT_STREAM(ctk_source_buffer_output_stream_get_type ()),
484 "buffer", buffer,
485 "remove-trailing-newline", remove_trailing_newline,
486 NULL((void*)0));
487
488 stream->priv->encodings = g_slist_copy (candidate_encodings);
489
490 return stream;
491}
492
493CtkSourceNewlineType
494ctk_source_buffer_output_stream_detect_newline_type (CtkSourceBufferOutputStream *stream)
495{
496 CtkSourceNewlineType type;
497 CtkTextIter iter;
498
499 g_return_val_if_fail (CTK_SOURCE_IS_BUFFER_OUTPUT_STREAM (stream),do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_15
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((stream)); GType __t = ((ctk_source_buffer_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; }))))) _g_boolean_var_15 = 1; _g_boolean_var_15; }), 1)
)) { } else { g_return_if_fail_warning ("CtkSourceView", ((const
char*) (__func__)), "CTK_SOURCE_IS_BUFFER_OUTPUT_STREAM (stream)"
); return (CTK_SOURCE_NEWLINE_TYPE_LF); } } while (0)
500 CTK_SOURCE_NEWLINE_TYPE_DEFAULT)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_15
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((stream)); GType __t = ((ctk_source_buffer_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; }))))) _g_boolean_var_15 = 1; _g_boolean_var_15; }), 1)
)) { } else { g_return_if_fail_warning ("CtkSourceView", ((const
char*) (__func__)), "CTK_SOURCE_IS_BUFFER_OUTPUT_STREAM (stream)"
); return (CTK_SOURCE_NEWLINE_TYPE_LF); } } while (0)
;
501
502 if (stream->priv->source_buffer == NULL((void*)0))
503 {
504 return CTK_SOURCE_NEWLINE_TYPE_DEFAULTCTK_SOURCE_NEWLINE_TYPE_LF;
505 }
506
507 type = CTK_SOURCE_NEWLINE_TYPE_DEFAULTCTK_SOURCE_NEWLINE_TYPE_LF;
508
509 ctk_text_buffer_get_start_iter (CTK_TEXT_BUFFER (stream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((stream->priv->source_buffer
)))))
,
510 &iter);
511
512 if (ctk_text_iter_ends_line (&iter) || ctk_text_iter_forward_to_line_end (&iter))
513 {
514 type = get_newline_type (&iter);
515 }
516
517 return type;
518}
519
520const CtkSourceEncoding *
521ctk_source_buffer_output_stream_get_guessed (CtkSourceBufferOutputStream *stream)
522{
523 g_return_val_if_fail (CTK_SOURCE_IS_BUFFER_OUTPUT_STREAM (stream), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_16
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((stream)); GType __t = ((ctk_source_buffer_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; }))))) _g_boolean_var_16 = 1; _g_boolean_var_16; }), 1)
)) { } else { g_return_if_fail_warning ("CtkSourceView", ((const
char*) (__func__)), "CTK_SOURCE_IS_BUFFER_OUTPUT_STREAM (stream)"
); return (((void*)0)); } } while (0)
;
524
525 if (stream->priv->current_encoding != NULL((void*)0))
526 {
527 return stream->priv->current_encoding->data;
528 }
529 else if (stream->priv->is_utf8 || !stream->priv->is_initialized)
530 {
531 /* If it is not initialized we assume that we are trying to
532 * convert the empty string.
533 */
534 return ctk_source_encoding_get_utf8 ();
535 }
536
537 return NULL((void*)0);
538}
539
540guint
541ctk_source_buffer_output_stream_get_num_fallbacks (CtkSourceBufferOutputStream *stream)
542{
543 g_return_val_if_fail (CTK_SOURCE_IS_BUFFER_OUTPUT_STREAM (stream), 0)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_17
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((stream)); GType __t = ((ctk_source_buffer_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; }))))) _g_boolean_var_17 = 1; _g_boolean_var_17; }), 1)
)) { } else { g_return_if_fail_warning ("CtkSourceView", ((const
char*) (__func__)), "CTK_SOURCE_IS_BUFFER_OUTPUT_STREAM (stream)"
); return (0); } } while (0)
;
544
545 return stream->priv->n_fallback_errors;
546}
547
548static void
549apply_error_tag (CtkSourceBufferOutputStream *stream)
550{
551 CtkTextIter start;
552
553 if (stream->priv->error_offset == -1 ||
554 stream->priv->source_buffer == NULL((void*)0))
555 {
556 return;
557 }
558
559 ctk_text_buffer_get_iter_at_offset (CTK_TEXT_BUFFER (stream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((stream->priv->source_buffer
)))))
,
560 &start, stream->priv->error_offset);
561
562 _ctk_source_buffer_set_as_invalid_character (stream->priv->source_buffer,
563 &start,
564 &stream->priv->pos);
565
566 stream->priv->error_offset = -1;
567}
568
569static void
570insert_fallback (CtkSourceBufferOutputStream *stream,
571 const gchar *buffer)
572{
573 guint8 out[4];
574 guint8 v;
575 const gchar hex[] = "0123456789ABCDEF";
576
577 if (stream->priv->source_buffer == NULL((void*)0))
578 {
579 return;
580 }
581
582 /* If we are here it is because we are pointing to an invalid char so we
583 * substitute it by an hex value.
584 */
585 v = *(guint8 *)buffer;
586 out[0] = '\\';
587 out[1] = hex[(v & 0xf0) >> 4];
588 out[2] = hex[(v & 0x0f) >> 0];
589 out[3] = '\0';
590
591 ctk_text_buffer_insert (CTK_TEXT_BUFFER (stream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((stream->priv->source_buffer
)))))
,
592 &stream->priv->pos, (const gchar *)out, 3);
593
594 ++stream->priv->n_fallback_errors;
595}
596
597static void
598validate_and_insert (CtkSourceBufferOutputStream *stream,
599 gchar *buffer,
600 gsize count,
601 gboolean owned)
602{
603 CtkTextBuffer *text_buffer;
604 CtkTextIter *iter;
605 gsize len;
606 gchar *free_text = NULL((void*)0);
607
608 if (stream->priv->source_buffer == NULL((void*)0))
609 {
610 return;
611 }
612
613 text_buffer = CTK_TEXT_BUFFER (stream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((stream->priv->source_buffer
)))))
;
614 iter = &stream->priv->pos;
615 len = count;
616
617 while (len != 0)
618 {
619 const gchar *end;
620 gboolean valid;
621 gsize nvalid;
622
623 /* validate */
624 valid = g_utf8_validate (buffer, len, &end);
625 nvalid = end - buffer;
626
627 /* Note: this is a workaround for a 'bug' in CtkTextBuffer where
628 inserting first a \r and then in a second insert, a \n,
629 will result in two lines being added instead of a single
630 one */
631
632 if (valid)
633 {
634 gchar *ptr;
635
636 ptr = g_utf8_find_prev_char (buffer, buffer + len);
637
638 if (ptr && *ptr == '\r' && ptr - buffer == (glong)len - 1)
639 {
640 stream->priv->buffer = g_new (gchar, 2)(gchar *) (__extension__ ({ gsize __n = (gsize) (2); gsize __s
= sizeof (gchar); gpointer __p; if (__s == 1) __p = g_malloc
(__n); else if (__builtin_constant_p (__n) && (__s ==
0 || __n <= (9223372036854775807L *2UL+1UL) / __s)) __p =
g_malloc (__n * __s); else __p = g_malloc_n (__n, __s); __p;
}))
;
641 stream->priv->buffer[0] = '\r';
642 stream->priv->buffer[1] = '\0';
643 stream->priv->buflen = 1;
644
645 /* Decrease also the len so in the check
646 nvalid == len we get out of this method */
647 --nvalid;
648 --len;
649 }
650 }
651
652 /* if we've got any valid char we must tag the invalid chars */
653 if (nvalid > 0)
654 {
655 gchar orig_non_null = '\0';
656
657 apply_error_tag (stream);
658
659 if ((nvalid != len || !owned) && buffer[nvalid] != '\0')
660 {
661 /* make sure the buffer is always properly null
662 * terminated. This is needed, at least for now,
663 * to avoid issues with pygobject marshalling of
664 * the insert-text signal of ctktextbuffer
665 *
666 * https://bugzilla.gnome.org/show_bug.cgi?id=726689
667 */
668 if (!owned)
669 {
670 /* forced to make a copy */
671 free_text = g_new (gchar, len + 1)(gchar *) (__extension__ ({ gsize __n = (gsize) (len + 1); gsize
__s = sizeof (gchar); gpointer __p; if (__s == 1) __p = g_malloc
(__n); else if (__builtin_constant_p (__n) && (__s ==
0 || __n <= (9223372036854775807L *2UL+1UL) / __s)) __p =
g_malloc (__n * __s); else __p = g_malloc_n (__n, __s); __p;
}))
;
672 memcpy (free_text, buffer, len);
673 free_text[len] = '\0';
674
675 buffer = free_text;
676 owned = TRUE(!(0));
677 }
678
679 orig_non_null = buffer[nvalid];
680 buffer[nvalid] = '\0';
681 }
682
683 ctk_text_buffer_insert (text_buffer, iter, buffer, nvalid);
684
685 if (orig_non_null != '\0')
686 {
687 /* restore null terminated replaced byte */
688 buffer[nvalid] = orig_non_null;
689 }
690 }
691
692 /* If we inserted all return */
693 if (nvalid == len)
694 {
695 break;
696 }
697
698 buffer += nvalid;
699 len = len - nvalid;
700
701 if ((len < MAX_UNICHAR_LEN6) &&
702 (g_utf8_get_char_validated (buffer, len) == (gunichar)-2))
703 {
704 stream->priv->buffer = g_strndup (end, len);
705 stream->priv->buflen = len;
706
707 break;
708 }
709
710 /* we need the start of the chunk of invalid chars */
711 if (stream->priv->error_offset == -1)
712 {
713 stream->priv->error_offset = ctk_text_iter_get_offset (&stream->priv->pos);
714 }
715
716 insert_fallback (stream, buffer);
717 ++buffer;
718 --len;
719 }
720
721 g_free (free_text);
722}
723
724static void
725remove_trailing_newline (CtkSourceBufferOutputStream *stream)
726{
727 CtkTextIter end;
728 CtkTextIter start;
729
730 if (stream->priv->source_buffer == NULL((void*)0))
731 {
732 return;
733 }
734
735 ctk_text_buffer_get_end_iter (CTK_TEXT_BUFFER (stream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((stream->priv->source_buffer
)))))
, &end);
736 start = end;
737
738 ctk_text_iter_set_line_offset (&start, 0);
739
740 if (ctk_text_iter_ends_line (&start) &&
741 ctk_text_iter_backward_line (&start))
742 {
743 if (!ctk_text_iter_ends_line (&start))
744 {
745 ctk_text_iter_forward_to_line_end (&start);
746 }
747
748 ctk_text_buffer_delete (CTK_TEXT_BUFFER (stream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((stream->priv->source_buffer
)))))
,
749 &start,
750 &end);
751 }
752}
753
754static void
755end_append_text_to_document (CtkSourceBufferOutputStream *stream)
756{
757 if (stream->priv->source_buffer == NULL((void*)0))
758 {
759 return;
760 }
761
762 if (stream->priv->remove_trailing_newline)
763 {
764 remove_trailing_newline (stream);
765 }
766
767 ctk_text_buffer_set_modified (CTK_TEXT_BUFFER (stream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((stream->priv->source_buffer
)))))
,
768 FALSE(0));
769
770 ctk_text_buffer_end_user_action (CTK_TEXT_BUFFER (stream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((stream->priv->source_buffer
)))))
);
771 ctk_source_buffer_end_not_undoable_action (stream->priv->source_buffer);
772}
773
774static gboolean
775convert_text (CtkSourceBufferOutputStream *stream,
776 const gchar *inbuf,
777 gsize inbuf_len,
778 gchar **outbuf,
779 gsize *outbuf_len,
780 GError **error)
781{
782 gchar *out, *dest;
783 gsize in_left, out_left, outbuf_size, res;
784 gint errsv;
785 gboolean done, have_error;
786
787 in_left = inbuf_len;
788 /* set an arbitrary length if inbuf_len is 0, this is needed to flush
789 the iconv data */
790 outbuf_size = (inbuf_len > 0) ? inbuf_len : 100;
791
792 out_left = outbuf_size;
793
794 /* keep room for null termination */
795 out = dest = g_malloc (sizeof (gchar) * (outbuf_size + 1));
796
797 done = FALSE(0);
798 have_error = FALSE(0);
799
800 while (!done && !have_error)
801 {
802 /* If we reached here is because we need to convert the text,
803 so we convert it using iconv.
804 See that if inbuf is NULL the data will be flushed */
805 res = g_iconv (stream->priv->iconv,
806 (gchar **)&inbuf, &in_left,
807 &out, &out_left);
808
809 /* something went wrong */
810 if (res == (gsize)-1)
811 {
812 errsv = errno(*__errno_location ());
813
814 switch (errsv)
815 {
816 case EINVAL22:
817 /* Incomplete text, do not report an error */
818 stream->priv->iconv_buffer = g_strndup (inbuf, in_left);
819 stream->priv->iconv_buflen = in_left;
820 done = TRUE(!(0));
821 break;
822
823 case E2BIG7:
824 {
825 /* allocate more space */
826 gsize used = out - dest;
827
828 outbuf_size *= 2;
829
830 /* make sure to allocate room for
831 terminating null byte */
832 dest = g_realloc (dest, outbuf_size + 1);
833
834 out = dest + used;
835 out_left = outbuf_size - used;
836 }
837 break;
838
839 case EILSEQ84:
840 g_set_error_literal (error, G_CONVERT_ERRORg_convert_error_quark(),
841 G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
842 _("Invalid byte sequence in conversion input")((char *) g_dgettext ("ctksourceview-4", "Invalid byte sequence in conversion input"
))
);
843 have_error = TRUE(!(0));
844 break;
845
846 default:
847 g_set_error (error, G_CONVERT_ERRORg_convert_error_quark(), G_CONVERT_ERROR_FAILED,
848 _("Error during conversion: %s")((char *) g_dgettext ("ctksourceview-4", "Error during conversion: %s"
))
,
849 g_strerror (errsv));
850 have_error = TRUE(!(0));
851 break;
852 }
853 }
854 else
855 {
856 done = TRUE(!(0));
857 }
858 }
859
860 if (have_error)
861 {
862 g_free (dest);
863 *outbuf = NULL((void*)0);
864 *outbuf_len = 0;
865
866 return FALSE(0);
867 }
868
869 *outbuf_len = out - dest;
870 dest[*outbuf_len] = '\0';
871
872 *outbuf = dest;
873 return TRUE(!(0));
874}
875
876static gssize
877ctk_source_buffer_output_stream_write (GOutputStream *stream,
878 const void *buffer,
879 gsize count,
880 GCancellable *cancellable,
881 GError **error)
882{
883 CtkSourceBufferOutputStream *ostream;
884 gchar *text;
885 gsize len;
886 gboolean freetext = FALSE(0);
887
888 ostream = CTK_SOURCE_BUFFER_OUTPUT_STREAM (stream)((((CtkSourceBufferOutputStream*) (void *) ((stream)))));
889
890 if (g_cancellable_set_error_if_cancelled (cancellable, error) ||
1
Assuming the condition is false
3
Taking false branch
891 ostream->priv->source_buffer == NULL((void*)0))
2
Assuming field 'source_buffer' is not equal to NULL
892 {
893 return -1;
894 }
895
896 if (!ostream->priv->is_initialized)
4
Assuming field 'is_initialized' is 0
5
Taking true branch
897 {
898 ostream->priv->charset_conv = guess_encoding (ostream, buffer, count);
6
Calling 'guess_encoding'
899
900 /* If we still have the previous case is that we didn't guess
901 anything */
902 if (ostream->priv->charset_conv == NULL((void*)0) &&
903 !ostream->priv->is_utf8)
904 {
905 g_set_error_literal (error, CTK_SOURCE_FILE_LOADER_ERRORctk_source_file_loader_error_quark (),
906 CTK_SOURCE_FILE_LOADER_ERROR_ENCODING_AUTO_DETECTION_FAILED,
907 "It is not possible to detect the encoding automatically");
908
909 return -1;
910 }
911
912 /* Do not initialize iconv if we are not going to convert anything */
913 if (!ostream->priv->is_utf8)
914 {
915 gchar *from_charset;
916
917 /* Initialize iconv */
918 g_object_get (G_OBJECT (ostream->priv->charset_conv)((((GObject*) (void *) ((ostream->priv->charset_conv)))
))
,
919 "from-charset", &from_charset,
920 NULL((void*)0));
921
922 ostream->priv->iconv = g_iconv_open ("UTF-8", from_charset);
923
924 if (ostream->priv->iconv == (GIConv)-1)
925 {
926 if (errno(*__errno_location ()) == EINVAL22)
927 {
928 g_set_error (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_NOT_SUPPORTED,
929 _("Conversion from character set “%s” to “UTF-8” is not supported")((char *) g_dgettext ("ctksourceview-4", "Conversion from character set “%s” to “UTF-8” is not supported"
))
,
930 from_charset);
931 }
932 else
933 {
934 g_set_error (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_FAILED,
935 _("Could not open converter from “%s” to “UTF-8”")((char *) g_dgettext ("ctksourceview-4", "Could not open converter from “%s” to “UTF-8”"
))
,
936 from_charset);
937 }
938
939 g_free (from_charset);
940 g_clear_object (&ostream->priv->charset_conv)do { _Static_assert (sizeof *((&ostream->priv->charset_conv
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&ostream->priv->charset_conv))) _pp = ((&ostream
->priv->charset_conv)); __typeof__ (*((&ostream->
priv->charset_conv))) _ptr = *_pp; *_pp = ((void*)0); if (
_ptr) (g_object_unref) (_ptr); } while (0)
;
941
942 return -1;
943 }
944
945 g_free (from_charset);
946 }
947
948 /* Begin not undoable action. Begin also a normal user action,
949 * since we load the file chunk by chunk and it should be seen
950 * as only one action, for the features that rely on the user
951 * action.
952 */
953 ctk_source_buffer_begin_not_undoable_action (ostream->priv->source_buffer);
954 ctk_text_buffer_begin_user_action (CTK_TEXT_BUFFER (ostream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((ostream->priv->source_buffer
)))))
);
955
956 ctk_text_buffer_get_start_iter (CTK_TEXT_BUFFER (ostream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((ostream->priv->source_buffer
)))))
,
957 &ostream->priv->pos);
958
959 ostream->priv->is_initialized = TRUE(!(0));
960 }
961
962 if (ostream->priv->buflen > 0)
963 {
964 len = ostream->priv->buflen + count;
965 text = g_malloc (len + 1);
966
967 memcpy (text, ostream->priv->buffer, ostream->priv->buflen);
968 memcpy (text + ostream->priv->buflen, buffer, count);
969
970 text[len] = '\0';
971
972 g_free (ostream->priv->buffer);
973
974 ostream->priv->buffer = NULL((void*)0);
975 ostream->priv->buflen = 0;
976
977 freetext = TRUE(!(0));
978 }
979 else
980 {
981 text = (gchar *) buffer;
982 len = count;
983 }
984
985 if (!ostream->priv->is_utf8)
986 {
987 gchar *outbuf;
988 gsize outbuf_len;
989
990 /* check if iconv was correctly initializated, this shouldn't
991 happen but better be safe */
992 if (ostream->priv->iconv == NULL((void*)0))
993 {
994 g_set_error_literal (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_NOT_INITIALIZED,
995 _("Invalid object, not initialized")((char *) g_dgettext ("ctksourceview-4", "Invalid object, not initialized"
))
);
996
997 if (freetext)
998 {
999 g_free (text);
1000 }
1001
1002 return -1;
1003 }
1004
1005 /* manage the previous conversion buffer */
1006 if (ostream->priv->iconv_buflen > 0)
1007 {
1008 gchar *text2;
1009 gsize len2;
1010
1011 len2 = len + ostream->priv->iconv_buflen;
1012 text2 = g_malloc (len2 + 1);
1013
1014 memcpy (text2, ostream->priv->iconv_buffer, ostream->priv->iconv_buflen);
1015 memcpy (text2 + ostream->priv->iconv_buflen, text, len);
1016
1017 text2[len2] = '\0';
1018
1019 if (freetext)
1020 {
1021 g_free (text);
1022 }
1023
1024 text = text2;
1025 len = len2;
1026
1027 g_free (ostream->priv->iconv_buffer);
1028
1029 ostream->priv->iconv_buffer = NULL((void*)0);
1030 ostream->priv->iconv_buflen = 0;
1031
1032 freetext = TRUE(!(0));
1033 }
1034
1035 if (!convert_text (ostream, text, len, &outbuf, &outbuf_len, error))
1036 {
1037 if (freetext)
1038 {
1039 g_free (text);
1040 }
1041
1042 return -1;
1043 }
1044
1045 if (freetext)
1046 {
1047 g_free (text);
1048 }
1049
1050 /* set the converted text as the text to validate */
1051 text = outbuf;
1052 len = outbuf_len;
1053 }
1054
1055 validate_and_insert (ostream, text, len, freetext);
1056
1057 if (freetext)
1058 {
1059 g_free (text);
1060 }
1061
1062 return count;
1063}
1064
1065static gboolean
1066ctk_source_buffer_output_stream_flush (GOutputStream *stream,
1067 GCancellable *cancellable,
1068 GError **error)
1069{
1070 CtkSourceBufferOutputStream *ostream;
1071
1072 ostream = CTK_SOURCE_BUFFER_OUTPUT_STREAM (stream)((((CtkSourceBufferOutputStream*) (void *) ((stream)))));
1073
1074 if (ostream->priv->is_closed ||
1075 ostream->priv->source_buffer == NULL((void*)0))
1076 {
1077 return TRUE(!(0));
1078 }
1079
1080 /* if we have converted something flush residual data, validate and insert */
1081 if (ostream->priv->iconv != NULL((void*)0))
1082 {
1083 gchar *outbuf;
1084 gsize outbuf_len;
1085
1086 if (convert_text (ostream, NULL((void*)0), 0, &outbuf, &outbuf_len, error))
1087 {
1088 validate_and_insert (ostream, outbuf, outbuf_len, TRUE(!(0)));
1089 g_free (outbuf);
1090 }
1091 else
1092 {
1093 return FALSE(0);
1094 }
1095 }
1096
1097 if (ostream->priv->buflen > 0 && *ostream->priv->buffer != '\r')
1098 {
1099 /* If we reached here is because the last insertion was a half
1100 correct char, which has to be inserted as fallback */
1101 gchar *text;
1102
1103 if (ostream->priv->error_offset == -1)
1104 {
1105 ostream->priv->error_offset = ctk_text_iter_get_offset (&ostream->priv->pos);
1106 }
1107
1108 text = ostream->priv->buffer;
1109 while (ostream->priv->buflen != 0)
1110 {
1111 insert_fallback (ostream, text);
1112 ++text;
1113 --ostream->priv->buflen;
1114 }
1115
1116 g_free (ostream->priv->buffer);
1117 ostream->priv->buffer = NULL((void*)0);
1118 }
1119 else if (ostream->priv->buflen == 1 && *ostream->priv->buffer == '\r')
1120 {
1121 /* The previous chars can be invalid */
1122 apply_error_tag (ostream);
1123
1124 /* See special case above, flush this */
1125 ctk_text_buffer_insert (CTK_TEXT_BUFFER (ostream->priv->source_buffer)((((CtkTextBuffer*) (void *) ((ostream->priv->source_buffer
)))))
,
1126 &ostream->priv->pos,
1127 "\r",
1128 1);
1129
1130 g_free (ostream->priv->buffer);
1131 ostream->priv->buffer = NULL((void*)0);
1132 ostream->priv->buflen = 0;
1133 }
1134
1135 if (ostream->priv->iconv_buflen > 0 )
1136 {
1137 /* If we reached here is because the last insertion was a half
1138 correct char, which has to be inserted as fallback */
1139 gchar *text;
1140
1141 if (ostream->priv->error_offset == -1)
1142 {
1143 ostream->priv->error_offset = ctk_text_iter_get_offset (&ostream->priv->pos);
1144 }
1145
1146 text = ostream->priv->iconv_buffer;
1147 while (ostream->priv->iconv_buflen != 0)
1148 {
1149 insert_fallback (ostream, text);
1150 ++text;
1151 --ostream->priv->iconv_buflen;
1152 }
1153
1154 g_free (ostream->priv->iconv_buffer);
1155 ostream->priv->iconv_buffer = NULL((void*)0);
1156 }
1157
1158 apply_error_tag (ostream);
1159
1160 return TRUE(!(0));
1161}
1162
1163static gboolean
1164ctk_source_buffer_output_stream_close (GOutputStream *stream,
1165 GCancellable *cancellable,
1166 GError **error)
1167{
1168 CtkSourceBufferOutputStream *ostream = CTK_SOURCE_BUFFER_OUTPUT_STREAM (stream)((((CtkSourceBufferOutputStream*) (void *) ((stream)))));
1169
1170 if (!ostream->priv->is_closed && ostream->priv->is_initialized)
1171 {
1172 end_append_text_to_document (ostream);
1173
1174 if (ostream->priv->iconv != NULL((void*)0))
1175 {
1176 g_iconv_close (ostream->priv->iconv);
1177 }
1178
1179 ostream->priv->is_closed = TRUE(!(0));
1180 }
1181
1182 if (ostream->priv->buflen > 0 || ostream->priv->iconv_buflen > 0)
1183 {
1184 g_set_error (error,
1185 G_IO_ERRORg_io_error_quark(),
1186 G_IO_ERROR_INVALID_DATA,
1187 _("Incomplete UTF-8 sequence in input")((char *) g_dgettext ("ctksourceview-4", "Incomplete UTF-8 sequence in input"
))
);
1188
1189 return FALSE(0);
1190 }
1191
1192 return TRUE(!(0));
1193}