/*
* Nextview GUI: Output of programme data in XML
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License Version 2 as
* published by the Free Software Foundation. You find a copy of this
* license in the file COPYRIGHT in the root directory of this release.
*
* 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.
*
*
* Description:
*
* This module implements methods to export PI in XML.
*
* Author: Tom Zoerner
*
* $Id: dumpxml.c,v 1.12.1.3 2005/04/02 16:56:46 tom Exp $
*/
#define DEBUG_SWITCH DEBUG_SWITCH_EPGUI
#define DPRINTF_OFF
#include
#include
#include
#include
#include
#include
#include
#include "epgctl/mytypes.h"
#include "epgctl/debug.h"
#include "epgctl/epgversion.h"
#include "epgdb/epgblock.h"
#include "epgdb/epgdbfil.h"
#include "epgdb/epgdbif.h"
#include "epgdb/epgtscqueue.h"
#include "epgdb/epgdbmerge.h"
#include "epgui/epgmain.h"
#include "epgui/pdc_themes.h"
#include "epgui/pifilter.h"
#include "epgui/pidescr.h"
#include "epgui/dumphtml.h"
#include "epgui/dumptext.h"
#include "epgui/dumpxml.h"
#include "epgtcl/dlg_dump.h"
#define IS_XML_DTD5(X) ((X) != EPGTCL_XMLTV_DTD_6)
//
typedef struct
{
FILE * fp;
int xmlDtdVersion;
} DUMP_XML_CB_INFO;
// ----------------------------------------------------------------------------
// Print Short- and Long-Info texts for XMLTV
//
static void EpgDumpXml_AppendInfoTextCb( void *vp, const char * pDesc, bool addSeparator )
{
DUMP_XML_CB_INFO * pCbInfo = vp;
FILE * fp;
const char * pNewline;
if ((pCbInfo != NULL) && (pCbInfo->fp != NULL) && (pDesc != NULL))
{
fp = pCbInfo->fp;
if (addSeparator)
{
if ( IS_XML_DTD5(pCbInfo->xmlDtdVersion) )
fprintf(fp, "\n\n");
else
fprintf(fp, "
\n\t
");
}
// replace newline characters with paragraph tags
while ( (pNewline = strchr(pDesc, '\n')) != NULL )
{
// print text up to (and excluding) the newline
EpgDumpHtml_WriteString(fp, pDesc, pNewline - pDesc);
if ( IS_XML_DTD5(pCbInfo->xmlDtdVersion) )
fprintf(fp, "\n\n");
else
fprintf(fp, "
\n
");
// skip to text following the newline
pDesc = pNewline + 1;
}
// write the segment behind the last newline
EpgDumpHtml_WriteString(fp, pDesc, -1);
}
}
// ----------------------------------------------------------------------------
// Helper func: read integer from global Tcl var
// - DTD version constants are defined at Tcl script level
//
static int EpgDumpXml_QueryXmlDtdVersion( Tcl_Interp *interp )
{
Tcl_Obj * pVarObj;
int value;
pVarObj = Tcl_GetVar2Ex(interp, "dumpxml_format", NULL, TCL_GLOBAL_ONLY);
if ( (pVarObj == NULL) ||
(Tcl_GetIntFromObj(interp, pVarObj, &value) != TCL_OK) )
{
debug1("EpgDumpXml-QueryLocaltimeSetting: failed to parse Tcl var 'dumpxml_format': %s", ((pVarObj != NULL) ? Tcl_GetString(pVarObj) : "*undef*"));
value = EPGTCL_XMLTV_DTD_5_GMT;
}
return value;
}
// ----------------------------------------------------------------------------
// Write timestamp into string
// - definition of date/time format in XMLTV DTD 0.5:
// "All dates and times in this DTD follow the same format, loosely based
// on ISO 8601. They can be 'YYYYMMDDhhmmss' or some initial
// substring, for example if you only know the year and month you can
// have 'YYYYMM'. You can also append a timezone to the end; if no
// explicit timezone is given, UTC is assumed. Examples:
// '200007281733 BST', '200209', '19880523083000 +0300'. (BST == +0100.)"
// - unfortunately the authors of some XMLTV parsers have overlooked this
// paragraph, so we need as a work-around the possibility to export times
// in the local time zone
//
static void EpgDumpXml_PrintTimestamp( char * pBuf, uint maxLen,
time_t then, int xmlDtdVersion )
{
size_t len;
sint lto;
char ltoSign;
if (xmlDtdVersion == EPGTCL_XMLTV_DTD_5_LTZ)
{
// print times in localtime
lto = EpgLtoGet(then) / 60;
if (lto < 0)
{
lto = 0 - lto;
ltoSign = '-';
}
else
ltoSign = '+';
len = strftime(pBuf, maxLen, "%Y%m%d%H%M%S", localtime(&then));
if (len + 1 + 6 <= maxLen)
{
sprintf(pBuf + len, " %c%02d%02d", ltoSign, lto/60, lto%60);
}
}
else if (xmlDtdVersion == EPGTCL_XMLTV_DTD_5_GMT)
{
strftime(pBuf, maxLen, "%Y%m%d%H%M%S +0000", gmtime(&then));
}
else if (xmlDtdVersion == EPGTCL_XMLTV_DTD_6)
{
strftime(pBuf, maxLen, "%Y-%m-%dT%H:%M:%SZ", gmtime(&then));
}
else
{
debug1("EpgDumpXml-PrintTimestamp: invalid XMLTV DTD version %d", xmlDtdVersion);
if (maxLen >= 1)
*pBuf = 0;
}
}
// ----------------------------------------------------------------------------
// Write XML file header
//
static void EpgDumpXml_WriteHeader( EPGDB_CONTEXT * pDbContext,
const AI_BLOCK * pAiBlock, const OI_BLOCK * pOiBlock,
FILE * fp, int xmlDtdVersion )
{
uchar start_str[50];
time_t lastAiUpdate;
// content provider string
comm[0] = 0;
if (EpgDbContextIsMerged(pDbContext) == FALSE)
{
EpgDumpHtml_RemoveQuotes(AI_GET_NETWOP_NAME(pAiBlock, pAiBlock->thisNetwop), comm, TCL_COMM_BUF_SIZE - 2);
strcat(comm, "/");
}
EpgDumpHtml_RemoveQuotes(AI_GET_SERVICENAME(pAiBlock), comm + strlen(comm), TCL_COMM_BUF_SIZE - strlen(comm));
// date when data was captured
lastAiUpdate = EpgDbGetAiUpdateTime(pDbContext);
EpgDumpXml_PrintTimestamp(start_str, sizeof(start_str), lastAiUpdate, xmlDtdVersion);
if ( IS_XML_DTD5(xmlDtdVersion) )
{
fprintf(fp, "\n"
"\n"
"\n", start_str);
}
else // XML DTD 6
{
fprintf(fp, "\n"
"\n"
"\n"
"\n"
"\t\n"
"\t\t