From 5d7fb01f67025dba5fc9262862dce0d978bcb7ed Mon Sep 17 00:00:00 2001 From: louis Date: Fri, 9 May 2014 16:20:06 +0200 Subject: [PATCH] added lib files --- lib/curl.c | 176 +++++++++++++++++++ lib/dbdict.c | 158 +++++++++++++++++ lib/dbdict.h | 52 ++++++ lib/demo.c | 279 ++++++++++++++++++++++++++++++ lib/imgtools.c | 190 ++++++++++++++++++++ lib/imgtools.h | 28 +++ lib/test.c | 458 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1341 insertions(+) create mode 100644 lib/curl.c create mode 100644 lib/dbdict.c create mode 100644 lib/dbdict.h create mode 100644 lib/demo.c create mode 100644 lib/imgtools.c create mode 100644 lib/imgtools.h create mode 100644 lib/test.c diff --git a/lib/curl.c b/lib/curl.c new file mode 100644 index 0000000..6eff24c --- /dev/null +++ b/lib/curl.c @@ -0,0 +1,176 @@ +/* + * curl.c: + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include + +#include "common.h" +#include "config.h" + +//*************************************************************************** +// Callbacks +//*************************************************************************** + +static size_t WriteMemoryCallback(void* ptr, size_t size, size_t nmemb, void* data) +{ + size_t realsize = size * nmemb; + struct MemoryStruct* mem = (struct MemoryStruct*)data; + + if (mem->memory) + mem->memory = (char*)realloc(mem->memory, mem->size + realsize + 1); + else + mem->memory = (char*)malloc(mem->size + realsize + 1); + + if (mem->memory) + { + memcpy (&(mem->memory[mem->size]), ptr, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + } + + return realsize; +} + +static size_t WriteHeaderCallback(void* ptr, size_t size, size_t nmemb, void* data) +{ + size_t realsize = size * nmemb; + struct MemoryStruct* mem = (struct MemoryStruct*)data; + char* p; + + if (ptr) + { + // get filename + { + // Content-Disposition: attachment; filename="20140103_20140103_de_qy.zip" + + const char* attribute = "Content-disposition: "; + + if ((p = strcasestr((char*)ptr, attribute))) + { + if (p = strcasestr(p, "filename=")) + { + p += strlen("filename="); + + tell(4, "found filename at [%s]", p); + + if (*p == '"') + p++; + + sprintf(mem->name, "%s", p); + + if ((p = strchr(mem->name, '\n'))) + *p = 0; + + if ((p = strchr(mem->name, '\r'))) + *p = 0; + + if ((p = strchr(mem->name, '"'))) + *p = 0; + + tell(4, "set name to '%s'", mem->name); + } + } + } + + // since some sources update "ETag" an "Last-Modified:" without changing the contents + // we have to use "Content-Length:" to check for updates :( + { + const char* attribute = "Content-Length: "; + + if ((p = strcasestr((char*)ptr, attribute))) + { + sprintf(mem->tag, "%s", p+strlen(attribute)); + + if ((p = strchr(mem->tag, '\n'))) + *p = 0; + + if ((p = strchr(mem->tag, '\r'))) + *p = 0; + + if ((p = strchr(mem->tag, '"'))) + *p = 0; + } + } + } + + return realsize; +} + +//*************************************************************************** +// Download File +//*************************************************************************** + +int downloadFile(const char* url, int& size, MemoryStruct* data, int timeout, const char* userAgent) +{ + CURL* curl_handle; + long code; + CURLcode res = CURLE_OK; + + size = 0; + + // init curl + + if (curl_global_init(CURL_GLOBAL_ALL) != 0) + { + tell(0, "Error, something went wrong with curl_global_init()"); + + return fail; + } + + curl_handle = curl_easy_init(); + + if (!curl_handle) + { + tell(0, "Error, unable to get handle from curl_easy_init()"); + + return fail; + } + + if (EPG2VDRConfig.useproxy) + { + curl_easy_setopt(curl_handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + curl_easy_setopt(curl_handle, CURLOPT_PROXY, EPG2VDRConfig.httpproxy); // Specify HTTP proxy + } + + curl_easy_setopt(curl_handle, CURLOPT_URL, url); // Specify URL to get + curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 0); // don't follow redirects + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); // Send all data to this function + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void*)data); // Pass our 'data' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, WriteHeaderCallback); // Send header to this function + curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, (void*)data); // Pass some header details to this struct + curl_easy_setopt(curl_handle, CURLOPT_MAXFILESIZE, 100*1024*1024); // Set maximum file size to get (bytes) + curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1); // No progress meter + curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); // No signaling + curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout); // Set timeout + curl_easy_setopt(curl_handle, CURLOPT_NOBODY, data->headerOnly ? 1 : 0); // + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, userAgent); // Some servers don't like requests + // that are made without a user-agent field + // perform http-get + + if ((res = curl_easy_perform(curl_handle)) != 0) + { + data->clear(); + + tell(1, "Error, download failed; %s (%d)", + curl_easy_strerror(res), res); + curl_easy_cleanup(curl_handle); // Cleanup curl stuff + + return fail; + } + + curl_easy_getinfo(curl_handle, CURLINFO_HTTP_CODE, &code); + curl_easy_cleanup(curl_handle); // cleanup curl stuff + + if (code == 404) + { + data->clear(); + return fail; + } + + size = data->size; + + return success; +} diff --git a/lib/dbdict.c b/lib/dbdict.c new file mode 100644 index 0000000..0b2211e --- /dev/null +++ b/lib/dbdict.c @@ -0,0 +1,158 @@ +/* + * dbdict.c + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include "common.h" +#include "dbdict.h" + +//*************************************************************************** +// cDbDict +//*************************************************************************** + +cDbDict::cDbDict() +{ + inside = no; +} + +cDbDict::~cDbDict() +{ +} + +//*************************************************************************** +// In +//*************************************************************************** + +int cDbDict::in(const char* file) +{ + FILE* f; + char* line = 0; + size_t size = 0; + char* path; + + asprintf(&path, "%s", file); + + f = fopen(path, "r"); + + while (getline(&line, &size, f) > 0) + { + char* p = strstr(line, "//"); + + if (p) *p = 0; + + allTrim(line); + + if (isEmpty(line)) + continue; + + if (atLine(line) != success) + { + tell(0, "Found unexpected definition '%s', aborting", line); + free(path); + return fail; + } + } + + fclose(f); + free(line); + free(path); + + return success; +} + +//*************************************************************************** +// At Line +//*************************************************************************** + +int cDbDict::atLine(const char* line) +{ + const char* p; + + if (p = strcasestr(line, "Table")) + { + char tableName[100]; + + p += strlen("Table"); + strcpy(tableName, p); + tell(0, "Table: '%s'", tableName); + } + + else if (strchr(line, '{')) + inside = yes; + + else if (strchr(line, '}')) + inside = no; + + else if (inside) + parseField(line); + + return success; +} + +//*************************************************************************** +// Get Token +//*************************************************************************** + +int getToken(const char*& p, char* token, int size) +{ + char* dest = token; + int num = 0; + + while (*p && *p == ' ') + p++; + + while (*p && *p != ' ' && num < size) + { + if (*p == '"') + p++; + else + { + *dest++ = *p++; + num++; + } + } + + *dest = 0; + + return success; +} + +//*************************************************************************** +// Parse Field +//*************************************************************************** + +int cDbDict::parseField(const char* line) +{ + const int sizeTokenMax = 100; + FieldDef f; + char token[sizeTokenMax+TB]; + const char* p = line; + + // tell(0, "Got: '%s'", p); + + for (int i = 0; i < dtCount; i++) + { + if (getToken(p, token, sizeTokenMax) != success) + { + tell(0, "Errot: can't parse line [%s]", line); + return fail; + } + + switch (i) + { + case dtName: f.name = strdup(token); break; + case dtDescription: break; + case dtFormat: f.format = toDictFormat(token); break; + case dtSize: f.size = atoi(token); break; + case dtType: f.type = toType(token); break; + } + + free((char*)f.name); // böser cast ... + + tell(0, "token %d -> '%s'", i, token); + } + + return success; +} diff --git a/lib/dbdict.h b/lib/dbdict.h new file mode 100644 index 0000000..100c626 --- /dev/null +++ b/lib/dbdict.h @@ -0,0 +1,52 @@ +/* + * dbdict.h + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef __DBDICT_H +#define __DBDICT_H + +#include "db.h" + +//*************************************************************************** +// cDbDict +//*************************************************************************** + +class cDbDict : public cDbService +{ + + public: + + // declarations + + enum DictToken + { + dtName, + dtDescription, + dtFormat, + dtSize, + dtType, + + dtCount + }; + + cDbDict(); + virtual ~cDbDict(); + + int in(const char* file); + + protected: + + int atLine(const char* line); + int parseField(const char* line); + + // data + + int inside; + static FieldDef fields[]; + +}; + +#endif // __DBDICT_H diff --git a/lib/demo.c b/lib/demo.c new file mode 100644 index 0000000..ae97cca --- /dev/null +++ b/lib/demo.c @@ -0,0 +1,279 @@ + + +#include "config.h" +#include "common.h" + +#include "db.h" +#include "tabledef.h" + +cDbConnection* connection = 0; + +//*************************************************************************** +// Init Connection +//*************************************************************************** + +void initConnection() +{ + cDbConnection::init(); + + cDbConnection::setEncoding("utf8"); + cDbConnection::setHost("localhost"); + + cDbConnection::setPort(3306); + cDbConnection::setName("epg2vdr"); + cDbConnection::setUser("epg2vdr"); + cDbConnection::setPass("epg"); + cDbTable::setConfPath("/etc/epgd/"); + + connection = new cDbConnection(); +} + +void exitConnection() +{ + cDbConnection::exit(); + + if (connection) + delete connection; +} + +//*************************************************************************** +// +//*************************************************************************** + +int demoStatement() +{ + int status = success; + + cTableEvents* eventsDb = new cTableEvents(connection); + + tell(0, "------------------- attach table ---------------"); + + // open table (attach) + + if (eventsDb->open() != success) + return fail; + + tell(0, "---------------- prepare select statement -------------"); + + // vorbereiten (prepare) eines statement, am besten einmal bei programmstart! + // ---------- + // select eventid, compshorttext, episodepart, episodelang + // from events + // where eventid > ? + + cDbStatement* selectByCompTitle = new cDbStatement(eventsDb); + + status += selectByCompTitle->build("select "); + status += selectByCompTitle->bind(cTableEvents::fiEventId, cDBS::bndOut); + status += selectByCompTitle->bind(cTableEvents::fiChannelId, cDBS::bndOut, ", "); + status += selectByCompTitle->bind(cTableEvents::fiTitle, cDBS::bndOut, ", "); + status += selectByCompTitle->build(" from %s where ", eventsDb->TableName()); + status += selectByCompTitle->bindCmp(0, cTableEvents::fiEventId, 0, ">"); + + status += selectByCompTitle->prepare(); // prepare statement + + if (status != success) + { + // prepare sollte oracle fehler ausgegeben haben! + + delete eventsDb; + delete selectByCompTitle; + + return fail; + } + + tell(0, "------------------ prepare done ----------------------"); + + tell(0, "------------------ create some rows ----------------------"); + + eventsDb->clear(); // alle values löschen + + for (int i = 0; i < 10; i++) + { + char* title; + asprintf(&title, "title %d", i); + + eventsDb->setValue(cTableEvents::fiEventId, 800 + i * 100); + eventsDb->setValue(cTableEvents::fiChannelId, "xxx-yyyy-zzz"); + eventsDb->setValue(cTableEvents::fiTitle, title); + + eventsDb->store(); // store -> select mit anschl. update oder insert je nachdem ob dier PKey bereits vorhanden ist + // eventsDb->insert(); // sofern man schon weiß das es ein insert ist + // eventsDb->update(); // sofern man schon weiß das der Datensatz vorhanden ist + + free(title); + } + + tell(0, "------------------ done ----------------------"); + + tell(0, "-------- select all where eventid > 1000 -------------"); + + eventsDb->clear(); // alle values löschen + eventsDb->setValue(cTableEvents::fiEventId, 1000); + + for (int f = selectByCompTitle->find(); f; f = selectByCompTitle->fetch()) + { + tell(0, "id: %ld", eventsDb->getIntValue(cTableEvents::fiEventId)); + tell(0, "channel: %s", eventsDb->getStrValue(cTableEvents::fiChannelId)); + tell(0, "titel: %s", eventsDb->getStrValue(cTableEvents::fiTitle)); + } + + // freigeben der Ergebnissmenge !! + + selectByCompTitle->freeResult(); + + // folgendes am programmende + + delete eventsDb; // implizietes close (detach) + delete selectByCompTitle; // statement freigeben (auch gegen die DB) + + return success; +} + +//*************************************************************************** +// Join +//*************************************************************************** + +int joinDemo() +{ + int status = success; + + // grundsätzlich genügt hier auch eine Tabelle, für die anderen sind cDbValue Instanzen außreichend + // so ist es etwas einfacher die cDbValues zu initialisieren. + // Ich habe statische "virtual FieldDef* getFieldDef(int f)" Methode in der Tabellenklassen geplant + // um ohne Instanz der cTable ein Feld einfach initialisieren zu können + + cTableEvents* eventsDb = new cTableEvents(connection); + cTableImageRefs* imageRefDb = new cTableImageRefs(connection); + cTableImages* imageDb = new cTableImages(connection); + + tell(0, "------------------- attach table ---------------"); + + // open table (attach) + + if (eventsDb->open() != success) + return fail; + + if (imageDb->open() != success) + return fail; + + if (imageRefDb->open() != success) + return fail; + + tell(0, "---------------- prepare select statement -------------"); + + // all images + + cDbStatement* selectAllImages = new cDbStatement(imageRefDb); + + // prepare fields + + cDbValue imageUpdSp; + cDbValue imageSize; + cDbValue masterId; + + cDBS::FieldDef imageSizeDef = { "image", cDBS::ffUInt, 0, 999, cDBS::ftData }; // eine Art ein Feld zu erzeugen + imageSize.setField(&imageSizeDef); // eine andere Art ein Feld zu erzeugen ... + imageUpdSp.setField(imageDb->getField(cTableImages::fiUpdSp)); + masterId.setField(eventsDb->getField(cTableEvents::fiMasterId)); + + // select e.masterid, r.imagename, r.eventid, r.lfn, length(i.image) + // from imagerefs r, images i, events e + // where i.imagename = r.imagename + // and e.eventid = r.eventid + // and (i.updsp > ? or r.updsp > ?) + + selectAllImages->build("select "); + selectAllImages->setBindPrefix("e."); + selectAllImages->bind(&masterId, cDBS::bndOut); + selectAllImages->setBindPrefix("r."); + selectAllImages->bind(cTableImageRefs::fiImgName, cDBS::bndOut, ", "); + selectAllImages->bind(cTableImageRefs::fiEventId, cDBS::bndOut, ", "); + selectAllImages->bind(cTableImageRefs::fiLfn, cDBS::bndOut, ", "); + selectAllImages->setBindPrefix("i."); + selectAllImages->build(", length("); + selectAllImages->bind(&imageSize, cDBS::bndOut); + selectAllImages->build(")"); + selectAllImages->clrBindPrefix(); + selectAllImages->build(" from %s r, %s i, %s e where ", + imageRefDb->TableName(), imageDb->TableName(), eventsDb->TableName()); + selectAllImages->build("e.%s = r.%s and i.%s = r.%s and (", + eventsDb->getField(cTableEvents::fiEventId)->name, + imageRefDb->getField(cTableImageRefs::fiEventId)->name, + imageDb->getField(cTableImages::fiImgName)->name, + imageRefDb->getField(cTableImageRefs::fiImgName)->name); + selectAllImages->bindCmp("i", &imageUpdSp, ">"); + selectAllImages->build(" or "); + selectAllImages->bindCmp("r", cTableImageRefs::fiUpdSp, 0, ">"); + selectAllImages->build(")"); + + status += selectAllImages->prepare(); + + if (status != success) + { + // prepare sollte oracle fehler ausgegeben haben! + + delete eventsDb; + delete imageDb; + delete imageRefDb; + delete selectAllImages; + + return fail; + } + + tell(0, "------------------ prepare done ----------------------"); + + tell(0, "------------------ select ----------------------"); + + time_t since = time(0) - 60 * 60; + imageRefDb->clear(); + imageRefDb->setValue(cTableImageRefs::fiUpdSp, since); + imageUpdSp.setValue(since); + + for (int res = selectAllImages->find(); res; res = selectAllImages->fetch()) + { + // so kommst du an die Werte der unterschgiedlichen Tabellen + + // int eventid = masterId.getIntValue(); + // const char* imageName = imageRefDb->getStrValue(cTableImageRefs::fiImgName); + // int lfn = imageRefDb->getIntValue(cTableImageRefs::fiLfn); + // int size = imageSize.getIntValue(); + + + } + + // freigeben der Ergebnissmenge !! + + selectAllImages->freeResult(); + + // folgendes am programmende + + delete eventsDb; // implizietes close (detach) + delete imageDb; + delete imageRefDb; + delete selectAllImages; // statement freigeben (auch gegen die DB) + + return success; +} + + +//*************************************************************************** +// Main +//*************************************************************************** + +int main() +{ + EPG2VDRConfig.logstdout = yes; + EPG2VDRConfig.loglevel = 2; + + initConnection(); + + // demoStatement(); + // joinDemo(); + + tell(0, "uuid: '%s'", getUniqueId()); + + exitConnection(); + + return 0; +} diff --git a/lib/imgtools.c b/lib/imgtools.c new file mode 100644 index 0000000..168bac9 --- /dev/null +++ b/lib/imgtools.c @@ -0,0 +1,190 @@ +/* + * imgtools.c + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include "imgtools.h" + +//*************************************************************************** +// Image converting stuff +//*************************************************************************** + +int fromJpeg(Imlib_Image& image, unsigned char* buffer, int size) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + int w, h; + DATA8 *ptr, *line[16], *data; + DATA32 *ptr2, *dest; + int x, y; + + cinfo.err = jpeg_std_error(&jerr); + + jpeg_create_decompress(&cinfo); + jpeg_mem_src(&cinfo, buffer, size); + jpeg_read_header(&cinfo, TRUE); + cinfo.do_fancy_upsampling = FALSE; + cinfo.do_block_smoothing = FALSE; + + jpeg_start_decompress(&cinfo); + + w = cinfo.output_width; + h = cinfo.output_height; + + image = imlib_create_image(w, h); + imlib_context_set_image(image); + + dest = ptr2 = imlib_image_get_data(); + data = (DATA8*)malloc(w * 16 * cinfo.output_components); + + for (int i = 0; i < cinfo.rec_outbuf_height; i++) + line[i] = data + (i * w * cinfo.output_components); + + for (int l = 0; l < h; l += cinfo.rec_outbuf_height) + { + jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); + int scans = cinfo.rec_outbuf_height; + + if (h - l < scans) + scans = h - l; + + ptr = data; + + for (y = 0; y < scans; y++) + { + for (x = 0; x < w; x++) + { + *ptr2 = (0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) << 8) | (ptr[2]); + ptr += cinfo.output_components; + ptr2++; + } + } + } + + free(data); + + imlib_image_put_back_data(dest); + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + return success; +} + +long toJpeg(Imlib_Image image, MemoryStruct* data, int quality) +{ + struct jpeg_compress_struct cinfo = { 0 }; + struct jpeg_error_mgr jerr; + DATA32* ptr; + DATA8* buf; + long unsigned int size = data->size; + + imlib_context_set_image(image); + + data->clear(); + + cinfo.err = jpeg_std_error(&jerr); + + jpeg_create_compress(&cinfo); + jpeg_mem_dest(&cinfo, (unsigned char**)(&data->memory), &size); + + cinfo.image_width = imlib_image_get_width(); + cinfo.image_height = imlib_image_get_height(); + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + + // get data pointer + + if (!(ptr = imlib_image_get_data_for_reading_only())) + return 0; + + // allocate a small buffer to convert image data */ + + buf = (DATA8*)malloc(imlib_image_get_width() * 3 * sizeof(DATA8)); + + while (cinfo.next_scanline < cinfo.image_height) + { + // convert scanline from ARGB to RGB packed + + for (int j = 0, i = 0; i < imlib_image_get_width(); i++) + { + buf[j++] = ((*ptr) >> 16) & 0xff; + buf[j++] = ((*ptr) >> 8) & 0xff; + buf[j++] = ((*ptr)) & 0xff; + + ptr++; + } + + // write scanline + + jpeg_write_scanlines(&cinfo, (JSAMPROW*)(&buf), 1); + } + + free(buf); + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + return data->size; +} + +int scaleImageToJpegBuffer(Imlib_Image image, MemoryStruct* data, int width, int height) +{ + if (width && height) + { + Imlib_Image scaledImage; + + imlib_context_set_image(image); + + int imgWidth = imlib_image_get_width(); + int imgHeight = imlib_image_get_height(); + double ratio = (double)imgWidth / (double)imgHeight; + + if ((double)width/(double)imgWidth < (double)height/(double)imgHeight) + height = (int)((double)width / ratio); + else + width = (int)((double)height * ratio); + + scaledImage = imlib_create_image(width, height); + imlib_context_set_image(scaledImage); + + imlib_context_set_color(240, 240, 240, 255); + imlib_image_fill_rectangle(0, 0, width, height); + + imlib_blend_image_onto_image(image, 0, 0, 0, + imgWidth, imgHeight, 0, 0, + width, height); + + toJpeg(scaledImage, data, 70); + + imlib_context_set_image(scaledImage); + imlib_free_image(); + + tell(1, "Scaled image to %d/%d, now %d bytes", width, height, (int)data->size); + } + else + { + toJpeg(image, data, 70); + } + + return success; +} + +int scaleJpegBuffer(MemoryStruct* data, int width, int height) +{ + Imlib_Image image; + + fromJpeg(image, (unsigned char*)data->memory, data->size); + + scaleImageToJpegBuffer(image, data, width, height); + + imlib_context_set_image(image); + imlib_free_image(); + + return success; +} diff --git a/lib/imgtools.h b/lib/imgtools.h new file mode 100644 index 0000000..c4f8ab7 --- /dev/null +++ b/lib/imgtools.h @@ -0,0 +1,28 @@ +/* + * imgtools.c + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef __IMGTOOLS_H +#define __IMGTOOLS_H + +#include + +#include +#include + +#include "common.h" + +//*************************************************************************** +// Image Manipulating +//*************************************************************************** + +int fromJpeg(Imlib_Image& image, unsigned char* buffer, int size); +long toJpeg(Imlib_Image image, MemoryStruct* data, int quality); +int scaleImageToJpegBuffer(Imlib_Image image, MemoryStruct* data, int width = 0, int height = 0); +int scaleJpegBuffer(MemoryStruct* data, int width = 0, int height = 0); + +//*************************************************************************** +#endif // __IMGTOOLS_H diff --git a/lib/test.c b/lib/test.c new file mode 100644 index 0000000..01b5c2d --- /dev/null +++ b/lib/test.c @@ -0,0 +1,458 @@ + +#include // uint_64_t +#include +#include + +#include +#include + +#include "config.h" +#include "common.h" +#include "db.h" +#include "tabledef.h" +#include "dbdict.h" + +cDbConnection* connection = 0; + +//*************************************************************************** +// +//*************************************************************************** + +class cTimeMs +{ + private: + + uint64_t begin; + + public: + + cTimeMs(int Ms = 0); + static uint64_t Now(void); + void Set(int Ms = 0); + bool TimedOut(void); + uint64_t Elapsed(void); +}; + +//*************************************************************************** +// Init Connection +//*************************************************************************** + +void initConnection() +{ + cDbConnection::init(); + + cDbConnection::setEncoding("utf8"); + cDbConnection::setHost("localhost"); + cDbConnection::setPort(EPG2VDRConfig.dbPort); + cDbConnection::setName(EPG2VDRConfig.dbName); + cDbConnection::setUser(EPG2VDRConfig.dbUser); + cDbConnection::setPass(EPG2VDRConfig.dbPass); + cDbTable::setConfPath("/etc/epgd/"); + + connection = new cDbConnection(); +} + +void exitConnection() +{ + cDbConnection::exit(); + + if (connection) + delete connection; +} + +//*************************************************************************** +// +//*************************************************************************** + +void chkCompress() +{ + std::string s = "_+*!#?=&%$< Hallo TEIL Hallo Folge "; + + printf("'%s'\n", s.c_str()); + prepareCompressed(s); + printf("'%s'\n", s.c_str()); + + s = "Place Vendôme - Heiße Diamanten"; + printf("'%s'\n", s.c_str()); + prepareCompressed(s); + printf("'%s'\n", s.c_str()); + + s = "Halöö älter"; + printf("'%s'\n", s.c_str()); + prepareCompressed(s); + printf("'%s'\n", s.c_str()); +} + +//*************************************************************************** +// +//*************************************************************************** + +void chkStatement1() +{ + cDbTable* epgDb = new cTableEvents(connection); + + if (epgDb->open() != success) + { + tell(0, "Could not access database '%s:%d' (%s)", + cDbConnection::getHost(), cDbConnection::getPort(), epgDb->TableName()); + + return ; + } + + tell(0, "---------------------------------------------------"); + + // prepare statement to mark wasted DVB events + + cDbValue* endTime = new cDbValue("starttime+duration", cDBS::ffInt, 10); + cDbStatement* updateDelFlg = new cDbStatement(epgDb); + + // update events set delflg = ?, updsp = ? + // where channelid = ? and source = ? + // and starttime+duration > ? + // and starttime < ? + // and (tableid > ? or (tableid = ? and version <> ?)) + + updateDelFlg->build("update %s set ", epgDb->TableName()); + updateDelFlg->bind(cTableEvents::fiDelFlg, cDBS::bndIn | cDBS::bndSet); + updateDelFlg->bind(cTableEvents::fiUpdSp, cDBS::bndIn | cDBS::bndSet, ", "); + updateDelFlg->build(" where "); + updateDelFlg->bind(cTableEvents::fiChannelId, cDBS::bndIn | cDBS::bndSet); + updateDelFlg->bind(cTableEvents::fiSource, cDBS::bndIn | cDBS::bndSet, " and "); + + updateDelFlg->bindCmp(0, endTime, ">", " and "); + + updateDelFlg->bindCmp(0, cTableEvents::fiStartTime, 0, "<" , " and "); + updateDelFlg->bindCmp(0, cTableEvents::fiTableId, 0, ">" , " and ("); + updateDelFlg->bindCmp(0, cTableEvents::fiTableId, 0, "=" , " or ("); + updateDelFlg->bindCmp(0, cTableEvents::fiVersion, 0, "<>" , " and "); + updateDelFlg->build("));"); + + updateDelFlg->prepare(); + + tell(0, "---------------------------------------------------"); +} + +//*************************************************************************** +// +//*************************************************************************** + +void chkStatement2() +{ + cDbTable* imageRefDb = new cTableImageRefs(connection); + cDbTable* imageDb = new cTableImages(connection); + + if (imageRefDb->open() != success) + return ; + + if (imageDb->open() != success) + return ; + + tell(0, "---------------------------------------------------"); + + cDbStatement* selectAllImages = new cDbStatement(imageRefDb); + + cDbValue imageData; + imageData.setField(imageDb->getField(cTableImages::fiImage)); + + // select r.imagename, r.eventid, r.lfn, i.image from imagerefs r, images i + // where r.imagename = i.imagename and i.image is not null; + + selectAllImages->build("select "); + selectAllImages->setBindPrefix("r."); + selectAllImages->bind(cTableImageRefs::fiImgName, cDBS::bndOut); + selectAllImages->bind(cTableImageRefs::fiEventId, cDBS::bndOut, ", "); + selectAllImages->bind(cTableImageRefs::fiLfn, cDBS::bndOut, ", "); + selectAllImages->setBindPrefix("i."); + selectAllImages->bind(&imageData, cDBS::bndOut, ","); + selectAllImages->clrBindPrefix(); + selectAllImages->build(" from %s r, %s i where ", imageRefDb->TableName(), imageDb->TableName()); + selectAllImages->build("r.%s = i.%s and i.%s is not null;", + imageRefDb->getField(cTableImageRefs::fiImgName)->name, + imageDb->getField(cTableImages::fiImgName)->name, + imageDb->getField(cTableImages::fiImage)->name); + + selectAllImages->prepare(); + + + tell(0, "---------------------------------------------------"); + + //delete s; + delete imageRefDb; + delete imageDb; +} + +//*************************************************************************** +// +//*************************************************************************** + +void chkStatement3() +{ + int count = 0; + int lcount = 0; + + cDbTable* epgDb = new cTableEvents(connection); + cDbTable* mapDb = new cTableChannelMap(connection); + + if (epgDb->open() != success) + return ; + + if (mapDb->open() != success) + return ; + + tell(0, "---------------------------------------------------"); + + cDbStatement* s = new cDbStatement(epgDb); + + s->build("select "); + s->setBindPrefix("e."); + s->bind(cTableEvents::fiEventId, cDBS::bndOut); + s->bind(cTableEvents::fiChannelId, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiSource, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiDelFlg, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiFileRef, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiTableId, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiVersion, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiTitle, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiShortText, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiStartTime, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiDuration, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiParentalRating, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiVps, cDBS::bndOut, ", "); + s->bind(cTableEvents::fiDescription, cDBS::bndOut, ", "); + s->clrBindPrefix(); + s->build(" from eventsview e, %s m where ", mapDb->TableName()); + s->build("e.%s = m.%s and e.%s = m.%s and ", + epgDb->getField(cTableEvents::fiChannelId)->name, + mapDb->getField(cTableChannelMap::fiChannelName)->name, + epgDb->getField(cTableEvents::fiSource)->name, + mapDb->getField(cTableChannelMap::fiSource)->name); + s->bindCmp("e", cTableEvents::fiUpdSp, 0, ">"); + s->build(" order by m.%s;", mapDb->getField(cTableChannelMap::fiChannelName)->name); + + s->prepare(); + + epgDb->clear(); + epgDb->setValue(cTableEvents::fiUpdSp, (double)0); + epgDb->setValue(cTableEvents::fiSource, "vdr"); // used by selectUpdEventsByChannel + epgDb->setValue(cTableEvents::fiChannelId, "xxxxxxxxxxxxx"); // used by selectUpdEventsByChannel + + int channels = 0; + char chan[100]; *chan = 0; + + tell(0, "---------------------------------------------------"); + + for (int found = s->find(); found; found = s->fetch()) + { + if (!*chan || strcmp(chan, epgDb->getStrValue(cTableEvents::fiChannelId)) != 0) + { + if (*chan) + tell(0, "processed %-20s with %d events", chan, count - lcount); + + lcount = count; + channels++; + strcpy(chan, epgDb->getStrValue(cTableEvents::fiChannelId)); + + tell(0, "processing %-20s now", chan); + } + + tell(0, "-> '%s' - (%ld)", epgDb->getStrValue(cTableEvents::fiChannelId), + epgDb->getIntValue(cTableEvents::fiEventId)); + + + count++; + } + + s->freeResult(); + + tell(0, "---------------------------------------------------"); + tell(0, "updated %d channels and %d events", channels, count); + tell(0, "---------------------------------------------------"); + + delete s; + delete epgDb; + delete mapDb; +} + +// --- cTimeMs --------------------------------------------------------------- + +cTimeMs::cTimeMs(int Ms) +{ + if (Ms >= 0) + Set(Ms); + else + begin = 0; +} + +uint64_t cTimeMs::Now(void) +{ +#define MIN_RESOLUTION 5 // ms + static bool initialized = false; + static bool monotonic = false; + struct timespec tp; + if (!initialized) { + // check if monotonic timer is available and provides enough accurate resolution: + if (clock_getres(CLOCK_MONOTONIC, &tp) == 0) { + // long Resolution = tp.tv_nsec; + // require a minimum resolution: + if (tp.tv_sec == 0 && tp.tv_nsec <= MIN_RESOLUTION * 1000000) { + if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) { + monotonic = true; + } + else + tell(0, "cTimeMs: clock_gettime(CLOCK_MONOTONIC) failed"); + } + else + tell(0, "cTimeMs: not using monotonic clock - resolution is too bad (%ld s %ld ns)", tp.tv_sec, tp.tv_nsec); + } + else + tell(0, "cTimeMs: clock_getres(CLOCK_MONOTONIC) failed"); + initialized = true; + } + if (monotonic) { + if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) + return (uint64_t(tp.tv_sec)) * 1000 + tp.tv_nsec / 1000000; + tell(0, "cTimeMs: clock_gettime(CLOCK_MONOTONIC) failed"); + monotonic = false; + // fall back to gettimeofday() + } + struct timeval t; + if (gettimeofday(&t, NULL) == 0) + return (uint64_t(t.tv_sec)) * 1000 + t.tv_usec / 1000; + return 0; +} + +void cTimeMs::Set(int Ms) +{ + begin = Now() + Ms; +} + +bool cTimeMs::TimedOut(void) +{ + return Now() >= begin; +} + +uint64_t cTimeMs::Elapsed(void) +{ + return Now() - begin; +} + +//*************************************************************************** +// +//*************************************************************************** + +void chkStatement4() +{ + cDbTable* eventDb = new cTableEvents(connection); + if (eventDb->open() != success) return; + + cDbTable* imageRefDb = new cTableImageRefs(connection); + if (imageRefDb->open() != success) return; + + cDbTable* imageDb = new cTableImages(connection); + if (imageDb->open() != success) return; + + // select e.masterid, r.imagename, r.eventid, r.lfn, i.image + // from imagerefs r, images i, events e + // where r.imagename = i.imagename + // and e.eventid = r.eventid, + // and i.image is not null + // and (i.updsp > ? or r.updsp > ?); + + cDBS::FieldDef masterFld = { "masterid", cDBS::ffUInt, 0, 999, cDBS::ftData }; + cDbValue masterId; + cDbValue imageData; + cDbValue imageUpdSp; + + masterId.setField(&masterFld); + imageData.setField(imageDb->getField(cTableImages::fiImage)); + imageUpdSp.setField(imageDb->getField(cTableImages::fiUpdSp)); + + cDbStatement* selectAllImages = new cDbStatement(imageRefDb); + + selectAllImages->build("select "); + selectAllImages->setBindPrefix("e."); + selectAllImages->bind(&masterId, cDBS::bndOut); + selectAllImages->setBindPrefix("r."); + selectAllImages->bind(cTableImageRefs::fiImgName, cDBS::bndOut, ", "); + selectAllImages->bind(cTableImageRefs::fiEventId, cDBS::bndOut, ", "); + selectAllImages->bind(cTableImageRefs::fiLfn, cDBS::bndOut, ", "); + selectAllImages->setBindPrefix("i."); + selectAllImages->bind(&imageData, cDBS::bndOut, ", "); + selectAllImages->clrBindPrefix(); + selectAllImages->build(" from %s r, %s i, %s e where ", + imageRefDb->TableName(), imageDb->TableName(), eventDb->TableName()); + selectAllImages->build("e.%s = r.%s and i.%s = r.%s and i.%s is not null and (", + eventDb->getField(cTableEvents::fiEventId)->name, + imageRefDb->getField(cTableImageRefs::fiEventId)->name, + imageDb->getField(cTableImageRefs::fiImgName)->name, + imageRefDb->getField(cTableImageRefs::fiImgName)->name, + imageDb->getField(cTableImages::fiImage)->name); + selectAllImages->bindCmp("i", &imageUpdSp, ">"); + selectAllImages->build(" or "); + selectAllImages->bindCmp("r", cTableImageRefs::fiUpdSp, 0, ">"); + selectAllImages->build(");"); + + selectAllImages->prepare(); + + imageRefDb->clear(); + imageRefDb->setValue(cTableImageRefs::fiUpdSp, 1377733333L); + imageUpdSp.setValue(1377733333L); + + int count = 0; + for (int res = selectAllImages->find(); res; res = selectAllImages->fetch()) + { + count ++; + } + tell(0,"%d", count); +} + +//*************************************************************************** +// Main +//*************************************************************************** + +int main() +{ + EPG2VDRConfig.logstdout = yes; + EPG2VDRConfig.loglevel = 2; + + setlocale(LC_CTYPE, ""); + char* lang = setlocale(LC_CTYPE, 0); + + if (lang) + { + tell(0, "Set locale to '%s'", lang); + + if ((strcasestr(lang, "UTF-8") != 0) || (strcasestr(lang, "UTF8") != 0)) + tell(0, "detected UTF-8"); + else + tell(0, "no UTF-8"); + } + else + { + tell(0, "Reseting locale for LC_CTYPE failed."); + } + + + cDbDict* dict = new cDbDict(); + + dict->in("../epg.dat"); + + delete dict; + + return 0; + + initConnection(); + + chkCompress(); + + tell(0, "duration was: '%s'", ms2Dur(2340).c_str()); + + // chkStatement1(); + // chkStatement2(); + // chkStatement3(); + // chkStatement4(); + + exitConnection(); + + return 0; +}