Sun, 17 Jul 2016 10:40:15 +0200
implemented string functionality for some davql operators
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "db.h" #include <libidav/utils.h> #include <libxml/encoding.h> #include <libxml/xmlwriter.h> #define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b) #ifdef _WIN32 #define ENV_HOME getenv("USERPROFILE") #else #define ENV_HOME getenv("HOME") #endif /* _WIN32 */ SyncDatabase* load_db(char *name) { char *dav_dir = util_concat_path(ENV_HOME, ".dav"); char *db_file = util_concat_path(dav_dir, name); free(dav_dir); SyncDatabase *db = malloc(sizeof(SyncDatabase)); db->resources = ucx_map_new(2048); db->conflict = ucx_map_new(16); xmlTextReaderPtr reader = xmlReaderForFile(db_file, NULL, 0); if(!reader) { xmlDoc *doc = doc = xmlNewDoc(BAD_CAST "1.0"); xmlNode *root = xmlNewNode(NULL, BAD_CAST "directory"); xmlDocSetRootElement(doc, root); if(!xmlSaveFormatFileEnc(db_file, doc, "UTF-8", 1) != -1) { destroy_db(db); db = NULL; } xmlFreeDoc(doc); free(db_file); return db; } free(db_file); int error = 0; while(xmlTextReaderRead(reader)) { int type = xmlTextReaderNodeType(reader); const xmlChar *name = xmlTextReaderConstName(reader); if(type == XML_READER_TYPE_ELEMENT) { if(xstreq(name, "resource")) { LocalResource *res = process_resource(reader); if(res) { ucx_map_cstr_put(db->resources, res->path, res); } else { error = 1; break; } } else if(xstreq(name, "conflict")) { LocalResource *res = process_conflict(reader); if(res) { ucx_map_cstr_put(db->conflict, res->path, res); } else { error = 1; break; } } } } xmlFreeTextReader(reader); if(error) { destroy_db(db); return NULL; } else { return db; } } LocalResource* process_resource(xmlTextReaderPtr reader) { LocalResource *res = calloc(1, sizeof(LocalResource)); int field = -1; while(xmlTextReaderRead(reader)) { int type = xmlTextReaderNodeType(reader); const xmlChar *name = xmlTextReaderConstName(reader); if(type == XML_READER_TYPE_ELEMENT) { if(xstreq(name, "path")) { field = 0; } else if(xstreq(name, "etag")) { field = 1; } else if(xstreq(name, "lastmodified")) { field = 2; } else if(xstreq(name, "size")) { field = 3; } } else if(type == XML_READER_TYPE_TEXT) { const xmlChar *value = xmlTextReaderConstValue(reader); //int b = 0; switch(field) { case 0: { res->path = strdup((char*)value); break; } case 1: { res->etag = strdup((char*)value); break; } case 2: { //res->last_modified = util_parse_lastmodified((char*)value); //res->last_modified = atoi((char*)value); char *endptr = (char*)value; time_t t = strtoll((char*)value, &endptr, 10); if(endptr == (char*)value) { fprintf( stderr, "lastmodified does not contain a number: %s\n", value); } else { res->last_modified = t; } break; } case 3: { res->size = atoi((char*)value); break; } } } else if(XML_READER_TYPE_END_ELEMENT) { if(xstreq(name, "resource")) { break; } else { field = -1; } } } if(!res->path) { // TODO: free res return NULL; } else { return res; } } LocalResource* process_conflict(xmlTextReaderPtr reader) { LocalResource *res = calloc(1, sizeof(LocalResource)); int path = 0; while(xmlTextReaderRead(reader)) { int type = xmlTextReaderNodeType(reader); const xmlChar *name = xmlTextReaderConstName(reader); if(type == XML_READER_TYPE_ELEMENT) { if(xstreq(name, "path")) { path = 1; } } else if(type == XML_READER_TYPE_TEXT && path) { const xmlChar *value = xmlTextReaderConstValue(reader); res->path = strdup((char*)value); } else if(XML_READER_TYPE_END_ELEMENT) { if(xstreq(name, "conflict")) { break; } else { path = 0; } } } if(!res->path) { // TODO: free res return NULL; } else { return res; } } int store_db(SyncDatabase *db, char *name) { // open writer char *dav_dir = util_concat_path(ENV_HOME, ".dav"); char *db_file = util_concat_path(dav_dir, name); free(dav_dir); xmlTextWriterPtr writer = xmlNewTextWriterFilename(db_file, 0); if(!writer) { fprintf(stderr, "Cannot write db file: %s\n", db_file); free(db_file); return -1; } free(db_file); // start document int r = 0; r = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL); if(r < 0) { xmlFreeTextWriter(writer); return -1; } xmlTextWriterStartElement(writer, BAD_CAST "directory"); // write all resource entries UcxMapIterator i = ucx_map_iterator(db->resources); LocalResource *res; UCX_MAP_FOREACH(key, res, i) { // <resource> xmlTextWriterStartElement(writer, BAD_CAST "resource"); r = xmlTextWriterWriteElement( writer, BAD_CAST "path", BAD_CAST res->path); if(r < 0) { fprintf(stderr, "Cannot write path: %s\n", res->path); xmlFreeTextWriter(writer); return -1; } if(res->etag) { r = xmlTextWriterWriteElement( writer, BAD_CAST "etag", BAD_CAST res->etag); if(r < 0) { fprintf(stderr, "Cannot write etag: %s\n", res->etag); xmlFreeTextWriter(writer); return -1; } } r = xmlTextWriterWriteFormatElement( writer, BAD_CAST "lastmodified", "%" PRId64, (int64_t)res->last_modified); if(r < 0) { fprintf(stderr, "Cannot write lastmodified\n"); xmlFreeTextWriter(writer); return -1; } r = xmlTextWriterWriteFormatElement( writer, BAD_CAST "size", "%" PRId64, (int64_t)res->size); if(r < 0) { fprintf(stderr, "Cannot write size\n"); xmlFreeTextWriter(writer); return -1; } // </resource> xmlTextWriterEndElement(writer); } // write all remove entries /* i = ucx_map_iterator(db->remove); UCX_MAP_FOREACH(key, res, i) { // <remove> xmlTextWriterStartElement(writer, BAD_CAST "remove"); xmlTextWriterWriteElement( writer, BAD_CAST "path", BAD_CAST res->path); // </remove> xmlTextWriterEndElement(writer); } */ // write all conflict entries i = ucx_map_iterator(db->conflict); UCX_MAP_FOREACH(key, res, i) { // <conflict> xmlTextWriterStartElement(writer, BAD_CAST "conflict"); xmlTextWriterWriteElement( writer, BAD_CAST "path", BAD_CAST res->path); // </conflict> xmlTextWriterEndElement(writer); } // end xmlTextWriterEndElement(writer); r = xmlTextWriterEndDocument(writer); if(r < 0) { xmlFreeTextWriter(writer); return -1; } xmlFreeTextWriter(writer); return 0; } void destroy_db(SyncDatabase *db) { ucx_map_free_content(db->resources, (ucx_destructor)local_resource_free); ucx_map_free_content(db->conflict, (ucx_destructor)local_resource_free); ucx_map_free(db->resources); ucx_map_free(db->conflict); free(db); } void local_resource_free(LocalResource *res) { if(!res) { return; } if(res->name) { free(res->name); } if(res->path) { free(res->path); } if(res->etag) { free(res->etag); } free(res); }