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; }
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); }