📄 dvdbookmarks.c
字号:
/* Ogle - A video player * Copyright (C) 2003 Bj鰎n Englund * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <string.h>#include <errno.h>#include <libxml/xmlmemory.h>#include <libxml/parser.h>#include "dvdbookmarks.h"#define OGLE_RC_DIR ".ogle"#define OGLE_BOOKMARK_DIR "bookmarks"struct DVDBookmark_s { char *filename; xmlDocPtr doc;};static xmlDocPtr new_bookmark_doc(const char *dvdid_str){ xmlDocPtr doc; xmlNodePtr node; if((doc = xmlNewDoc("1.0")) == NULL) { return NULL; } if((node = xmlNewDocNode(doc, NULL, "ogle_bookmarks", NULL)) == NULL) { xmlFreeDoc(doc); return NULL; } if(xmlDocSetRootElement(doc, node)) { xmlFreeNode(node); xmlFreeDoc(doc); return NULL; } xmlNewProp(node, "dvddiscid", dvdid_str); return doc;}static xmlNodePtr get_bookmark(xmlDocPtr doc, xmlNodePtr cur, int nr){ int n = 0; cur = cur->xmlChildrenNode; while(cur != NULL) { if((!xmlStrcmp(cur->name, (const xmlChar *)"bookmark"))) { if(n++ == nr) { return cur; } } cur = cur->next; } return NULL; }/** * Open and and read the file that contains the bookmarks for a dvd. * @param dvdid This is the dvddiscid and will be used to locate the correct * file to read from. * @param dir This should be NULL to use the standard bookmark directory. * If the bookmarks should be read from another directory, name it here. * The default directory used when none is specified is * $HOME/.ogle/bookmarks * * @param create Set this to 1 if the bookmark file should be create in case * it doesn't exist. 0 if it shouldn't be created. * Setting it to 0 can be used if one wants to find out if there are * any bookmarks for a dvd. If there are none, NULL will be returned. * * @return If successful a handle is returned else NULL and errno is set if * the failure was file related. * */DVDBookmark_t *DVDBookmarkOpen(const unsigned char dvdid[16], const char *dir, int create){ DVDBookmark_t *bm; char *home = NULL; xmlDocPtr doc = NULL; char *filename = NULL; int fd; char dvdid_str[33]; int n; /* convert dvdid to text format */ for(n = 0; n < 16; n++) { sprintf(&dvdid_str[n*2], "%02x", dvdid[n]); } if(dir == NULL) { home = getenv("HOME"); if(home == NULL) { return NULL; } else { struct stat buf; filename = malloc(strlen(home) + 1 + strlen(OGLE_RC_DIR) + 1 + strlen(OGLE_BOOKMARK_DIR) + 1 + strlen(dvdid_str) + 1); if(filename == NULL) { return NULL; } strcpy(filename, home); strcat(filename, "/"); strcat(filename, OGLE_RC_DIR); if(stat(filename, &buf) == -1) { if(errno == ENOENT) { mkdir(filename, 0755); } } strcat(filename, "/"); strcat(filename, OGLE_BOOKMARK_DIR); if(stat(filename, &buf) == -1) { if(errno == ENOENT) { mkdir(filename, 0755); } } strcat(filename, "/"); strcat(filename, dvdid_str); } } else { filename = malloc( strlen(dir) + 1 + strlen(dvdid_str) + 1 ); if(filename == NULL) { return NULL; } strcpy(filename, dir); strcat(filename, "/"); strcat(filename, dvdid_str); } xmlKeepBlanksDefault(0); if((fd = open(filename, O_RDONLY)) != -1) { close(fd); } else { if(!create || (errno != ENOENT)) { free(filename); return NULL; } else { if((fd = open(filename, O_RDONLY | O_CREAT, 0644)) != -1) { close(fd); if((doc = new_bookmark_doc(dvdid_str)) == NULL) { free(filename); return NULL; } } else { free(filename); return NULL; } } } if(doc == NULL) { xmlNodePtr cur; xmlChar *prop; if((doc = xmlParseFile(filename)) == NULL) { free(filename); return NULL; } if((cur = xmlDocGetRootElement(doc)) == NULL) { xmlFree(doc); free(filename); return NULL; } if((prop = xmlGetProp(cur, "dvddiscid")) == NULL) { xmlFree(doc); free(filename); return NULL; } if(xmlStrcmp(prop, (const xmlChar *)dvdid_str)) { xmlFree(prop); xmlFree(doc); free(filename); return NULL; } xmlFree(prop); } if((bm = malloc(sizeof(DVDBookmark_t))) == NULL) { return NULL; } bm->filename = filename; bm->doc = doc; return bm;}/** * Retrieve the number of bookmarks for the current disc * * @param bm Handle from DVDBookmarkOpen. * * @return Returns -1 on failure, otherwise the number of bookmarks. */int DVDBookmarkGetNr(DVDBookmark_t *bm){ xmlNodePtr cur; int n = 0; if(!bm || !(bm->doc)) { return -1; } if((cur = xmlDocGetRootElement(bm->doc)) == NULL) { return -1; } cur = cur->xmlChildrenNode; while(cur != NULL) { if((!xmlStrcmp(cur->name, (const xmlChar *)"bookmark"))) { n++; } cur = cur->next; } return n; }/** * Retrieve a bookmark for the current disc. * * @param bm Handle from DVDBookmarkOpen. * @param nr The specific bookmark for this disc. * There can be several bookmarks for one disc. * Bookmarks are numbered from 0 and up. * To read all bookmarks for this disc, call this function * with numbers from 0 and up until -1 is returned. * @param navstate This is where a pointer to the navstate data * will be returned. You need to free() this when you are done with it. * If this is NULL the navstate won't be returned. * @param usercomment This is where a pointer to the usercomment data * will be returned. You need to free() this when you are done with it. * If this is NULL the usercommment won't be returned. * @param appname If you supply the name of your application here, you will * get application specific data back in appinfo if there is a matching * entry for your appname. * If no data is returned for a char ** it will be set to NULL, unless * the call fails in which case it will be undefined. * @param appinfo This is where a pointer to the appinfo data * will be returned. You need to free() this when you are done with it. * If this is NULL the appinfo won't be returned. */int DVDBookmarkGet(DVDBookmark_t *bm, int nr, char **navstate, char **usercomment, const char *appname, char **appinfo){ xmlNodePtr cur; xmlChar *data; int navstate_read = 0; int usercomment_read = 0; int appinfo_read = 0; if(!bm || !(bm->doc) || (nr < 0)) { return -1; } if((cur = xmlDocGetRootElement(bm->doc)) == NULL) { return -1; } cur = get_bookmark(bm->doc, cur, nr); if(cur == NULL) { return -1; } if(navstate) { *navstate = NULL; } if(usercomment) { *usercomment = NULL; } if(appinfo) { *appinfo = NULL; } cur = cur->xmlChildrenNode; while(cur != NULL) { if((!xmlStrcmp(cur->name, (const xmlChar *)"navstate"))) { xmlBufferPtr xmlbuf; if(navstate != NULL && !navstate_read) { if((xmlbuf = xmlBufferCreate()) == NULL) { return -1; } xmlNodeDump(xmlbuf, bm->doc, cur, 0, 0); *navstate = strdup(xmlBufferContent(xmlbuf)); xmlBufferFree(xmlbuf); navstate_read = 1; } } else if((!xmlStrcmp(cur->name, (const xmlChar *)"usercomment"))) { if(usercomment != NULL && !usercomment_read) { data = xmlNodeListGetString(bm->doc, cur->xmlChildrenNode, 1); *usercomment = strdup(data); xmlFree(data); usercomment_read = 1; } } else if((!xmlStrcmp(cur->name, (const xmlChar *)"appinfo"))) { if((appname != NULL) && (appinfo != NULL)) { xmlChar *prop; if((prop = xmlGetProp(cur, "appname")) != NULL) { if(!xmlStrcmp(prop, (const xmlChar *)appname) && !appinfo_read) { data = xmlNodeListGetString(bm->doc, cur->xmlChildrenNode, 1); *appinfo = strdup(data); xmlFree(data); appinfo_read = 1; } xmlFree(prop); } } } cur = cur->next; } return 0;} /** * Add a bookmark for the current disc. * * @param bm Handle from DVDBookmarkOpen. * There can be several bookmarks for one disc. * The bookmark will be added at the end of the list of bookmarks * for this disc. * @param navstate The navstate data for the bookmark. * @param usercomment The usercomment data for the bookmark. * @param appname If you supply the name of your application here, you will * be able to supply application specific data in appinfo. * @param appinfo The appinfo data * * All char * should point to a nullterminated string. * The only char * that must be set is navstate, the rest can be NULL. * * @return 0 on success, -1 on failure. */int DVDBookmarkAdd(DVDBookmark_t *bm, const char *navstate, const char *usercomment, const char *appname, const char *appinfo){ xmlNodePtr cur; if(!bm || !navstate) { return -1; } if((cur = xmlDocGetRootElement(bm->doc)) == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -