00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00012
00013 #include <QCoreApplication>
00014 #include <QFile>
00015 #include <QFileInfo>
00016
00017 #include "serverSideScripting.h"
00018 #include "mythlogging.h"
00019
00020 QScriptValue formatStr(QScriptContext *context, QScriptEngine *interpreter);
00021
00023
00025
00026 QScriptValue formatStr(QScriptContext *context, QScriptEngine *interpreter)
00027 {
00028 unsigned int count = context->argumentCount();
00029
00030 if (count == 0)
00031 return QScriptValue(interpreter, QString());
00032
00033 if (count == 1)
00034 return QScriptValue(interpreter, context->argument(0).toString());
00035
00036 QString result = context->argument(0).toString();
00037 for (unsigned int i = 1; i < count; i++)
00038 result.replace(QString("%%1").arg(i), context->argument(i).toString());
00039
00040 return QScriptValue(interpreter, result);
00041 }
00042
00044
00046
00047 ServerSideScripting::ServerSideScripting()
00048 {
00049
00050
00051
00052
00053 m_engine.installTranslatorFunctions();
00054
00055
00056
00057
00058
00059 QScriptValue qsFormatStr = m_engine.newFunction(formatStr);
00060 m_engine.globalObject().setProperty("formatStr", qsFormatStr);
00061
00062
00063
00064
00065
00066
00067
00068
00069 }
00070
00072
00074
00075 ServerSideScripting::~ServerSideScripting()
00076 {
00077 Lock();
00078
00079 QMap<QString, ScriptInfo*>::iterator it = m_mapScripts.begin();
00080
00081 for (; it != m_mapScripts.end(); ++it)
00082 {
00083 if (*it)
00084 delete (*it);
00085 }
00086
00087 m_mapScripts.clear();
00088 Unlock();
00089 }
00090
00092
00094
00095 void ServerSideScripting::RegisterMetaObjectType( const QString &sName,
00096 const QMetaObject *pMetaObject,
00097 QScriptEngine::FunctionSignature pFunction)
00098 {
00099 QScriptValue ctor = m_engine.newFunction( pFunction );
00100
00101 QScriptValue metaObject = m_engine.newQMetaObject( pMetaObject, ctor );
00102 m_engine.globalObject().setProperty( sName, metaObject );
00103 }
00104
00106
00108
00109 bool ServerSideScripting::EvaluatePage( QTextStream *pOutStream, const QString &sFileName )
00110 {
00111 try
00112 {
00113 bool bFound( false );
00114 ScriptInfo *pInfo = NULL;
00115
00116
00117
00118
00119
00120 Lock();
00121
00122 if ( (bFound = m_mapScripts.contains( sFileName )) == true )
00123 pInfo = m_mapScripts[ sFileName ];
00124
00125 Unlock();
00126
00127
00128
00129
00130
00131 QFileInfo fileInfo ( sFileName );
00132 QDateTime dtLastModified = fileInfo.lastModified();
00133
00134 if ((pInfo == NULL) || (pInfo->m_dtTimeStamp != dtLastModified ))
00135 {
00136 QString sCode = CreateMethodFromFile( sFileName );
00137
00138 QScriptValue func = m_engine.evaluate( sCode, sFileName );
00139
00140 if ( m_engine.hasUncaughtException() )
00141 {
00142 LOG(VB_GENERAL, LOG_ERR,
00143 QString("Error Loading QSP File: %1 - (%2)%3")
00144 .arg(sFileName)
00145 .arg(m_engine.uncaughtExceptionLineNumber())
00146 .arg(m_engine.uncaughtException().toString()));
00147
00148 return false;
00149 }
00150
00151 if (pInfo != NULL)
00152 {
00153 pInfo->m_oFunc = func;
00154 pInfo->m_dtTimeStamp = dtLastModified;
00155 }
00156 else
00157 {
00158 pInfo = new ScriptInfo( func, dtLastModified );
00159 Lock();
00160 m_mapScripts[ sFileName ] = pInfo;
00161 Unlock();
00162 }
00163 }
00164
00165
00166
00167
00168
00169 OutputStream outStream( pOutStream );
00170
00171 QScriptValueList args;
00172 args << m_engine.newQObject( &outStream );
00173
00174 pInfo->m_oFunc.call( QScriptValue(), args );
00175
00176 if (m_engine.hasUncaughtException())
00177 {
00178 LOG(VB_GENERAL, LOG_ERR,
00179 QString("Error calling QSP File: %1 - %2")
00180 .arg(sFileName)
00181 .arg(m_engine.uncaughtException().toString()));
00182 return false;
00183 }
00184 }
00185 catch(...)
00186 {
00187 LOG(VB_GENERAL, LOG_ERR,
00188 QString("Exception while evaluating QSP File: %1") .arg(sFileName));
00189
00190 return false;
00191 }
00192
00193 return true;
00194 }
00195
00197
00199
00200 QString ServerSideScripting::CreateMethodFromFile( const QString &sFileName )
00201 {
00202 bool bInCode = false;
00203 QString sBuffer;
00204 QTextStream sCode( &sBuffer );
00205
00206 QFile scriptFile( sFileName );
00207
00208 if (!scriptFile.open( QIODevice::ReadOnly ))
00209 throw "Unable to open file";
00210
00211 try
00212 {
00213 QTextStream stream( &scriptFile );
00214 QString sTransBuffer;
00215
00216 sCode << "(function( os ) {\n";
00217
00218 while( !stream.atEnd() )
00219 {
00220 QString sLine = stream.readLine();
00221
00222 bInCode = ProcessLine( sCode, sLine, bInCode, sTransBuffer );
00223 }
00224
00225 sCode << "})";
00226 }
00227 catch(...)
00228 {
00229 LOG(VB_GENERAL, LOG_ERR,
00230 QString("Exception while reading QSP File: %1") .arg(sFileName));
00231 }
00232
00233 scriptFile.close();
00234
00235 sCode.flush();
00236
00237 return sBuffer;
00238 }
00239
00241
00243
00244 bool ServerSideScripting::ProcessLine( QTextStream &sCode,
00245 QString &sLine,
00246 bool bInCode,
00247 QString &sTransBuffer )
00248 {
00249 sLine = sLine.trimmed();
00250
00251 QString sLowerLine = sLine.toLower();
00252
00253 if (!sTransBuffer.isEmpty())
00254 {
00255 int nEndTransPos = sLowerLine.indexOf("</i18n>");
00256
00257 if (nEndTransPos == -1)
00258 {
00259 sTransBuffer.append(" ");
00260 sTransBuffer.append(sLine);
00261 return bInCode;
00262 }
00263
00264 if (nEndTransPos > 0)
00265 sTransBuffer.append(" ");
00266
00267 sTransBuffer.append(sLine.left(nEndTransPos).trimmed());
00268 QString trStr =
00269 QCoreApplication::translate("HtmlUI", sTransBuffer.trimmed().toLocal8Bit().data());
00270 trStr.replace( '"', "\\\"" );
00271 sCode << "os.write( \"" << trStr << "\" );\n";
00272 sTransBuffer = "";
00273
00274 if (nEndTransPos == (sLine.length() - 7))
00275 return bInCode;
00276
00277 sLine = sLine.right(sLine.length() - (nEndTransPos + 7));
00278 }
00279
00280 int nStartTransPos = sLowerLine.indexOf("<i18n>");
00281 if (nStartTransPos != -1)
00282 {
00283 int nEndTransPos = sLowerLine.indexOf("</i18n>");
00284 if (nEndTransPos != -1)
00285 {
00286 QString patStr = sLine.mid(nStartTransPos,
00287 (nEndTransPos + 7 - nStartTransPos));
00288 QString repStr = patStr.mid(6, patStr.length() - 13).trimmed();
00289 sLine.replace(patStr, QCoreApplication::translate("HtmlUI", repStr.toLocal8Bit().data()));
00290 return ProcessLine(sCode, sLine, bInCode, sTransBuffer);
00291 }
00292 else
00293 {
00294 sTransBuffer = " ";
00295 sTransBuffer.append(sLine.mid(nStartTransPos + 6).trimmed());
00296 sLine = sLine.left(nStartTransPos);
00297 }
00298 }
00299
00300 int nStartPos = 0;
00301 int nEndPos = 0;
00302 int nMatchPos = 0;
00303 bool bMatchFound = false;
00304
00305 QString sExpecting = bInCode ? "%>" : "<%";
00306 bool bNewLine = !(sLine.startsWith( sExpecting ));
00307
00308 while (nStartPos < sLine.length())
00309 {
00310 nEndPos = sLine.length() - 1;
00311
00312 sExpecting = bInCode ? "%>" : "<%";
00313 nMatchPos = sLine.indexOf( sExpecting, nStartPos );
00314
00315
00316
00317
00318
00319 if (nMatchPos < 0)
00320 {
00321 nMatchPos = nEndPos + 1;
00322 bMatchFound = false;
00323 }
00324 else
00325 bMatchFound = true;
00326
00327
00328
00329
00330
00331 QString sSegment = sLine.mid( nStartPos, nMatchPos - nStartPos );
00332
00333 if ( !sSegment.isEmpty())
00334 {
00335 if (bInCode)
00336 {
00337
00338
00339 if (sSegment.startsWith( "=" ))
00340 sCode << "os.write( " << sSegment.mid( 1 ) << " ); "
00341 << "\n";
00342 else
00343 sCode << sSegment << "\n";
00344
00345 if (bMatchFound)
00346 bInCode = false;
00347 }
00348 else
00349 {
00350
00351
00352 sSegment.replace( '"', "\\\"" );
00353
00354 sCode << "os.write( \"" << sSegment << "\" );\n";
00355
00356 if (bMatchFound)
00357 bInCode = true;
00358 else
00359 bNewLine = false;
00360 }
00361 }
00362 else
00363 {
00364 if (bMatchFound)
00365 bInCode = !bInCode;
00366 }
00367
00368 nStartPos = nMatchPos + 2;
00369 }
00370
00371 if ((bNewLine) && !bInCode )
00372 sCode << "os.writeln( \"\" );\n";
00373
00374 return bInCode;
00375 }