scbdoc.c

Go to the documentation of this file.
00001 /*
00002  * File Name: scbdoc.c
00003  */
00004 
00005 /*
00006  * This file is part of liberscribble.
00007  *
00008  * liberscribble is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * liberscribble is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 
00028 #define _GNU_SOURCE
00029 
00030 //----------------------------------------------------------------------------
00031 // Include Files
00032 //----------------------------------------------------------------------------
00033 
00034 // system include files, between < >
00035 #include <fcntl.h>
00036 #include <string.h>
00037 #include <assert.h>
00038 
00039 #ifdef WIN32
00040 #include <windows.h>
00041 #else
00042 #include <sys/time.h>
00043 #endif
00044 
00045 #include <glib.h>
00046 #include <glib/gprintf.h>
00047 
00048 // ereader include files, between < >
00049 
00050 // local include files, between " "
00051 #include "scbdoc.h"
00052 #include "scblog.h"
00053 #include "scbpage.h"
00054 
00055 
00056 //----------------------------------------------------------------------------
00057 // Type Declarations
00058 //----------------------------------------------------------------------------
00059 
00060 
00061 //----------------------------------------------------------------------------
00062 // Global Constants
00063 //----------------------------------------------------------------------------
00064 
00065 #define METADB_FILE_POSITION "file_position"
00066 #define METADB_START_ANCHOR  "start_anchor"
00067 #define METADB_END_ANCHOR    "end_anchor"
00068 #define METADB_ANNOTATION_ID "annotation_id"
00069 #define METADB_DATA          "data"
00070 
00071 
00072 //----------------------------------------------------------------------------
00073 // Static Variables
00074 //----------------------------------------------------------------------------
00075 
00076 // g_enable_autodelete: TRUE  -> (default) automaticaly delete pages with stroke count 0 
00077 // g_enable_autodelete: FALSE -> do not automaticaly delete pages with stroke count 0 
00078 static gboolean g_enable_autodelete = TRUE;
00079 
00080 //============================================================================
00081 // Local Function Definitions
00082 //============================================================================
00083 
00084 static void             update_timestamp                (ScbPagePtr page);
00085 static void             remove_oldest_page_scribbles    (ScbDocPtr doc);
00086 static gboolean         load_application_data           (ScbDocPtr doc);
00087 static gboolean         save_application_data           (ScbDocPtr doc);
00088 static void             load_pages_basic_data           (const ScbDocPtr doc, 
00089                                                          const metadata_table *table);
00090 static metadata_table   *load_document_data             (const ScbDocPtr doc);
00091 static gboolean         load_page_data                  (ScbDocPtr doc, 
00092                                                          ScbPagePtr page);
00093 
00094 #ifdef SAVE_TO_FILE
00095 static ScbStreamPtr doc_load_page_file                  (const ScbPageIdPtr id);
00096 static gboolean doc_save_page_file                      (const ScbPageIdPtr id, 
00097                                                          ScbStreamPtr stream);
00098 #else
00099 static gboolean save_page_data                          (const ScbDocPtr doc, 
00100                                                          const ScbPagePtr page, 
00101                                                          const ScbStreamPtr stream,
00102                                                          gboolean *need_free_stream);
00103 #endif
00104 
00105 //============================================================================
00106 // Functions Implementation
00107 //============================================================================
00108 
00109 void erscribble_doc_init_context(ScbDocPtr ptr)
00110 {
00111     LOGPRINTF("entry");
00112     // TODO. Remove the old code and initialize the setting by new items(shape...)
00113     ptr->context.table = g_array_sized_new(FALSE, TRUE, 
00114             sizeof(ScbTBSItem), ERSCRIBBLE_DEF_CMD_ACT_SIZE);
00115     ptr->context.curState = ERSCRIBBLE_TBS_SCRIBBLE;
00116     ptr->context.curStrokeAttr.color     = ERSCRIBBLE_DEV_COLOR_BLACK;
00117     ptr->context.curStrokeAttr.layer     = ERSCRIBBLE_DEF_STROKE_LAYER;
00118     ptr->context.curStrokeAttr.points_number = 0;
00119     ptr->context.curStrokeAttr.shape_id  = ERSCRIBBLE_DEF_SHAPE_LINE;
00120     ptr->context.curStrokeAttr.zoom      = ERSCRIBBLE_DEF_ZOOM_FACTOR;
00121 
00122     ptr->context.appId = -1;
00123 
00124     // The application data is goint to be saved
00125     ptr->context.need_save_app = TRUE;
00126     LOGPRINTF("exit");
00127 }
00128 
00129 
00130 void erscribble_doc_free_context(ScbDocPtr ptr)
00131 {
00132     LOGPRINTF("entry");
00133     if (ptr->context.table != NULL)
00134     {
00135         g_array_free(ptr->context.table, TRUE);
00136         ptr->context.table = NULL;
00137     }
00138     LOGPRINTF("exit");
00139 }
00140 
00141 
00142 ScbDocPtr erscribble_doc_new(const ScbPathPtr target_doc_path)
00143 {
00144     LOGPRINTF("entry");
00145     g_return_val_if_fail((target_doc_path && target_doc_path->document_path != '\0'), NULL);
00146 
00147     gchar *path = g_path_get_dirname(target_doc_path->document_path);
00148     erMetadb db = ermetadb_local_open(path, TRUE);
00149     g_free(path);
00150     if (db == NULL) return NULL;
00151 
00152     gchar *name = g_path_get_basename(target_doc_path->document_path);
00153     ScbDocPtr doc = erscribble_doc_new_with_database(name, db);
00154     g_free(name);
00155     if (doc == NULL) {
00156         ermetadb_close(db);
00157     }
00158     LOGPRINTF("exit");
00159     return doc;
00160 }
00161 
00162 
00163 ScbDocPtr erscribble_doc_new_with_database(const char *target_file_name, erMetadb metadata_db)
00164 {
00165 
00166     LOGPRINTF("entry");
00167     g_return_val_if_fail((target_file_name && *target_file_name), NULL);
00168 
00169     ScbDocPtr doc = g_new0(ScbDoc, 1);
00170     if (NULL == doc)
00171     {
00172         ERRORPRINTF("Not enough memory!");
00173         return NULL;
00174     }
00175 
00176     if (!erscribble_pages_new(&doc->pages))
00177     {
00178         g_free(doc);
00179         return NULL;
00180     }
00181 
00182     erscribble_doc_init_context(doc);
00183 
00184     // set version data
00185     doc->version.version_number.major = ERSCRIBBLE_LIB_VERSION_MAJOR;
00186     doc->version.version_number.minor = ERSCRIBBLE_LIB_VERSION_MINOR;
00187     doc->version.company = g_string_new(ERSCRIBBLE_LIB_ORG);
00188 
00189     // set screen data
00190     doc->screen.dpi = ERSCRIBBLE_DEF_SCREEN_DPI;
00191     doc->screen.units = g_string_new(ERSCRIBBLE_DEF_SCREEN_UNITS);
00192 
00193     // use the specified metadata db for the document
00194     doc->metadata_db = metadata_db;
00195 
00196     // set the target document path
00197     strcpy(doc->path.document_path, target_file_name);
00198 
00199     LOGPRINTF("exit");
00200     return doc;
00201 }
00202 
00203 
00204 void erscribble_doc_free(ScbDocPtr ptr)
00205 {
00206     LOGPRINTF("entry");
00207     if (NULL == ptr)
00208     {
00209         return;
00210     }
00211 
00212     erscribble_doc_free_context(ptr);
00213     erscribble_pages_free(&ptr->pages);
00214 
00215     if (ptr->version.company != NULL)
00216     {
00217         g_string_free(ptr->version.company, TRUE);
00218     }
00219 
00220     if (ptr->screen.units != NULL)
00221     {
00222         g_string_free(ptr->screen.units, TRUE);
00223     }
00224 
00225     g_free(ptr);
00226     LOGPRINTF("exit");
00227 }
00228 
00229 
00230 void erscribble_doc_free_without_database(ScbDocPtr ptr)
00231 {
00232     LOGPRINTF("entry");
00233     if (NULL == ptr)
00234     {
00235         return;
00236     }
00237 
00238     // close the database
00239     ermetadb_close(ptr->metadata_db);
00240     ptr->metadata_db = NULL;
00241 
00242     // free the scribbble doc
00243     erscribble_doc_free(ptr);
00244     LOGPRINTF("exit");
00245 }
00246 
00247 
00248 ScbDocPtr erscribble_doc_open(const ScbPathPtr target_doc_path)
00249 {
00250     LOGPRINTF("entry");
00251     g_return_val_if_fail((target_doc_path && target_doc_path->document_path != '\0'), NULL);
00252 
00253     gchar *path = g_path_get_dirname(target_doc_path->document_path);
00254     erMetadb db = ermetadb_local_open(path, FALSE);
00255     g_free(path);
00256     if (db == NULL) return NULL;
00257     
00258     gchar *name = g_path_get_basename(target_doc_path->document_path);
00259     ScbDocPtr doc = erscribble_doc_open_with_database(name, db);
00260     g_free(name);
00261     if (doc == NULL)
00262     {
00263         ermetadb_close(db);
00264     }
00265     LOGPRINTF("exit");
00266     return doc;
00267 }
00268 
00269 
00270 ScbDocPtr erscribble_doc_open_with_database(const char *target_file_name, erMetadb metadata_db)
00271 {
00272     LOGPRINTF("entry");
00273     ScbDocPtr doc = NULL; 
00274     gboolean  ok;
00275 
00276     g_return_val_if_fail((target_file_name && *target_file_name), NULL);
00277 
00278     doc = g_new0(ScbDoc, 1);
00279     if (NULL == doc)
00280     {
00281         ERRORPRINTF("Not enough memory!");
00282         return NULL;
00283     }
00284 
00285     doc->metadata_db = metadata_db;
00286 
00287     // set the target document path
00288     strcpy(doc->path.document_path, target_file_name);
00289 
00290     ok = load_application_data(doc);
00291     if (ok)
00292     {
00293         // the application data has been saved in metadb
00294         // we don't have to save it again
00295         // TODO. if the application data is modified, set the flag to be TRUE
00296         doc->context.need_save_app = FALSE;
00297 
00298         ok = erscribble_pages_new(&doc->pages);
00299     }
00300 
00301     if (ok)
00302     {
00303         // load the document data from data base
00304         ok = (NULL != load_document_data(doc));
00305     }
00306 
00307     if (ok)
00308     {
00309         erscribble_doc_init_context(doc); 
00310     }
00311 
00312     if (!ok)
00313     {
00314         // free the document
00315         erscribble_doc_free(doc);
00316         doc = NULL;
00317     }
00318     LOGPRINTF("exit");
00319     return doc;
00320 }
00321 
00322 
00323 ScbPagesPtr erscribble_doc_get_pages(ScbDocPtr ptr)
00324 {
00325     LOGPRINTF("entry");
00326     if (ptr)
00327     {
00328         return &ptr->pages;
00329     }
00330     return NULL;
00331 }
00332 
00333 
00334 ScbStrokeAttributesPtr erscribble_doc_get_current_stroke_attributes(ScbDocPtr doc)
00335 {
00336     LOGPRINTF("entry");
00337     return &doc->context.curStrokeAttr;
00338 }
00339 
00340 
00341 ScbPagePtr erscribble_doc_get_page(ScbDocPtr doc, const ScbPageIdPtr id)
00342 {
00343     LOGPRINTF("entry");
00344     ScbPagesPtr pages = erscribble_doc_get_pages(doc);
00345     if (NULL == pages)
00346     {
00347         ERRORPRINTF("Pages list is not constructed!");
00348         return NULL;
00349     }
00350 
00351     // search the page from cache
00352     ScbPagePtr page = erscribble_pages_get_page(pages, id);
00353 
00354     if (page != NULL)
00355     {
00356         // update the access time of current page
00357         update_timestamp(page);
00358 
00359         // load the BLOB data of current page if it exists
00360         // at this time, the BLOB data of oldest page would be deleted
00361         load_page_data(doc, page);
00362     }
00363     else
00364     {
00365 #ifdef SAVE_TO_FILE
00366         // TEST try to load the page in local file
00367         page = erscribble_page_new();
00368 
00369         ScbStreamPtr stream = doc_load_page_file(id);
00370         if (stream != NULL)
00371         {
00372             erscribble_page_load(page, stream);
00373         }
00374 
00375         erscribble_page_copy_id(&page->id, id);
00376         // add the loaded page into cache
00377         erscribble_pages_add_page(&doc->pages, page);
00378 #else
00379         // if the page is exist, create a new one
00380         page = erscribble_page_new();
00381 
00382         erscribble_page_copy_id(&page->id, id);
00383 
00384         erscribble_pages_add_page(pages, page);
00385 
00386         // update the access time of current page
00387         update_timestamp(page);
00388 #endif
00389     }
00390 
00391     assert(page != NULL);
00392 
00393     LOGPRINTF("exit");
00394     return page;
00395 }
00396 
00397 
00398 gboolean erscribble_doc_save_page(ScbDocPtr doc, ScbPagePtr page)
00399 {
00400     LOGPRINTF("entry");
00401     if (doc->context.need_save_app)
00402     {
00403         gboolean ok = save_application_data(doc);
00404         if (!ok)
00405         {
00406             LOGPRINTF("save_application_data NOK");
00407             return FALSE;
00408         }
00409         doc->context.need_save_app = FALSE;
00410     }
00411 
00412     int page_len = erscribble_page_get_length(page);
00413     LOGPRINTF("page_len %d page %s", page_len, page->id.id);
00414     // need free the stream buffer?
00415     gboolean need_free_stream_buffer = TRUE;
00416 
00417     // create a memory stream for writing, length = page length + 128
00418     ScbStreamPtr stream = erscribble_create_stream(page_len + 128);
00419 
00420     if (NULL == stream)
00421     {
00422         LOGPRINTF("creation of stream failed");
00423         return FALSE;
00424     }
00425 
00426     // set the minor version number of the library
00427     erscribble_page_set_minor_version_number(page, doc->version.version_number.minor);
00428     LOGPRINTF("minor version number %d", doc->version.version_number.minor);
00429     
00430     // write the page data into stream
00431     gboolean ret = erscribble_page_write_stream(page, stream);
00432     if (ret)
00433     {
00434 #ifdef SAVE_TO_FILE
00435         ret = doc_save_page_file(&page->id, stream);
00436 #else
00437         ret = save_page_data(doc, page, stream, &need_free_stream_buffer);
00438 #endif
00439     }
00440 
00441     // Free the stream by the results of saving operation
00442     if (!need_free_stream_buffer)
00443     {
00444         // if the saving operation returns successfully, it means
00445         // that the BLOB has been written into database. The ownership of
00446         // stream's buffer has been transfered to metadata lib.
00447         // Scribble lib MUST NOT free the memory any more.
00448         erscribble_free_stream(stream, FALSE);
00449     }
00450     else
00451     {
00452         // if saving fails, scribble lib considers the ownership has not
00453         // been transfered to metadata lib. So the memory should be released here.
00454         // TODO. HOWEVER, a problem is that the saveing may fail no matter whether
00455         // taking the ownership of BLOB or not. SHOULD BE FIXED.
00456         erscribble_free_stream(stream, TRUE);
00457     }
00458 
00459     LOGPRINTF("exit %d", ret);
00460     return ret;
00461 }
00462 
00463 
00464 gboolean erscribble_doc_add_page(ScbDocPtr doc, ScbPagePtr page)
00465 {
00466     LOGPRINTF("entry");
00467     ScbPagesPtr pages = erscribble_doc_get_pages(doc);
00468     if (NULL == pages) return FALSE;
00469     LOGPRINTF("exit");
00470     return erscribble_pages_add_page(pages, page);
00471 }
00472 
00473 static gboolean erscribble_doc_insert_page_impl(ScbDocPtr doc, ScbPagesPtr pages, ScbPagePtr page)
00474 {
00475     LOGPRINTF("entry");
00476     // Note: page is already created with erscribble_page_new
00477     ERSCRIBBLE_RET_FALSE_IF(NULL == doc || NULL == pages || NULL == page, "Invalid pages or page pointer!");
00478    
00479     int result = ER_OK;
00480     ScbPagePtr cur_page  = NULL;
00481     GList* ptr = g_list_first(pages->pages);
00482     while (ptr)
00483     {
00484         cur_page = (ScbPagePtr)ptr->data;
00485         if (cur_page && (cur_page->id.position >= page->id.position))
00486         {
00487             // move pages after inserted page
00488             // update the access time of current page
00489             update_timestamp(cur_page);
00490 
00491             // load the BLOB data of current page if it exists
00492             load_page_data(doc, cur_page);
00493 
00494             cur_page->id.position += 1;
00495             gint64 my_id = 0;
00496             my_id = g_ascii_strtoll(cur_page->id.id,  NULL, 10);
00497             my_id += 1;
00498             g_sprintf(cur_page->id.id, "%lld", my_id);
00499             result = erscribble_doc_save_page(doc, cur_page); 
00500             LOGPRINTF("incremented page id to %s(%d) res: %d", cur_page->id.id, cur_page->id.position, result);
00501             if (result != ER_OK) break;
00502         }
00503         ptr = g_list_next(ptr);
00504     }
00505 
00506     // add and save new page
00507     if (result == ER_OK )
00508     {
00509         pages->pages = g_list_append(pages->pages, page); 
00510         result = erscribble_doc_save_page(doc, page); 
00511     }
00512 
00513     LOGPRINTF("exit %d", result);
00514     return (gboolean)( result == ER_OK );
00515 }
00516 
00517 gboolean erscribble_doc_insert_page(ScbDocPtr doc, ScbPagePtr page)
00518 {
00519     LOGPRINTF("entry");
00520     ScbPagesPtr pages = erscribble_doc_get_pages(doc);
00521     if (NULL == pages) 
00522         return FALSE;
00523     LOGPRINTF("exit");
00524     return erscribble_doc_insert_page_impl(doc, pages, page);
00525 }
00526 
00527 static gboolean erscribble_doc_delete_page_impl(ScbDocPtr doc, ScbPagesPtr pages, ScbPageIdPtr pid)
00528 {
00529     LOGPRINTF("entry");
00530     ERSCRIBBLE_RET_FALSE_IF(NULL == doc || NULL == pages || NULL == pid, "Invalid pages or page pointer!");
00531    
00532     int result = -1;
00533     gboolean ok = FALSE;
00534     ScbPagePtr page = erscribble_pages_get_page(pages, pid);
00535 
00536     if (page != NULL)
00537     {
00538         // update the access time of current page
00539         update_timestamp(page);
00540 
00541         // load the BLOB data of current page if it exists
00542         // at this time, the BLOB data of oldest page would be deleted
00543         erscribble_page_clear_strokes(page);
00544         page->is_blob_loaded = FALSE;
00545         load_page_data(doc, page);
00546     }
00547   
00548     ermetadb_local_remove_annotation(doc->metadata_db, page->id.annotation_id);
00549     page = NULL ; 
00550     erscribble_pages_free(&doc->pages);
00551 
00552     ok = erscribble_pages_new(&doc->pages);
00553 
00554     if (ok)
00555     {
00556         // load the document data from data base
00557         ok = (NULL != load_document_data(doc));
00558     }
00559 
00560     GList* ptr = g_list_first((&doc->pages)->pages);
00561     ScbPagePtr cur_page = (ScbPagePtr)ptr->data;
00562 
00563     if (ok)
00564     {
00565         while (ptr)
00566         {
00567             cur_page = (ScbPagePtr)ptr->data;
00568             if (cur_page && (cur_page->id.position > pid->position))
00569             {
00570                 // update the access time of current page
00571                 update_timestamp(cur_page);
00572                 load_page_data(doc, cur_page);
00573 
00574                 cur_page->id.position -= 1;
00575                 gint64 my_id = 0;
00576                 my_id = g_ascii_strtoll(cur_page->id.id,  NULL, 10  );
00577                 my_id -= 1;
00578                 g_sprintf(cur_page->id.id, "%lld", my_id);
00579 
00580                 result = erscribble_doc_save_page(doc, cur_page); // todo check result
00581                 if (result != ER_OK ) break;
00582             }
00583             ptr = g_list_next(ptr);
00584         }
00585     }
00586     else 
00587     {
00588         result = -1;
00589     }
00590 
00591     LOGPRINTF("exit");
00592     return (gboolean)( result == ER_OK );
00593 }
00594 
00595 
00596 gboolean erscribble_doc_delete_page(ScbDocPtr doc, ScbPageIdPtr pid)
00597 {
00598     LOGPRINTF("entry");
00599     ScbPagesPtr pages = erscribble_doc_get_pages(doc);
00600     if (NULL == pages) 
00601         return FALSE;
00602     LOGPRINTF("exit");
00603     return erscribble_doc_delete_page_impl(doc, pages, pid);
00604 }
00605 
00606 
00607 void erscribble_doc_add_map_item(ScbDocPtr doc, const ScbTBSItemPtr ptr)
00608 {
00609     LOGPRINTF("entry");
00610     //ERSCRIBBLE_RET_IF(NULL == doc || NULL == ptr, "Invalid pointer(s)!");
00611     g_array_append_val(doc->context.table,  *ptr);
00612     LOGPRINTF("exit");
00613 }
00614 
00615 
00616 ScbTBState erscribble_doc_get_current_state(ScbDocPtr doc)
00617 {
00618     if (NULL == doc) return ERSCRIBBLE_TBS_INVALID;
00619     return doc->context.curState;
00620 }
00621 
00622 
00623 gboolean erscribble_state_is_scribble(ScbDocPtr doc)
00624 {
00625     return ERSCRIBBLE_TBS_SCRIBBLE == erscribble_doc_get_current_state(doc);
00626 }
00627 
00628 
00629 gboolean erscribble_state_is_erase(ScbDocPtr doc)
00630 {
00631     return ERSCRIBBLE_TBS_ERASE == erscribble_doc_get_current_state(doc);
00632 }
00633 
00634 
00635 void erscribble_doc_dump(ScbDocPtr ptr)
00636 {
00637     if (ptr)
00638     {
00639         erscribble_pages_dump(&ptr->pages);
00640     }
00641 }
00642 
00643 
00644 //============================================================================
00645 // Local Functions Implementation
00646 //============================================================================
00647 
00648 static void update_timestamp(ScbPagePtr page)
00649 {
00650     int now;
00651 #ifdef WIN32
00652     now = GetTickCount();
00653 #else
00654     struct timeval cur_time_struct;
00655     gettimeofday(&cur_time_struct, 0);
00656     now = cur_time_struct.tv_sec;
00657 #endif
00658     page->timestamp = now;
00659 }
00660 
00661 
00662 static void remove_oldest_page_scribbles(ScbDocPtr doc)
00663 {
00664     LOGPRINTF("entry");
00665     gboolean ret_clear = FALSE;
00666     while (!ret_clear)
00667     {
00668         ret_clear = remove_oldest_page_data(&doc->pages);
00669     }
00670     LOGPRINTF("exit");
00671 }
00672 
00673 
00674 static gboolean load_application_data(ScbDocPtr doc)
00675 {
00676     LOGPRINTF("entry");
00677     if (doc->metadata_db == NULL)
00678     {
00679         ERRORPRINTF("Document is not ready");
00680         return FALSE;
00681     }
00682 
00683     // get document basic information from application_data table
00684 
00685     // 1. create an empty table with required keys
00686     metadata_table *name_table = metadata_table_new();
00687 
00688     if (name_table == NULL)
00689     {
00690         return FALSE;
00691     }
00692 
00693     // 2. set new column of the table
00694     metadata_table_add_column(name_table, ERSCRIBBLE_VERSION_MAJOR);
00695     metadata_table_add_column(name_table, ERSCRIBBLE_VERSION_MINOR);
00696     metadata_table_add_column(name_table, ERSCRIBBLE_VERSION_COMPANY);
00697     metadata_table_add_column(name_table, ERSCRIBBLE_SCREEN_DPI);
00698     metadata_table_add_column(name_table, ERSCRIBBLE_SCREEN_UNITS);
00699 
00700     // 3. get the results
00701     metadata_table *results_table = NULL;
00702     int ret = ermetadb_local_get_application_data(doc->metadata_db
00703             , doc->path.document_path
00704             , name_table
00705             , &results_table);
00706     metadata_table_free(name_table);
00707 
00708     if (results_table == NULL)
00709     {
00710         return FALSE;
00711     }
00712 
00713     if (ret == ER_OK)
00714     {
00715         const metadata_cell *cell = NULL;
00716         // get major version number
00717         int index = metadata_table_find_column(results_table, ERSCRIBBLE_VERSION_MAJOR);
00718         if (index >= 0)
00719         {
00720             cell = metadata_table_get_cell(results_table, index);
00721             if (cell != NULL)
00722             {
00723                 sscanf(cell->value.v_text->str, "%hd", &doc->version.version_number.major);
00724 
00725                 cell = NULL;
00726             }
00727         }
00728 
00729         //  get minor version number
00730         index = metadata_table_find_column(results_table, ERSCRIBBLE_VERSION_MINOR);
00731         if (index >= 0)
00732         {
00733             cell = metadata_table_get_cell(results_table, index);
00734             if (cell != NULL)
00735             {
00736                 sscanf(cell->value.v_text->str, "%hd", &doc->version.version_number.minor);
00737 
00738                 cell = NULL;
00739             }
00740         }
00741 
00742         // get company name
00743         index = metadata_table_find_column(results_table, ERSCRIBBLE_VERSION_COMPANY);
00744         if (index >= 0)
00745         {
00746             cell = metadata_table_get_cell(results_table, index);
00747             if (cell != NULL)
00748             {
00749                 doc->version.company = g_string_new(cell->value.v_text->str);
00750                 cell = NULL;
00751             }
00752         }
00753 
00754         // get screen dpi
00755         index = metadata_table_find_column(results_table, ERSCRIBBLE_SCREEN_DPI);
00756         if (index >= 0)
00757         {
00758             cell = metadata_table_get_cell(results_table, index);
00759             if (cell != NULL)
00760             {
00761                 sscanf(cell->value.v_text->str, "%d", &doc->screen.dpi);
00762 
00763                 cell = NULL;
00764             }
00765         }
00766 
00767         // get screen units
00768         index = metadata_table_find_column(results_table, ERSCRIBBLE_SCREEN_UNITS);
00769         if (index >= 0)
00770         {
00771             cell = metadata_table_get_cell(results_table, index);
00772             if (cell != NULL)
00773             {
00774                 doc->screen.units = g_string_new(cell->value.v_text->str);
00775                 cell = NULL;
00776             }
00777         }
00778     }
00779 
00780     // free the results table
00781     metadata_table_free(results_table);
00782 
00783     LOGPRINTF("exit");
00784     return (ret == ER_OK);
00785 }
00786 
00787 
00788 static gboolean save_application_data(ScbDocPtr doc)
00789 {
00790     LOGPRINTF("entry");
00791     if (doc->metadata_db == NULL)
00792     {
00793         ERRORPRINTF("Document is not ready");
00794         return FALSE;
00795     }
00796     
00797     // This function MUST be called when there is scribble data in current document
00798 
00799     // save document basic information into application_data table
00800     // 1. create an empty table with required keys
00801     metadata_table *value_table = metadata_table_new();
00802 
00803     if (value_table == NULL)
00804     {
00805         return FALSE;
00806     }
00807 
00808     // 2. set new column of the table
00809     metadata_table_add_column(value_table, ERSCRIBBLE_VERSION_MAJOR);
00810     metadata_table_add_column(value_table, ERSCRIBBLE_VERSION_MINOR);
00811     metadata_table_add_column(value_table, ERSCRIBBLE_VERSION_COMPANY);
00812     metadata_table_add_column(value_table, ERSCRIBBLE_SCREEN_DPI);
00813     metadata_table_add_column(value_table, ERSCRIBBLE_SCREEN_UNITS);
00814 
00815     // 3. set the value of each item
00816     GString *value_str = g_string_new("");
00817 
00818     int index = metadata_table_find_column(value_table, ERSCRIBBLE_VERSION_MAJOR);
00819     if (index >= 0)
00820     {
00821         g_string_printf(value_str, "%d", doc->version.version_number.major);
00822         if (metadata_table_set_text(value_table, index, value_str->str)
00823             != ER_OK)
00824         {
00825             ERRORPRINTF("Cannot write major version number");
00826         }
00827     }
00828 
00829     index = metadata_table_find_column(value_table, ERSCRIBBLE_VERSION_MINOR);
00830     if (index >= 0)
00831     {
00832         g_string_printf(value_str, "%d", doc->version.version_number.minor);
00833         if (metadata_table_set_text(value_table, index, value_str->str)
00834             != ER_OK)
00835         {
00836             ERRORPRINTF("Cannot write minor version number");
00837         }
00838     }
00839 
00840     index = metadata_table_find_column(value_table, ERSCRIBBLE_VERSION_COMPANY);
00841     if (index >= 0)
00842     {
00843         if (metadata_table_set_text(value_table, index, doc->version.company->str)
00844             != ER_OK)
00845         {
00846             ERRORPRINTF("Cannot write company name");
00847         }
00848     }
00849 
00850     index = metadata_table_find_column(value_table, ERSCRIBBLE_SCREEN_DPI);
00851     if (index >= 0)
00852     {
00853         g_string_printf(value_str, "%d", doc->screen.dpi);
00854         if (metadata_table_set_text(value_table, index, value_str->str)
00855             != ER_OK)
00856         {
00857             ERRORPRINTF("Cannot write DPI");
00858         }
00859     }
00860 
00861     index = metadata_table_find_column(value_table, ERSCRIBBLE_SCREEN_UNITS);
00862     if (index >= 0)
00863     {
00864         if (metadata_table_set_text(value_table, index, doc->screen.units->str)
00865             != ER_OK)
00866         {
00867             ERRORPRINTF("Cannot write screen units");
00868         }
00869     }
00870 
00871     // write to database
00872     int ret = ermetadb_local_set_application_data(doc->metadata_db, doc->path.document_path, value_table);
00873     metadata_table_free(value_table);
00874 
00875     LOGPRINTF("exit");
00876     return ret == ER_OK;
00877 }
00878 
00879 
00880 static void load_pages_basic_data(const ScbDocPtr doc, const metadata_table *table)
00881 {
00882    LOGPRINTF("entry");
00883     // The page instance would be constructed in this function
00884     // All of the basic data of a page would be set, except the BLOB
00885 
00886     if (table == NULL || table->cell_data->len <= 0)
00887     {
00888         LOGPRINTF("Empty table of scribble");
00889         return;
00890     }
00891 
00892     gint64 position = 0;
00893     gint64 anno_id = 0;
00894     guint  idx = 0;
00895     for (; idx < table->n_rows; ++idx)
00896     {
00897         // read the file position
00898         int cell_idx = metadata_table_find_column(table, METADB_FILE_POSITION);
00899         assert(cell_idx >= 0);
00900         const metadata_cell* cell = metadata_table_get_cell(table,
00901             metadata_table_cell_index(table, idx, cell_idx));
00902         assert(cell->type == METADATA_INT64);
00903         position = cell->value.v_int64;
00904 
00905         // read the annotation id
00906         cell_idx = metadata_table_find_column(table, METADB_ANNOTATION_ID);
00907         assert(cell_idx >= 0);
00908         cell = metadata_table_get_cell(table,
00909             metadata_table_cell_index(table, idx, cell_idx));
00910         assert(cell->type == METADATA_INT64);
00911         anno_id = cell->value.v_int64;
00912 
00913         // read the start anchor
00914         cell_idx = metadata_table_find_column(table, METADB_START_ANCHOR);
00915         assert(cell_idx >= 0);
00916         cell = metadata_table_get_cell(table,
00917             metadata_table_cell_index(table, idx, cell_idx));
00918         assert(cell->type == METADATA_TEXT);
00919         // create a new page with the start anchor and related information
00920         ScbPagePtr page = erscribble_page_new();
00921         if (page != NULL)
00922         {
00923             // add the loaded page into pages list
00924             if (!erscribble_pages_add_page(&doc->pages, page))
00925             {
00926                 erscribble_page_free(page);
00927             }
00928             else
00929             {
00930                 // set page id
00931                 erscribble_page_set_id(&page->id, position, cell->value.v_text->str, anno_id);
00932             }
00933         }
00934     }
00935 
00936     LOGPRINTF("exit");
00937 }
00938 
00939 
00940 static metadata_table *load_document_data(const ScbDocPtr doc)
00941 {
00942    LOGPRINTF("entry");
00943     if (doc->metadata_db == NULL)
00944     {
00945         ERRORPRINTF("Document is not ready");
00946         return NULL;
00947     }
00948 
00949     metadata_table *results = NULL;
00950     int ret = ermetadb_local_select_annotations(
00951                                     doc->metadata_db,
00952                                     doc->path.document_path,
00953                                     ERSCRIBBLE_ANNOTATION_TYPE,
00954                                     NULL,
00955                                     -1,
00956                                     -1,
00957                                     &results);
00958     if (ret == ER_OK)
00959     {
00960         // load all of the pages data from results table
00961         load_pages_basic_data(doc, results);
00962     }
00963     else
00964     {
00965         metadata_table_free(results);
00966         results = NULL;
00967     }
00968 
00969     LOGPRINTF("exit");
00970     return results;
00971 }
00972 
00973 
00974 static gboolean load_page_data(ScbDocPtr doc, ScbPagePtr page)
00975 {
00976     LOGPRINTF("entry");
00977     if (doc->metadata_db == NULL)
00978     {
00979         ERRORPRINTF("Document is not ready");
00980         return FALSE;
00981     }
00982     
00983     if (page->is_blob_loaded)
00984     {
00985         // the blob of this page has been loaded, DO NOT
00986         // access the database again
00987         return FALSE;
00988     }
00989 
00990     if (erscribble_page_get_stroke_count(page) > 0)
00991     {
00992         // if the data of strokes exists, return true
00993         return FALSE;
00994     }
00995 
00996     if (page->id.annotation_id < 0)
00997     {
00998         // the annotation id is invalid, do not query metadb
00999         return FALSE;
01000     }
01001 
01002     // Set is_blob_loaded to be TRUE no matter it can be loaded or not,
01003     // to improve the performance
01004     page->is_blob_loaded = TRUE;
01005 
01006     // Load the BLOB from metadb
01007     // TODO. Load the BLOB of adjacent pages?
01008     gint64 anno_list[1];
01009     anno_list[0] = page->id.annotation_id;
01010 
01011     metadata_table *value = NULL;
01012     int ret = ermetadb_local_get_annotations(doc->metadata_db,
01013         &anno_list[0], 1, &value);
01014 
01015     if (ret != ER_OK || value == NULL)
01016     {
01017         ERRORPRINTF("Cannot retrieve BLOB of page %s", page->id.id);
01018         return FALSE;
01019     }
01020 
01021     // Should not retrieve more than one rows of data
01022     guint idx = 0;
01023     for (; idx < value->n_rows; ++idx)
01024     {
01025         int cell_idx = metadata_table_find_column(value, METADB_DATA);
01026         const metadata_cell *cell =
01027             metadata_table_get_cell(value, metadata_table_cell_index(value, idx, cell_idx));
01028         assert(cell->type == METADATA_BLOB);
01029         gsize length = cell->value.v_blob.len;
01030 
01031         // create a stream to import the BLOB
01032         // TODO. maybe we can use only one stream instance
01033         ScbStreamPtr stream = erscribble_create_stream(length);
01034         if (stream != NULL)
01035         {
01036             // read the BLOB
01037             if (erscribble_write_stream(stream, (void*)cell->value.v_blob.data, length))
01038             {
01039                 erscribble_reset_offset(stream);
01040                 // the BLOB is read out successfully
01041                 // try to load the page
01042                 if (!erscribble_page_load(page, stream))
01043                 {
01044                     ERRORPRINTF("Error happens when loading page:%s",
01045                         page->id.id);
01046                     // clear the strokes if they exist
01047                     erscribble_page_clear_strokes(page);
01048                     return FALSE;
01049                 }
01050 
01051                 // remove the oldest page
01052                 remove_oldest_page_scribbles(doc);
01053             }
01054 
01055             erscribble_free_stream(stream, TRUE);
01056             stream = NULL;
01057         }
01058         else
01059         {
01060             ERRORPRINTF("Not enough memory to create a new stream");
01061             return FALSE;
01062         }
01063     }
01064 
01065     LOGPRINTF("exit");
01066     return TRUE;
01067 }
01068 
01069 
01070 #ifdef SAVE_TO_FILE
01071 
01072 static ScbStreamPtr doc_load_page_file(const ScbPageIdPtr id)
01073 {
01074     LOGPRINTF("entry");
01075     FILE *f_read = fopen(id->id, "rb");
01076     
01077     if (NULL == f_read)
01078     {
01079         // the file does not exist
01080         return NULL;
01081     }
01082     
01083     // obtain file size:
01084     fseek(f_read , 0 , SEEK_END);
01085     long size = ftell(f_read);
01086 
01087     ScbStreamPtr stream = erscribble_create_stream(size);
01088     if (NULL == stream)
01089     {
01090         fclose(f_read);
01091         return NULL;
01092     }
01093 
01094     fseek(f_read, 0, SEEK_SET);
01095     long ret = fread(stream->buffer, 1, size, f_read);
01096     if (ret != size)
01097     {
01098         erscribble_free_stream(stream, TRUE);
01099         stream = NULL;
01100     }
01101 
01102     fclose(f_read);
01103     LOGPRINTF("exit");
01104     return stream;
01105 }
01106 
01107 
01108 static gboolean doc_save_page_file(const ScbPageIdPtr id, ScbStreamPtr stream)
01109 {
01110     LOGPRINTF("entry");
01111     FILE *f_write = fopen(id->id, "wb");
01112     if (NULL == f_write)
01113     {
01114         // the file does not exist
01115         return FALSE;
01116     }
01117 
01118     if (fwrite(stream->buffer, 1, stream->offset, f_write) != stream->offset)
01119     {
01120         return FALSE;
01121     }
01122 
01123     fclose(f_write);
01124 
01125     LOGPRINTF("exit");
01126     return TRUE;
01127 }
01128 
01129 #else
01130 
01131 static gboolean save_page_data(const ScbDocPtr doc, 
01132                                const ScbPagePtr page, 
01133                                const ScbStreamPtr stream,
01134                                gboolean *need_free_stream)
01135 {
01136     LOGPRINTF("entry");
01137     if (doc == NULL || page == NULL || stream == NULL)
01138     {
01139         return FALSE;
01140     }
01141 
01142     if (doc->metadata_db == NULL)
01143     {
01144         ERRORPRINTF("document is not ready");
01145         return FALSE;
01146     }
01147 
01148     int ret = ER_FAIL;
01149     *need_free_stream = TRUE;
01150 
01151     if (page->id.annotation_id < 0)
01152     {
01153         // the page has not been stored in data base before
01154         // create a new row if the number of strokes is not 0
01155         //if (erscribble_page_get_stroke_count(page) > 0)
01156         gboolean do_create = FALSE;
01157         if (g_enable_autodelete)
01158             do_create = erscribble_page_get_stroke_count(page) >  0 ? TRUE : FALSE;
01159         else 
01160             do_create = erscribble_page_get_stroke_count(page) >= 0 ? TRUE : FALSE;
01161             
01162         if (do_create)
01163         {
01164             ret = ermetadb_local_create_annotation (doc->metadata_db,
01165                                               doc->path.document_path,
01166                                               &page->id.annotation_id,
01167                                               ERSCRIBBLE_ANNOTATION_TYPE,
01168                                               "",
01169                                               page->id.position,
01170                                               NULL,      // title is null
01171                                               page->id.id,
01172                                               NULL,      // end anchor is null
01173                                               (gchar*)stream->buffer,
01174                                               stream->offset);
01175 
01176             if (ret == ER_OK)
01177             {
01178                 *need_free_stream = FALSE;
01179             }
01180         }
01181     }
01182     else
01183     {
01184         // the page has been stored in data base
01185         // update it
01186         // if there is no any strokes in the page, we should remove the record in data base
01187         //if (erscribble_page_get_stroke_count(page) > 0)
01188         gboolean do_update = FALSE;
01189         if (g_enable_autodelete)
01190             do_update = erscribble_page_get_stroke_count(page) >  0 ? TRUE : FALSE;
01191         else 
01192             do_update = erscribble_page_get_stroke_count(page) >= 0 ? TRUE : FALSE;
01193 
01194         if (do_update)
01195         {
01196             ret = ermetadb_local_set_annotation(doc->metadata_db,
01197                     page->id.annotation_id,
01198                     ERSCRIBBLE_ANNOTATION_TYPE,
01199                     "",
01200                     page->id.position,
01201                     NULL,        // title is null
01202                     page->id.id,
01203                     NULL,        // end anchor is null
01204                     (gchar*)stream->buffer,
01205                     stream->offset);
01206             if (ret == ER_OK)
01207             {
01208                 *need_free_stream = FALSE;
01209             }
01210         }
01211         else
01212         {
01213             // otherwise update the record
01214             ret = ermetadb_local_remove_annotation(doc->metadata_db,
01215                                              page->id.annotation_id);
01216             // set annotation id to be invalid
01217             page->id.annotation_id = -1;
01218         }
01219     }
01220 
01221     if (page->id.annotation_id >= 0)
01222     {
01223         // Set is_blob_loaded to be TRUE, so that we need not laod the
01224         // BLOB from metadb when getting this page.
01225         page->is_blob_loaded = TRUE;
01226 
01227         // remove the oldest page if necessary
01228         remove_oldest_page_scribbles(doc);
01229     }
01230 
01231     LOGPRINTF("exit");
01232     return ret;
01233 }
01234 
01235 void erscribble_doc_disable_autodelete(gboolean do_disable)
01236 {
01237     g_enable_autodelete = !do_disable ;  // reverse semantics
01238 }
01239 
01240 
01241 
01242 #endif
Generated by  doxygen 1.6.2-20100208