No issues found
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* shell-secure-text-buffer.c - secure memory clutter text buffer
3
4 Copyright (C) 2009 Stefan Walter
5 Copyright (C) 2012 Red Hat Inc.
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 This program 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 GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with the Gnome Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
21
22 Author: Stef Walter <stefw@gnome.org>
23 */
24
25 #include "config.h"
26
27 #include "shell-secure-text-buffer.h"
28
29 #define GCR_API_SUBJECT_TO_CHANGE
30 #include <gcr/gcr-base.h>
31
32 #include <string.h>
33
34 typedef struct _ShellSecureTextBuffer ShellSecureTextBuffer;
35 typedef struct _ShellSecureTextBufferClass ShellSecureTextBufferClass;
36
37 struct _ShellSecureTextBuffer {
38 ClutterTextBuffer parent;
39 gchar *text;
40 gsize text_size;
41 gsize text_bytes;
42 guint text_chars;
43 };
44
45 struct _ShellSecureTextBufferClass {
46 ClutterTextBufferClass parent_class;
47 };
48
49 /* Initial size of buffer, in bytes */
50 #define MIN_SIZE 16
51
52 G_DEFINE_TYPE (ShellSecureTextBuffer, shell_secure_text_buffer, CLUTTER_TYPE_TEXT_BUFFER);
53
54 static const gchar *
55 shell_secure_text_buffer_real_get_text (ClutterTextBuffer *buffer,
56 gsize *n_bytes)
57 {
58 ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer);
59 if (n_bytes)
60 *n_bytes = self->text_bytes;
61 if (!self->text)
62 return "";
63 return self->text;
64 }
65
66 static guint
67 shell_secure_text_buffer_real_get_length (ClutterTextBuffer *buffer)
68 {
69 ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer);
70 return self->text_chars;
71 }
72
73 static guint
74 shell_secure_text_buffer_real_insert_text (ClutterTextBuffer *buffer,
75 guint position,
76 const gchar *chars,
77 guint n_chars)
78 {
79 ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer);
80 gsize n_bytes;
81 gsize at;
82
83 n_bytes = g_utf8_offset_to_pointer (chars, n_chars) - chars;
84
85 /* Need more memory */
86 if (n_bytes + self->text_bytes + 1 > self->text_size)
87 {
88 /* Calculate our new buffer size */
89 while (n_bytes + self->text_bytes + 1 > self->text_size)
90 {
91 if (self->text_size == 0)
92 {
93 self->text_size = MIN_SIZE;
94 }
95 else
96 {
97 if (2 * self->text_size < CLUTTER_TEXT_BUFFER_MAX_SIZE)
98 {
99 self->text_size *= 2;
100 }
101 else
102 {
103 self->text_size = CLUTTER_TEXT_BUFFER_MAX_SIZE;
104 if (n_bytes > self->text_size - self->text_bytes - 1)
105 {
106 n_bytes = self->text_size - self->text_bytes - 1;
107 n_bytes = g_utf8_find_prev_char (chars, chars + n_bytes + 1) - chars;
108 n_chars = g_utf8_strlen (chars, n_bytes);
109 }
110 break;
111 }
112 }
113 }
114 self->text = gcr_secure_memory_realloc (self->text, self->text_size);
115 }
116
117 /* Actual text insertion */
118 at = g_utf8_offset_to_pointer (self->text, position) - self->text;
119 g_memmove (self->text + at + n_bytes, self->text + at, self->text_bytes - at);
120 memcpy (self->text + at, chars, n_bytes);
121
122 /* Book keeping */
123 self->text_bytes += n_bytes;
124 self->text_chars += n_chars;
125 self->text[self->text_bytes] = '\0';
126
127 clutter_text_buffer_emit_inserted_text (buffer, position, chars, n_chars);
128 return n_chars;
129 }
130
131 static guint
132 shell_secure_text_buffer_real_delete_text (ClutterTextBuffer *buffer,
133 guint position,
134 guint n_chars)
135 {
136 ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer);
137 gsize start, end;
138
139 if (position > self->text_chars)
140 position = self->text_chars;
141 if (position + n_chars > self->text_chars)
142 n_chars = self->text_chars - position;
143
144 if (n_chars > 0)
145 {
146 start = g_utf8_offset_to_pointer (self->text, position) - self->text;
147 end = g_utf8_offset_to_pointer (self->text, position + n_chars) - self->text;
148
149 g_memmove (self->text + start, self->text + end, self->text_bytes + 1 - end);
150 self->text_chars -= n_chars;
151 self->text_bytes -= (end - start);
152
153 clutter_text_buffer_emit_deleted_text (buffer, position, n_chars);
154 }
155
156 return n_chars;
157 }
158
159 static void
160 shell_secure_text_buffer_init (ShellSecureTextBuffer *self)
161 {
162
163 }
164
165 static void
166 shell_secure_text_buffer_finalize (GObject *obj)
167 {
168 ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (obj);
169
170 if (self->text)
171 {
172 gcr_secure_memory_strfree (self->text);
173 self->text = NULL;
174 self->text_bytes = self->text_size = 0;
175 self->text_chars = 0;
176 }
177
178 G_OBJECT_CLASS (shell_secure_text_buffer_parent_class)->finalize (obj);
179 }
180
181 static void
182 shell_secure_text_buffer_class_init (ShellSecureTextBufferClass *klass)
183 {
184 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
185 ClutterTextBufferClass *buffer_class = CLUTTER_TEXT_BUFFER_CLASS (klass);
186
187 gobject_class->finalize = shell_secure_text_buffer_finalize;
188
189 buffer_class->get_text = shell_secure_text_buffer_real_get_text;
190 buffer_class->get_length = shell_secure_text_buffer_real_get_length;
191 buffer_class->insert_text = shell_secure_text_buffer_real_insert_text;
192 buffer_class->delete_text = shell_secure_text_buffer_real_delete_text;
193 }
194
195 ClutterTextBuffer *
196 shell_secure_text_buffer_new (void)
197 {
198 return g_object_new (SHELL_TYPE_SECURE_TEXT_BUFFER, NULL);
199 }