/** * infd_chat_filesystem_format_write: * @storage: A #InfdFilesystemStorage. * @path: Storage path where to write the session to. * @buffer: The #InfChatBuffer to write. * @error: Location to store error information, if any, or %NULL. * * Writes the given buffer into the filesystem storage at @path. If * successful, the session can then be read back with * infd_chat_filesystem_format_read(). If the function fails, %FALSE is * returned and @error is set. * * Returns: %TRUE on success or %FALSE on error. */ gboolean infd_chat_filesystem_format_write(InfdFilesystemStorage* storage, const gchar* path, InfChatBuffer* buffer, GError** error) { FILE* stream; xmlDocPtr doc; xmlNodePtr root; xmlErrorPtr xmlerror; g_return_val_if_fail(INFD_IS_FILESYSTEM_STORAGE(storage), FALSE); g_return_val_if_fail(path != NULL, FALSE); g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* Open stream before exporting buffer to XML so possible errors are * catched earlier. */ stream = infd_filesystem_storage_open( INFD_FILESYSTEM_STORAGE(storage), "InfChat", path, "w", NULL, error ); if(stream == NULL) return FALSE; root = xmlNewNode(NULL, (const xmlChar*)"inf-chat-session"); doc = xmlNewDoc((const xmlChar*)"1.0"); xmlDocSetRootElement(doc, root); /* TODO: At this point, we should tell libxml2 to use * infd_filesystem_storage_stream_write() instead of fwrite(), * to prevent C runtime mixups. */ if(xmlDocFormatDump(stream, doc, 1) == -1) { xmlerror = xmlGetLastError(); infd_filesystem_storage_stream_close(stream); xmlFreeDoc(doc); g_set_error_literal( error, g_quark_from_static_string("LIBXML2_OUTPUT_ERROR"), xmlerror->code, xmlerror->message ); return FALSE; } infd_filesystem_storage_stream_close(stream); xmlFreeDoc(doc); return TRUE; }
static gboolean infd_note_plugin_text_session_write(InfdStorage* storage, InfSession* session, const gchar* path, gpointer user_data, GError** error) { InfUserTable* table; InfTextBuffer* buffer; InfTextBufferIter* iter; xmlNodePtr root; xmlNodePtr buffer_node; xmlNodePtr segment_node; guint author; gchar* content; gsize bytes; FILE* stream; xmlDocPtr doc; xmlErrorPtr xmlerror; g_assert(INFD_IS_FILESYSTEM_STORAGE(storage)); g_assert(INF_TEXT_IS_SESSION(session)); /* Open stream before exporting buffer to XML so possible errors are * catched earlier. */ stream = infd_filesystem_storage_open( INFD_FILESYSTEM_STORAGE(storage), "InfText", path, "w", error ); if(stream == NULL) return FALSE; root = xmlNewNode(NULL, (const xmlChar*)"inf-text-session"); buffer = INF_TEXT_BUFFER(inf_session_get_buffer(session)); table = inf_session_get_user_table(session); inf_user_table_foreach_user( table, infd_note_plugin_text_session_write_foreach_user_func, root ); buffer_node = xmlNewChild(root, NULL, (const xmlChar*)"buffer", NULL); iter = inf_text_buffer_create_iter(buffer); if(iter != NULL) { do { author = inf_text_buffer_iter_get_author(buffer, iter); content = inf_text_buffer_iter_get_text(buffer, iter); bytes = inf_text_buffer_iter_get_bytes(buffer, iter); segment_node = xmlNewChild( buffer_node, NULL, (const xmlChar*)"segment", NULL ); inf_xml_util_set_attribute_uint(segment_node, "author", author); inf_xml_util_add_child_text(segment_node, content, bytes); g_free(content); } while(inf_text_buffer_iter_next(buffer, iter)); inf_text_buffer_destroy_iter(buffer, iter); } doc = xmlNewDoc((const xmlChar*)"1.0"); xmlDocSetRootElement(doc, root); if(xmlDocFormatDump(stream, doc, 1) == -1) { xmlerror = xmlGetLastError(); fclose(stream); xmlFreeDoc(doc); g_set_error( error, g_quark_from_static_string("LIBXML2_OUTPUT_ERROR"), xmlerror->code, "%s", xmlerror->message ); return FALSE; } fclose(stream); xmlFreeDoc(doc); return TRUE; }
static InfSession* infd_note_plugin_text_session_read(InfdStorage* storage, InfIo* io, InfCommunicationManager* manager, const gchar* path, gpointer user_data, GError** error) { InfUserTable* user_table; InfTextBuffer* buffer; InfTextSession* session; FILE* stream; xmlDocPtr doc; xmlErrorPtr xmlerror; xmlNodePtr root; xmlNodePtr child; gboolean result; g_assert(INFD_IS_FILESYSTEM_STORAGE(storage)); user_table = inf_user_table_new(); buffer = INF_TEXT_BUFFER(inf_text_default_buffer_new("UTF-8")); /* TODO: Use a SAX parser for better performance */ stream = infd_filesystem_storage_open( INFD_FILESYSTEM_STORAGE(storage), "InfText", path, "r", error ); if(stream == NULL) return FALSE; doc = xmlReadIO( infd_note_plugin_text_session_read_read_func, infd_note_plugin_text_sesison_read_close_func, stream, path, /* TODO: Get some "infinote-filesystem-storage://" URL? */ "UTF-8", XML_PARSE_NOWARNING | XML_PARSE_NOERROR ); if(doc == NULL) { xmlerror = xmlGetLastError(); g_set_error( error, g_quark_from_static_string("LIBXML2_PARSER_ERROR"), xmlerror->code, "Error parsing XML in file '%s': [%d]: %s", path, xmlerror->line, xmlerror->message ); result = FALSE; } else { root = xmlDocGetRootElement(doc); if(strcmp((const char*)root->name, "inf-text-session") != 0) { g_set_error( error, g_quark_from_static_string("INF_NOTE_PLUGIN_TEXT_ERROR"), INFD_NOTE_PLUGIN_TEXT_ERROR_NOT_A_TEXT_SESSION, "Error processing file '%s': %s", path, "The document is not a text session" ); result = FALSE; } else { for(child = root->children; child != NULL; child = child->next) { if(child->type != XML_ELEMENT_NODE) continue; if(strcmp((const char*)child->name, "user") == 0) { if(!infd_note_plugin_text_read_user(user_table, child, error)) { g_prefix_error(error, "Error processing file '%s': ", path); result = FALSE; break; } } else if(strcmp((const char*)child->name, "buffer") == 0) { if(!infd_note_plugin_text_read_buffer(buffer, user_table, child, error)) { g_prefix_error(error, "Error processing file '%s': ", path); result = FALSE; break; } } else { infd_note_plugin_text_session_unexpected_node(child, error); g_prefix_error(error, "Error processing file '%s': ", path); result = FALSE; break; } } if(child == NULL) result = TRUE; } xmlFreeDoc(doc); } if(result == FALSE) return NULL; session = inf_text_session_new_with_user_table( manager, buffer, io, user_table, INF_SESSION_RUNNING, NULL, NULL ); return INF_SESSION(session); }
/** * infd_chat_filesystem_format_read: * @storage: A #InfdFilesystemStorage. * @path: Storage path to retrieve the session from. * @buffer: An empty #InfTextBuffer to use as the new session's buffer. * @error: Location to store error information, if any, or %NULL. * * Reads a chat session from @path in @storage. The file is expected to have * been saved with infd_chat_filesystem_format_write() before. The @buffer * parameter should be an empty #InfChatBuffer, and the document will be * written into this buffer. If the function succeeds, the buffer can be used * to create an #InfChatSession with inf_chat_session_new(). If the function * fails, %FALSE is returned and @error is set. * * Returns: %TRUE on success or %FALSE on error. */ gboolean infd_chat_filesystem_format_read(InfdFilesystemStorage* storage, const gchar* path, InfChatBuffer* buffer, GError** error) { FILE* stream; gchar* full_path; gchar* uri; xmlDocPtr doc; xmlErrorPtr xmlerror; xmlNodePtr root; xmlNodePtr child; gboolean result; g_return_val_if_fail(INFD_IS_FILESYSTEM_STORAGE(storage), FALSE); g_return_val_if_fail(path != NULL, FALSE); g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* TODO: Use a SAX parser for better performance */ full_path = NULL; stream = infd_filesystem_storage_open( INFD_FILESYSTEM_STORAGE(storage), "InfChat", path, "r", &full_path, error ); if(stream == NULL) { g_free(full_path); return FALSE; } uri = g_filename_to_uri(full_path, NULL, error); g_free(full_path); if(uri == NULL) return FALSE; doc = xmlReadIO( infd_chat_filesystem_format_read_read_func, infd_chat_filesystem_format_read_close_func, stream, uri, "UTF-8", XML_PARSE_NOWARNING | XML_PARSE_NOERROR ); g_free(uri); if(doc == NULL) { xmlerror = xmlGetLastError(); g_set_error( error, g_quark_from_static_string("LIBXML2_PARSER_ERROR"), xmlerror->code, _("Error parsing XML in file \"%s\": [%d]: %s"), path, xmlerror->line, xmlerror->message ); result = FALSE; } else { root = xmlDocGetRootElement(doc); if(strcmp((const char*)root->name, "inf-chat-session") != 0) { g_set_error( error, infd_chat_filesystem_format_error_quark(), INFD_CHAT_FILESYSTEM_FORMAT_ERROR_NOT_A_CHAT_SESSION, _("Error processing file \"%s\": %s"), path, _("The document is not a chat session") ); result = FALSE; } else { result = TRUE; } xmlFreeDoc(doc); } if(result == FALSE) return FALSE; return TRUE; }