Blame src/shell-secure-text-buffer.c

Packit Service ed5168
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
Packit Service ed5168
/* shell-secure-text-buffer.c - secure memory clutter text buffer
Packit Service ed5168
Packit Service ed5168
   Copyright (C) 2009 Stefan Walter
Packit Service ed5168
   Copyright (C) 2012 Red Hat Inc.
Packit Service ed5168
Packit Service ed5168
   This program is free software; you can redistribute it and/or
Packit Service ed5168
   modify it under the terms of the GNU Library General Public License as
Packit Service ed5168
   published by the Free Software Foundation; either version 2 of the
Packit Service ed5168
   License, or (at your option) any later version.
Packit Service ed5168
Packit Service ed5168
   This program is distributed in the hope that it will be useful,
Packit Service ed5168
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service ed5168
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service ed5168
   Library General Public License for more details.
Packit Service ed5168
Packit Service ed5168
   You should have received a copy of the GNU Library General Public
Packit Service ed5168
   License along with the Gnome Library; see the file COPYING.LIB.  If not,
Packit Service ed5168
   see <http://www.gnu.org/licenses/>.
Packit Service ed5168
Packit Service ed5168
   Author: Stef Walter <stefw@gnome.org>
Packit Service ed5168
*/
Packit Service ed5168
Packit Service ed5168
#include "config.h"
Packit Service ed5168
Packit Service ed5168
#include "shell-secure-text-buffer.h"
Packit Service ed5168
Packit Service ed5168
#define GCR_API_SUBJECT_TO_CHANGE
Packit Service ed5168
#include <gcr/gcr-base.h>
Packit Service ed5168
Packit Service ed5168
#include <string.h>
Packit Service ed5168
Packit Service ed5168
struct _ShellSecureTextBuffer {
Packit Service ed5168
  ClutterTextBuffer parent;
Packit Service ed5168
  gchar *text;
Packit Service ed5168
  gsize text_size;
Packit Service ed5168
  gsize text_bytes;
Packit Service ed5168
  guint text_chars;
Packit Service ed5168
};
Packit Service ed5168
Packit Service ed5168
/* Initial size of buffer, in bytes */
Packit Service ed5168
#define MIN_SIZE 16
Packit Service ed5168
Packit Service ed5168
G_DEFINE_TYPE (ShellSecureTextBuffer, shell_secure_text_buffer, CLUTTER_TYPE_TEXT_BUFFER);
Packit Service ed5168
Packit Service ed5168
static const gchar *
Packit Service ed5168
shell_secure_text_buffer_real_get_text (ClutterTextBuffer *buffer,
Packit Service ed5168
                                        gsize             *n_bytes)
Packit Service ed5168
{
Packit Service ed5168
  ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer);
Packit Service ed5168
  if (n_bytes)
Packit Service ed5168
    *n_bytes = self->text_bytes;
Packit Service ed5168
  if (!self->text)
Packit Service ed5168
    return "";
Packit Service ed5168
  return self->text;
Packit Service ed5168
}
Packit Service ed5168
Packit Service ed5168
static guint
Packit Service ed5168
shell_secure_text_buffer_real_get_length (ClutterTextBuffer *buffer)
Packit Service ed5168
{
Packit Service ed5168
  ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer);
Packit Service ed5168
  return self->text_chars;
Packit Service ed5168
}
Packit Service ed5168
Packit Service ed5168
static guint
Packit Service ed5168
shell_secure_text_buffer_real_insert_text (ClutterTextBuffer *buffer,
Packit Service ed5168
                                           guint              position,
Packit Service ed5168
                                           const gchar       *chars,
Packit Service ed5168
                                           guint              n_chars)
Packit Service ed5168
{
Packit Service ed5168
  ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer);
Packit Service ed5168
  gsize n_bytes;
Packit Service ed5168
  gsize at;
Packit Service ed5168
Packit Service ed5168
  n_bytes = g_utf8_offset_to_pointer (chars, n_chars) - chars;
Packit Service ed5168
Packit Service ed5168
  /* Need more memory */
Packit Service ed5168
  if (n_bytes + self->text_bytes + 1 > self->text_size)
Packit Service ed5168
    {
Packit Service ed5168
      /* Calculate our new buffer size */
Packit Service ed5168
      while (n_bytes + self->text_bytes + 1 > self->text_size)
Packit Service ed5168
        {
Packit Service ed5168
          if (self->text_size == 0)
Packit Service ed5168
            {
Packit Service ed5168
              self->text_size = MIN_SIZE;
Packit Service ed5168
            }
Packit Service ed5168
          else
Packit Service ed5168
            {
Packit Service ed5168
              if (2 * self->text_size < CLUTTER_TEXT_BUFFER_MAX_SIZE)
Packit Service ed5168
                {
Packit Service ed5168
                  self->text_size *= 2;
Packit Service ed5168
                }
Packit Service ed5168
              else
Packit Service ed5168
                {
Packit Service ed5168
                  self->text_size = CLUTTER_TEXT_BUFFER_MAX_SIZE;
Packit Service ed5168
                  if (n_bytes > self->text_size - self->text_bytes - 1)
Packit Service ed5168
                    {
Packit Service ed5168
                      n_bytes = self->text_size - self->text_bytes - 1;
Packit Service ed5168
                      n_bytes = g_utf8_find_prev_char (chars, chars + n_bytes + 1) - chars;
Packit Service ed5168
                      n_chars = g_utf8_strlen (chars, n_bytes);
Packit Service ed5168
                    }
Packit Service ed5168
                  break;
Packit Service ed5168
                }
Packit Service ed5168
            }
Packit Service ed5168
        }
Packit Service ed5168
      self->text = gcr_secure_memory_realloc (self->text, self->text_size);
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
  /* Actual text insertion */
Packit Service ed5168
  at = g_utf8_offset_to_pointer (self->text, position) - self->text;
Packit Service ed5168
  g_memmove (self->text + at + n_bytes, self->text + at, self->text_bytes - at);
Packit Service ed5168
  memcpy (self->text + at, chars, n_bytes);
Packit Service ed5168
Packit Service ed5168
  /* Book keeping */
Packit Service ed5168
  self->text_bytes += n_bytes;
Packit Service ed5168
  self->text_chars += n_chars;
Packit Service ed5168
  self->text[self->text_bytes] = '\0';
Packit Service ed5168
Packit Service ed5168
  clutter_text_buffer_emit_inserted_text (buffer, position, chars, n_chars);
Packit Service ed5168
  return n_chars;
Packit Service ed5168
}
Packit Service ed5168
Packit Service ed5168
static guint
Packit Service ed5168
shell_secure_text_buffer_real_delete_text (ClutterTextBuffer *buffer,
Packit Service ed5168
                                           guint              position,
Packit Service ed5168
                                           guint              n_chars)
Packit Service ed5168
{
Packit Service ed5168
  ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer);
Packit Service ed5168
  gsize start, end;
Packit Service ed5168
Packit Service ed5168
  if (position > self->text_chars)
Packit Service ed5168
    position = self->text_chars;
Packit Service ed5168
  if (position + n_chars > self->text_chars)
Packit Service ed5168
    n_chars = self->text_chars - position;
Packit Service ed5168
Packit Service ed5168
  if (n_chars > 0)
Packit Service ed5168
    {
Packit Service ed5168
      start = g_utf8_offset_to_pointer (self->text, position) - self->text;
Packit Service ed5168
      end = g_utf8_offset_to_pointer (self->text, position + n_chars) - self->text;
Packit Service ed5168
Packit Service ed5168
      g_memmove (self->text + start, self->text + end, self->text_bytes + 1 - end);
Packit Service ed5168
      self->text_chars -= n_chars;
Packit Service ed5168
      self->text_bytes -= (end - start);
Packit Service ed5168
Packit Service ed5168
      clutter_text_buffer_emit_deleted_text (buffer, position, n_chars);
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
  return n_chars;
Packit Service ed5168
}
Packit Service ed5168
Packit Service ed5168
static void
Packit Service ed5168
shell_secure_text_buffer_init (ShellSecureTextBuffer *self)
Packit Service ed5168
{
Packit Service ed5168
Packit Service ed5168
}
Packit Service ed5168
Packit Service ed5168
static void
Packit Service ed5168
shell_secure_text_buffer_finalize (GObject *obj)
Packit Service ed5168
{
Packit Service ed5168
  ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (obj);
Packit Service ed5168
Packit Service ed5168
  if (self->text)
Packit Service ed5168
    {
Packit Service ed5168
      gcr_secure_memory_strfree (self->text);
Packit Service ed5168
      self->text = NULL;
Packit Service ed5168
      self->text_bytes = self->text_size = 0;
Packit Service ed5168
      self->text_chars = 0;
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
  G_OBJECT_CLASS (shell_secure_text_buffer_parent_class)->finalize (obj);
Packit Service ed5168
}
Packit Service ed5168
Packit Service ed5168
static void
Packit Service ed5168
shell_secure_text_buffer_class_init (ShellSecureTextBufferClass *klass)
Packit Service ed5168
{
Packit Service ed5168
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit Service ed5168
  ClutterTextBufferClass *buffer_class = CLUTTER_TEXT_BUFFER_CLASS (klass);
Packit Service ed5168
Packit Service ed5168
  gobject_class->finalize = shell_secure_text_buffer_finalize;
Packit Service ed5168
Packit Service ed5168
  buffer_class->get_text = shell_secure_text_buffer_real_get_text;
Packit Service ed5168
  buffer_class->get_length = shell_secure_text_buffer_real_get_length;
Packit Service ed5168
  buffer_class->insert_text = shell_secure_text_buffer_real_insert_text;
Packit Service ed5168
  buffer_class->delete_text = shell_secure_text_buffer_real_delete_text;
Packit Service ed5168
}
Packit Service ed5168
Packit Service ed5168
ClutterTextBuffer *
Packit Service ed5168
shell_secure_text_buffer_new (void)
Packit Service ed5168
{
Packit Service ed5168
  return g_object_new (SHELL_TYPE_SECURE_TEXT_BUFFER, NULL);
Packit Service ed5168
}