static void
inf_text_default_delete_operation_apply(InfAdoptedOperation* operation,
                                        InfAdoptedUser* by,
                                        InfBuffer* buffer)
{
  InfTextDefaultDeleteOperationPrivate* priv;

  g_assert(INF_TEXT_IS_DEFAULT_DELETE_OPERATION(operation));
  g_assert(INF_TEXT_IS_BUFFER(buffer));

  priv = INF_TEXT_DEFAULT_DELETE_OPERATION_PRIVATE(operation);

#ifdef DELETE_OPERATION_CHECK_TEXT_MATCH
  g_assert(
    inf_text_default_delete_operation_text_match(
      INF_TEXT_DEFAULT_DELETE_OPERATION(operation),
      INF_TEXT_BUFFER(buffer)
    )
  );
#endif /* DELETE_OPERATION_CHECK_TEXT_MATCH */

  inf_text_buffer_erase_text(
    INF_TEXT_BUFFER(buffer),
    priv->position,
    inf_text_chunk_get_length(priv->chunk),
    INF_USER(by)
  );
}
static void
infinoted_plugin_document_stream_text_erased_cb(InfTextBuffer* buffer,
                                                guint pos,
                                                InfTextChunk* chunk,
                                                InfUser* user,
                                                gpointer user_data)
{
  InfinotedPluginDocumentStreamStream* stream;
  guint32 comm;
  guint32 pos32;
  guint32 len32;
  gboolean alive;

  stream = (InfinotedPluginDocumentStreamStream*)user_data;

  comm = 4; /* ERASE */
  pos32 = (guint32)pos;
  len32 = inf_text_chunk_get_length(chunk);

  alive = infinoted_plugin_document_stream_send(stream, &comm, 4);
  if(alive)
    alive = infinoted_plugin_document_stream_send(stream, &pos32, 4);
  if(alive)
    alive = infinoted_plugin_document_stream_send(stream, &len32, 4);
}
static guint
inf_text_default_delete_operation_get_length(
  InfTextDeleteOperation* operation)
{
  return inf_text_chunk_get_length(
    INF_TEXT_DEFAULT_DELETE_OPERATION_PRIVATE(operation)->chunk
  );
}
static guint
inf_text_default_insert_operation_get_length(
  InfTextInsertOperation* operation)
{
  return inf_text_chunk_get_length(
    INF_TEXT_DEFAULT_INSERT_OPERATION_PRIVATE(operation)->chunk
  );
}
/* TODO: Merge adjacent text chunks */
static GSList*
inf_text_remote_delete_operation_recon_feed(GSList* recon_list,
                                            guint position,
                                            InfTextChunk* chunk)
{
  GSList* item;
  InfTextRemoteDeleteOperationRecon* recon;
  GSList* new_list;
  GSList* last;
  InfTextRemoteDeleteOperationRecon* new_recon;

  guint text_pos;
  guint cur_len;
  guint text_len;

  new_list = NULL;
  text_pos = 0;
  cur_len = 0;

  for(item = recon_list; item != NULL; item = g_slist_next(item))
  {
    recon = (InfTextRemoteDeleteOperationRecon*)item->data;
    if(position + text_pos + cur_len < recon->position &&
       text_pos < inf_text_chunk_get_length(chunk))
    {
      text_len = recon->position - position - text_pos - cur_len;
      if(text_len > inf_text_chunk_get_length(chunk) - text_pos)
        text_len = inf_text_chunk_get_length(chunk) - text_pos;

      new_recon = g_slice_new(InfTextRemoteDeleteOperationRecon);
      new_recon->position = position + text_pos + cur_len;
      new_recon->chunk = inf_text_chunk_substring(chunk, text_pos, text_len);
      new_list = g_slist_append_fast(new_list, &last, new_recon);
      text_pos += text_len;
    }

    cur_len += inf_text_chunk_get_length(recon->chunk);
    new_recon = g_slice_new(InfTextRemoteDeleteOperationRecon);
    new_recon->position = recon->position;
    new_recon->chunk = inf_text_chunk_copy(recon->chunk);
    new_list = g_slist_append_fast(new_list, &last, new_recon);
  }

  if(text_pos < inf_text_chunk_get_length(chunk))
  {
    new_recon = g_slice_new(InfTextRemoteDeleteOperationRecon);
    new_recon->position = position + text_pos + cur_len;
    new_recon->chunk = inf_text_chunk_substring(
      chunk,
      text_pos,
      inf_text_chunk_get_length(chunk) - text_pos
    );

    new_list = g_slist_append_fast(new_list, &last, new_recon);
  }

  return new_list;
}
static InfAdoptedSplitOperation*
inf_text_default_delete_operation_transform_split(
  InfTextDeleteOperation* operation,
  guint split_pos,
  guint split_len)
{
  InfTextDefaultDeleteOperationPrivate* priv;
  InfTextChunk* first_chunk;
  InfTextChunk* second_chunk;
  GObject* first;
  GObject* second;
  InfAdoptedSplitOperation* result;

  priv = INF_TEXT_DEFAULT_DELETE_OPERATION_PRIVATE(operation);

  first_chunk = inf_text_chunk_substring(priv->chunk, 0, split_pos);
  second_chunk = inf_text_chunk_substring(
    priv->chunk,
    split_pos,
    inf_text_chunk_get_length(priv->chunk) - split_pos
  );

  first = g_object_new(
    INF_TEXT_TYPE_DEFAULT_DELETE_OPERATION,
    "position", priv->position,
    "chunk", first_chunk,
    NULL
  );

  second = g_object_new(
    INF_TEXT_TYPE_DEFAULT_DELETE_OPERATION,
    "position", priv->position + split_pos + split_len,
    "chunk", second_chunk,
    NULL
  );

  inf_text_chunk_free(first_chunk);
  inf_text_chunk_free(second_chunk);

  result = inf_adopted_split_operation_new(
    INF_ADOPTED_OPERATION(first),
    INF_ADOPTED_OPERATION(second)
  );

  g_object_unref(first);
  g_object_unref(second);
  return result;
}
Esempio n. 7
0
static void
inf_test_text_recover_text_erased_cb(InfTextBuffer* buffer,
                                     guint pos,
                                     InfTextChunk* chunk,
                                     InfUser* user,
                                     gpointer user_data)
{
  InfAdoptedOperation* operation;
  guint len;

  InfTextChunk* print_chunk;
  gsize print_bytes;
  gpointer print_text;

  /* If the document has substantial content and this deletes most of it,
   * then print out the document here. */
  len = inf_text_chunk_get_length(chunk);
  if(inf_text_buffer_get_length(buffer) + len >= 50)
  {
    if(len >= (inf_text_buffer_get_length(buffer) + len)*75/100)
    {
      if(*(int*)user_data == 0)
      {
        print_chunk = inf_text_buffer_get_slice(
          buffer,
          0,
          inf_text_buffer_get_length(buffer)
        );

        inf_text_chunk_insert_chunk(print_chunk, pos, chunk);
        print_text = inf_text_chunk_get_text(print_chunk, &print_bytes);
        inf_text_chunk_free(print_chunk);

        printf("%.*s\n", (int)print_bytes, (gchar*)print_text);
        g_free(print_text);
      }

      --*(int*)user_data;
    }
  }

  g_object_unref(buffer);
}
static gboolean
inf_text_default_delete_operation_text_match(
  InfTextDefaultDeleteOperation* operation,
  InfTextBuffer* buffer)
{
  InfTextDefaultDeleteOperationPrivate* priv;
  InfTextChunk* chunk;
  gchar* first;
  gchar* second;
  gsize first_len;
  gsize second_len;
  int result;

  priv = INF_TEXT_DEFAULT_DELETE_OPERATION_PRIVATE(operation);

  /* TODO: inf_text_chunk_cmp_substring */
  chunk = inf_text_buffer_get_slice(
    buffer,
    priv->position,
    inf_text_chunk_get_length(priv->chunk)
  );

  first = inf_text_chunk_get_text(priv->chunk, &first_len);
  second = inf_text_chunk_get_text(chunk, &second_len);
  inf_text_chunk_free(chunk);

  /* TODO: Owners must match, too */
  if(first_len == second_len)
    result = memcmp(first, second, first_len);
  else
    result = 1; /* != 0 */

  g_free(second);
  g_free(first);

  return result == 0;
}
static InfAdoptedSplitOperation*
inf_text_remote_delete_operation_transform_split(
  InfTextDeleteOperation* operation,
  guint split_pos,
  guint split_len)
{
  /* Need to split the delete operation and the recon list */
  InfTextRemoteDeleteOperationPrivate* priv;
  InfAdoptedSplitOperation* result;
  GObject* first_operation;
  GObject* second_operation;
  InfTextRemoteDeleteOperationPrivate* result_priv;
  InfTextRemoteDeleteOperationRecon* recon;
  InfTextRemoteDeleteOperationRecon* new_recon;
  GSList* first_recon;
  GSList* second_recon;
  guint recon_cur_len;
  GSList* item;

  priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(operation);

  first_recon = NULL;
  second_recon = NULL;
  recon_cur_len = 0;

  for(item = priv->recon; item != NULL; item = g_slist_next(item))
  {
    recon = (InfTextRemoteDeleteOperationRecon*)item->data;

    g_assert(recon->position >= recon_cur_len);
    if(recon->position - recon_cur_len <= split_pos)
    {
      new_recon = g_slice_new(InfTextRemoteDeleteOperationRecon);
      new_recon->position = recon->position;
      new_recon->chunk = inf_text_chunk_copy(recon->chunk);
      first_recon = g_slist_prepend(first_recon, new_recon);

      recon_cur_len += inf_text_chunk_get_length(recon->chunk);
    }
    else
    {
      new_recon = g_slice_new(InfTextRemoteDeleteOperationRecon);
      new_recon->position = recon->position - (split_pos + recon_cur_len);
      new_recon->chunk = inf_text_chunk_copy(recon->chunk);
      second_recon = g_slist_prepend(second_recon, new_recon);
    }
  }

  first_operation = g_object_new(
    INF_TEXT_TYPE_REMOTE_DELETE_OPERATION,
    "position", priv->position,
    "length", split_pos,
    NULL
  );
  
  second_operation = g_object_new(
    INF_TEXT_TYPE_REMOTE_DELETE_OPERATION,
    "position", priv->position + split_len,
    "length", priv->length - split_pos,
    NULL
  );

  result_priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(first_operation);
  result_priv->recon = g_slist_reverse(first_recon);
  result_priv->recon_offset = priv->recon_offset;

  result_priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(second_operation);
  result_priv->recon = g_slist_reverse(second_recon);
  result_priv->recon_offset = priv->recon_offset + split_pos + recon_cur_len;

  result = inf_adopted_split_operation_new(
    INF_ADOPTED_OPERATION(first_operation),
    INF_ADOPTED_OPERATION(second_operation)
  );

  g_object_unref(G_OBJECT(second_operation));
  g_object_unref(G_OBJECT(first_operation));
  return result;
}
static InfAdoptedOperation*
inf_text_remote_delete_operation_apply_transformed(InfAdoptedOperation* op,
                                                   InfAdoptedOperation* trans,
                                                   InfAdoptedUser* by,
                                                   InfBuffer* buffer,
                                                   GError** error)
{
  InfTextRemoteDeleteOperationPrivate* priv;
  InfTextChunk* chunk;
  InfTextChunk* temp_slice;
  GSList* list;
  GSList* item;
  InfAdoptedOperation* operation;
  GSList* recon_list;
  GSList* recon_item;
  InfTextRemoteDeleteOperationRecon* recon;
  InfTextDefaultDeleteOperation* result;

  g_assert(INF_TEXT_IS_REMOTE_DELETE_OPERATION(op));
  g_assert(INF_TEXT_IS_BUFFER(buffer));

  /* TODO: We can probably optimize this function, but then we should
   * a) profile it and b) in many cases input parameters to this function
   * are trivial anyway. */
  if(INF_ADOPTED_IS_SPLIT_OPERATION(trans))
  {
    list = inf_adopted_split_operation_unsplit(
      INF_ADOPTED_SPLIT_OPERATION(trans)
    );
  }
  else
  {
    list = g_slist_prepend(NULL, trans);
  }

  chunk = inf_text_chunk_new(
    inf_text_buffer_get_encoding(INF_TEXT_BUFFER(buffer))
  );

  /* We assume the list of remote delete operations to be in order */
  for(item = list; item != NULL; item = g_slist_next(item))
  {
    g_assert(INF_TEXT_IS_REMOTE_DELETE_OPERATION(item->data));
    priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(item->data);

    operation = INF_ADOPTED_OPERATION(item->data);

    if(priv->length > 0)
    {
      temp_slice = inf_text_buffer_get_slice(
        INF_TEXT_BUFFER(buffer),
        priv->position,
        priv->length
      );

      recon_list = inf_text_remote_delete_operation_recon_feed(
        priv->recon,
        0,
        temp_slice
      );

      inf_text_chunk_free(temp_slice);
    }
    else
    {
      recon_list = priv->recon;
    }

    for(recon_item = recon_list;
        recon_item != NULL;
        recon_item = g_slist_next(recon_item))
    {
      recon = (InfTextRemoteDeleteOperationRecon*)recon_item->data;
      g_assert(priv->recon_offset + recon->position ==
               inf_text_chunk_get_length(chunk));

      inf_text_chunk_insert_chunk(
        chunk,
        inf_text_chunk_get_length(chunk),
        recon->chunk
      );
    }

    /* Free recon list if newly allocated */
    if(priv->length > 0)
      inf_text_remote_delete_operation_recon_free(recon_list);

    if(!inf_adopted_operation_apply(operation, by, buffer, error))
    {
      g_slist_free(list);
      inf_text_chunk_free(chunk);
      return NULL;
    }
  }

  g_slist_free(list);

  priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(op);
  result = inf_text_default_delete_operation_new(priv->position, chunk);
  inf_text_chunk_free(chunk);

  return INF_ADOPTED_OPERATION(result);
}