File indexing completed on 2024-05-05 04:52:23
0001 /* 0002 * convertscanfiles.cpp 0003 * 0004 * Copyright (C) 2008-2011 Christoph Pfister <christophpfister@gmail.com> 0005 * 0006 * This program is free software; you can redistribute it and/or modify 0007 * it under the terms of the GNU General Public License as published by 0008 * the Free Software Foundation; either version 2 of the License, or 0009 * (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License along 0017 * with this program; if not, write to the Free Software Foundation, Inc., 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0019 */ 0020 0021 #include <QDebug> 0022 #if QT_VERSION < 0x050500 0023 # define qInfo qDebug 0024 #endif 0025 0026 #include <QCoreApplication> 0027 #include <QDate> 0028 #include <QDir> 0029 #include <QRegularExpression> 0030 0031 #include "../src/dvb/dvbtransponder.h" 0032 0033 // Mark fallthoughs to shut up gcc 7 warnings 0034 #ifndef __GNUC__ 0035 #define FALLTHROUGH 0036 #else 0037 # if __GNUC__ <= 6 0038 #define FALLTHROUGH 0039 # else 0040 #define FALLTHROUGH __attribute__ ((fallthrough)); 0041 # endif 0042 #endif 0043 0044 class NumericalLessThan 0045 { 0046 public: 0047 bool operator()(const QString &x, const QString &y) 0048 { 0049 int i = 0; 0050 0051 while (true) { 0052 if ((i == x.length()) || (i == y.length())) { 0053 return x.length() < y.length(); 0054 } 0055 0056 if (x.at(i) != y.at(i)) { 0057 break; 0058 } 0059 0060 ++i; 0061 } 0062 0063 int xIndex = x.indexOf(' ', i); 0064 0065 if (xIndex == -1) { 0066 xIndex = x.length(); 0067 } 0068 0069 int yIndex = y.indexOf(' ', i); 0070 0071 if (yIndex == -1) { 0072 yIndex = y.length(); 0073 } 0074 0075 if (xIndex != yIndex) { 0076 return xIndex < yIndex; 0077 } else { 0078 return x.at(i) < y.at(i); 0079 } 0080 } 0081 }; 0082 0083 class parseDvbv5 0084 { 0085 public: 0086 bool parseInputLine(QString line); 0087 void resetParser(); 0088 QString outputLine(); 0089 parseDvbv5(QString name); 0090 int getPos(); 0091 bool hasTransponder; 0092 DvbTransponderBase::TransmissionType type; 0093 0094 private: 0095 QString name; 0096 0097 int lineno; 0098 0099 QString delsys = ""; 0100 QString frq = ""; 0101 QString modulation = ""; 0102 QString symbolRate = ""; 0103 QString fec = ""; 0104 QString polar = ""; 0105 QString inversion = ""; 0106 QString rollOff = ""; 0107 QString plscode = ""; 0108 QString plsmode = ""; 0109 QString bandwidth = ""; 0110 QString fec_hi = ""; 0111 QString fec_lo = ""; 0112 QString t_mode = ""; 0113 QString g_interval = ""; 0114 QString hierarchy = ""; 0115 0116 // ISDB-T specific fields 0117 0118 QString isdbtLayerEnabled = ""; 0119 QString isdbtPartialReception = ""; 0120 QString isdbtSb = ""; 0121 QString isdbtSbSubchId = ""; 0122 QString isdbtSbSegIdx = ""; 0123 QString isdbtSbSegCount = ""; 0124 QString isdbtLayerAFec = ""; 0125 QString isdbtLayerAModulation = ""; 0126 QString isdbtLayerASegCount = ""; 0127 QString isdbtLayerAInterleaving = ""; 0128 QString isdbtLayerBFec = ""; 0129 QString isdbtLayerBModulation = ""; 0130 QString isdbtLayerBSegCount = ""; 0131 QString isdbtLayerBInterleaving = ""; 0132 QString isdbtLayerCFec = ""; 0133 QString isdbtLayerCModulation = ""; 0134 QString isdbtLayerCSegCount = ""; 0135 QString isdbtLayerCInterleaving = ""; 0136 int isdbtLayers = 0; 0137 int streamid = 0; 0138 }; 0139 0140 int parseDvbv5::getPos() 0141 { 0142 return lineno; 0143 }; 0144 0145 parseDvbv5::parseDvbv5(QString name) 0146 { 0147 type = DvbTransponderBase::Invalid; 0148 hasTransponder = false; 0149 0150 this->name = name; 0151 0152 lineno = 0; 0153 }; 0154 0155 void parseDvbv5::resetParser() 0156 { 0157 delsys = ""; 0158 frq = ""; 0159 modulation = ""; 0160 symbolRate = ""; 0161 fec = ""; 0162 polar = ""; 0163 inversion = ""; 0164 rollOff = ""; 0165 plscode = ""; 0166 plsmode = ""; 0167 bandwidth = ""; 0168 fec_hi = ""; 0169 fec_lo = ""; 0170 t_mode = ""; 0171 g_interval = ""; 0172 hierarchy = ""; 0173 0174 isdbtLayerEnabled = ""; 0175 isdbtPartialReception = ""; 0176 isdbtSb = ""; 0177 isdbtSbSubchId = ""; 0178 isdbtSbSegIdx = ""; 0179 isdbtSbSegCount = ""; 0180 isdbtLayerAFec = ""; 0181 isdbtLayerAModulation = ""; 0182 isdbtLayerASegCount = ""; 0183 isdbtLayerAInterleaving = ""; 0184 isdbtLayerBFec = ""; 0185 isdbtLayerBModulation = ""; 0186 isdbtLayerBSegCount = ""; 0187 isdbtLayerBInterleaving = ""; 0188 isdbtLayerCFec = ""; 0189 isdbtLayerCModulation = ""; 0190 isdbtLayerCSegCount = ""; 0191 isdbtLayerCInterleaving = ""; 0192 isdbtLayers = 0; 0193 streamid = 0; 0194 } 0195 0196 bool parseDvbv5::parseInputLine(QString line) 0197 { 0198 lineno++; 0199 0200 QRegularExpression rejex = QRegularExpression("^\\s*\\[(.*)]"); 0201 if (line.contains(rejex)) { 0202 bool oldHasTransponder = hasTransponder; 0203 hasTransponder = true; 0204 return oldHasTransponder; 0205 } 0206 0207 int pos = line.indexOf('#'); 0208 0209 if (pos != -1) { 0210 while ((pos > 0) && (line[pos - 1] == ' ')) { 0211 --pos; 0212 } 0213 0214 line.truncate(pos); 0215 } 0216 0217 if (line.isEmpty()) { 0218 return false; 0219 } 0220 0221 if (line.contains("DELIVERY_SYSTEM")) { 0222 delsys = line.split(" = ")[1]; 0223 if (!delsys.compare("ATSC", Qt::CaseInsensitive)) { 0224 type = DvbTransponderBase::Atsc; 0225 } else if (!delsys.compare("DVBC/ANNEX_A", Qt::CaseInsensitive)) { 0226 type = DvbTransponderBase::DvbC; 0227 } else if (!delsys.compare("DVBC/ANNEX_B", Qt::CaseInsensitive)) { 0228 type = DvbTransponderBase::Atsc; 0229 } else if (!delsys.compare("DVBS", Qt::CaseInsensitive)) { 0230 type = DvbTransponderBase::DvbS; 0231 } else if (!delsys.compare("DVBS2", Qt::CaseInsensitive)) { 0232 type = DvbTransponderBase::DvbS2; 0233 } else if (!delsys.compare("DVBT", Qt::CaseInsensitive)) { 0234 type = DvbTransponderBase::DvbT; 0235 } else if (!delsys.compare("DVBT2", Qt::CaseInsensitive)) { 0236 type = DvbTransponderBase::DvbT2; 0237 } else if (!delsys.compare("ISDBT", Qt::CaseInsensitive)) { 0238 type = DvbTransponderBase::IsdbT; 0239 } else { 0240 type = DvbTransponderBase::Invalid; 0241 } 0242 return false; 0243 } 0244 if (line.contains("FREQUENCY = ")) { 0245 frq = line.split(" = ")[1]; 0246 return false; 0247 } 0248 if (line.contains("INNER_FEC")) { 0249 fec = line.split(" = ")[1]; 0250 return false; 0251 } 0252 if (line.contains("SYMBOL_RATE")) { 0253 symbolRate = line.split(" = ")[1]; 0254 return false; 0255 } 0256 if (line.contains("MODULATION")) { 0257 modulation = line.split(" = ")[1]; 0258 return false; 0259 } 0260 if (line.contains("POLARIZATION")) { 0261 polar = line.split(" = ")[1]; 0262 return false; 0263 } 0264 if (line.contains("INVERSION")) { 0265 inversion = line.split(" = ")[1]; 0266 return false; 0267 } 0268 if (line.contains("ROLLOFF")) { 0269 rollOff = line.split(" = ")[1]; 0270 return false; 0271 } 0272 if (line.contains("STREAM_ID")) { 0273 streamid = line.split(" = ")[1].toInt(); 0274 return false; 0275 } 0276 if (line.contains("PLS_CODE")) { 0277 plscode = line.split(" = ")[1]; 0278 return false; 0279 } 0280 if (line.contains("PLS_MODE")) { 0281 plsmode = line.split(" = ")[1]; 0282 return false; 0283 } 0284 if (line.contains("BANDWIDTH_HZ")) { 0285 bandwidth = line.split(" = ")[1]; 0286 return false; 0287 } 0288 if (line.contains("TRANSMISSION_MODE")) { 0289 t_mode = line.split(" = ")[1]; 0290 return false; 0291 } 0292 if (line.contains("CODE_RATE_HP")) { 0293 fec_hi = line.split(" = ")[1]; 0294 return false; 0295 } 0296 if (line.contains("CODE_RATE_LP")) { 0297 fec_lo = line.split(" = ")[1]; 0298 return false; 0299 } 0300 if (line.contains("HIERARCHY")) { 0301 hierarchy = line.split(" = ")[1]; 0302 return false; 0303 } 0304 if (line.contains("GUARD_INTERVAL")) { 0305 g_interval = line.split(" = ")[1]; 0306 return false; 0307 } 0308 if (line.contains("ISDBT_LAYER_ENABLED")) { 0309 isdbtLayerEnabled = line.split(" = ")[1]; 0310 return false; 0311 } 0312 if (line.contains("ISDBT_PARTIAL_RECEPTION")) { 0313 isdbtPartialReception = line.split(" = ")[1]; 0314 return false; 0315 } 0316 if (line.contains("ISDBT_SOUND_BROADCASTING")) { 0317 isdbtSb = line.split(" = ")[1]; 0318 return false; 0319 } 0320 if (line.contains("ISDBT_SB_SUBCHANNEL_ID")) { 0321 isdbtSbSubchId = line.split(" = ")[1]; 0322 return false; 0323 } 0324 if (line.contains("ISDBT_SB_SEGMENT_IDX")) { 0325 isdbtSbSegIdx = line.split(" = ")[1]; 0326 return false; 0327 } 0328 if (line.contains("ISDBT_SB_SEGMENT_COUNT")) { 0329 isdbtSbSegCount = line.split(" = ")[1]; 0330 return false; 0331 } 0332 // Layer A 0333 if (line.contains("ISDBT_LAYERA_FEC")) { 0334 isdbtLayerAFec = line.split(" = ")[1]; 0335 isdbtLayers |= 1; 0336 return false; 0337 } 0338 if (line.contains("ISDBT_LAYERA_MODULATION")) { 0339 isdbtLayerAModulation = line.split(" = ")[1]; 0340 isdbtLayers |= 1; 0341 return false; 0342 } 0343 if (line.contains("ISDBT_LAYERA_SEGMENT_COUNT")) { 0344 isdbtLayerASegCount = line.split(" = ")[1]; 0345 isdbtLayers |= 1; 0346 return false; 0347 } 0348 if (line.contains("ISDBT_LAYERA_TIME_INTERLEAVING")) { 0349 isdbtLayerAInterleaving = line.split(" = ")[1]; 0350 isdbtLayers |= 1; 0351 return false; 0352 } 0353 // Layer B 0354 if (line.contains("ISDBT_LAYERB_FEC")) { 0355 isdbtLayerBFec = line.split(" = ")[1]; 0356 isdbtLayers |= 2; 0357 return false; 0358 } 0359 if (line.contains("ISDBT_LAYERB_MODULATION")) { 0360 isdbtLayerBModulation = line.split(" = ")[1]; 0361 isdbtLayers |= 2; 0362 return false; 0363 } 0364 if (line.contains("ISDBT_LAYERB_SEGMENT_COUNT")) { 0365 isdbtLayerBSegCount = line.split(" = ")[1]; 0366 isdbtLayers |= 2; 0367 return false; 0368 } 0369 if (line.contains("ISDBT_LAYERB_TIME_INTERLEAVING")) { 0370 isdbtLayerBInterleaving = line.split(" = ")[1]; 0371 isdbtLayers |= 2; 0372 return false; 0373 } 0374 // Layer C 0375 if (line.contains("ISDBT_LAYERC_FEC")) { 0376 isdbtLayerCFec = line.split(" = ")[1]; 0377 isdbtLayers |= 4; 0378 return false; 0379 } 0380 if (line.contains("ISDBT_LAYERC_MODULATION")) { 0381 isdbtLayerCModulation = line.split(" = ")[1]; 0382 isdbtLayers |= 4; 0383 return false; 0384 } 0385 if (line.contains("ISDBT_LAYERC_SEGMENT_COUNT")) { 0386 isdbtLayerCSegCount = line.split(" = ")[1]; 0387 isdbtLayers |= 4; 0388 return false; 0389 } 0390 if (line.contains("ISDBT_LAYERC_TIME_INTERLEAVING")) { 0391 isdbtLayerCInterleaving = line.split(" = ")[1]; 0392 isdbtLayers |= 4; 0393 return false; 0394 } 0395 qWarning() << "Can't parse line" << lineno << ":" << line << " for " << name; 0396 return false; 0397 }; 0398 0399 0400 QString parseDvbv5::outputLine() 0401 { 0402 QString line = ""; 0403 0404 if (frq.isEmpty()) { 0405 qWarning() << "frequency is empty in pos " 0406 << lineno << " file" << name; 0407 return line; 0408 } 0409 0410 switch (type) { 0411 case DvbTransponderBase::Invalid: 0412 if (!hasTransponder) 0413 return ""; 0414 qWarning() << "Invalid transponder type in pos " 0415 << lineno << " file" << name; 0416 return line; 0417 case DvbTransponderBase::DvbC: { 0418 if (symbolRate.isEmpty()) { 0419 qWarning() << "No symbol rate in pos " 0420 << lineno << " file" << name; 0421 return line; 0422 } 0423 if (modulation.isEmpty()) { 0424 qWarning() << "No symbol rate in pos " 0425 << lineno << " file" << name; 0426 return line; 0427 } 0428 line = "C " + frq + ' ' + symbolRate + ' ' + fec + ' ' + modulation.remove('/'); 0429 return line; 0430 } 0431 case DvbTransponderBase::DvbS: { 0432 if (rollOff.isEmpty() && (modulation.isEmpty() || !modulation.compare("QPSK"))) { 0433 line = "S " + frq + ' ' + polar[0] + ' ' + symbolRate + ' ' + fec; 0434 return line; 0435 } 0436 type = DvbTransponderBase::DvbS2; 0437 0438 // Fall through DVB-S2 handling 0439 FALLTHROUGH 0440 } 0441 case DvbTransponderBase::DvbS2: { 0442 if (rollOff.isEmpty()) 0443 rollOff = "25"; 0444 0445 if (modulation.isEmpty()) { 0446 modulation = "AUTO"; 0447 } if (modulation.contains("/")) { 0448 QString temp1 = modulation.split('/')[0]; 0449 QString temp2 = modulation.split('/')[1]; 0450 modulation = temp2 + temp1; 0451 } 0452 0453 line = "S2 " + frq + ' ' + polar[0] + ' ' + symbolRate + ' ' + fec + ' ' + rollOff + ' ' + modulation; 0454 0455 return line; 0456 } 0457 case DvbTransponderBase::DvbT: { 0458 line = "T " + frq; 0459 if (!bandwidth.isEmpty()) { 0460 int number = bandwidth.toInt(); 0461 number = number / 1000000; 0462 line += ' ' + QString::number(number) + "MHz"; 0463 } 0464 if (!fec_hi.isEmpty()) { 0465 line += ' ' + fec_hi; 0466 } else { 0467 line += " AUTO"; 0468 } 0469 if (!fec_lo.isEmpty()) { 0470 line += ' ' + fec_lo; 0471 } else { 0472 line += " AUTO"; 0473 } 0474 if (!modulation.isEmpty()) { 0475 line += ' ' + modulation.remove('/').replace("QAMAUTO", "AUTO"); 0476 } else { 0477 line += " AUTO"; 0478 } 0479 if (!t_mode.isEmpty()) { 0480 line += ' ' + t_mode.replace('K', 'k'); 0481 } else { 0482 line += " AUTO"; 0483 } 0484 if (!g_interval.isEmpty()) { 0485 line += ' ' + g_interval; 0486 } else { 0487 line += " AUTO"; 0488 } 0489 if (!hierarchy.isEmpty()) { 0490 line += ' ' + hierarchy; 0491 } else { 0492 line += " AUTO"; 0493 } 0494 return line; 0495 } 0496 case DvbTransponderBase::DvbT2: { 0497 line = "T2 " + frq; 0498 if (!bandwidth.isEmpty()) { 0499 int number = bandwidth.toInt(); 0500 number = number / 1000000; 0501 line += ' ' + QString::number(number) + "MHz"; 0502 } 0503 if (!fec_hi.isEmpty()) { 0504 line += ' ' + fec_hi; 0505 } else { 0506 line += " AUTO"; 0507 } 0508 if (!fec_lo.isEmpty()) { 0509 line += ' ' + fec_lo; 0510 } else { 0511 line += " AUTO"; 0512 } 0513 if (!modulation.isEmpty()) { 0514 line += ' ' + modulation.remove('/').replace("QAMAUTO", "AUTO"); 0515 } else { 0516 line += " AUTO"; 0517 } 0518 if (!t_mode.isEmpty()) { 0519 line += ' ' + t_mode.replace('K', 'k'); 0520 } else { 0521 line += " AUTO"; 0522 } 0523 if (!g_interval.isEmpty()) { 0524 line += ' ' + g_interval; 0525 } else { 0526 line += " AUTO"; 0527 } 0528 if (!hierarchy.isEmpty()) { 0529 line += ' ' + hierarchy; 0530 } else { 0531 line += " AUTO"; 0532 } 0533 line += ' ' + QString::number(streamid); 0534 return line; 0535 } 0536 case DvbTransponderBase::Atsc: { 0537 line = "A " + frq; 0538 if (!modulation.isEmpty()) { 0539 QString temp1 = modulation.split('/')[0]; 0540 QString temp2 = modulation.split('/')[1]; 0541 if (!(temp1 == "QAM")) { 0542 line += ' ' + temp2 + temp1; 0543 } else { 0544 line += ' ' + temp1 + temp2; 0545 } 0546 } else { 0547 line += " AUTO"; 0548 } 0549 return line; 0550 } 0551 case DvbTransponderBase::IsdbT: { 0552 line = "I " + frq; 0553 if (!bandwidth.isEmpty()) { 0554 int number = bandwidth.toInt(); 0555 number = number / 1000000; 0556 line += ' ' + QString::number(number) + "MHz"; 0557 } else { 0558 line += " 6MHz"; 0559 } 0560 if (!t_mode.isEmpty()) { 0561 line += ' ' + t_mode.replace('K', 'k'); 0562 } else { 0563 line += " AUTO"; 0564 } 0565 if (!g_interval.isEmpty()) { 0566 line += ' ' + g_interval; 0567 } else { 0568 line += " AUTO"; 0569 } 0570 if (!isdbtPartialReception.isEmpty()) { 0571 line += ' ' + isdbtPartialReception; 0572 } else { 0573 line += " AUTO"; 0574 } 0575 if (!isdbtSb.isEmpty()) { 0576 line += ' ' + isdbtSb; 0577 } else { 0578 line += " AUTO"; 0579 } 0580 if (!isdbtSbSubchId.isEmpty()) { 0581 line += ' ' + isdbtSbSubchId; 0582 } else { 0583 line += " AUTO"; 0584 } 0585 if (!isdbtSbSegCount.isEmpty()) { 0586 line += ' ' + isdbtSbSegCount; 0587 } else { 0588 line += " AUTO"; 0589 } 0590 if (!isdbtSbSegIdx.isEmpty()) { 0591 line += ' ' + isdbtSbSegIdx; 0592 } else { 0593 line += " AUTO"; 0594 } 0595 0596 line += ' ' + QString::number(isdbtLayers); 0597 0598 // Layer A 0599 if (!isdbtLayerAModulation.isEmpty()) { 0600 line += ' ' + isdbtLayerAModulation.remove('/').replace("QAMAUTO", "AUTO"); 0601 } else { 0602 line += " AUTO"; 0603 } 0604 if (!isdbtLayerAFec.isEmpty()) { 0605 line += ' ' + isdbtLayerAFec; 0606 } else { 0607 line += " AUTO"; 0608 } 0609 if (!isdbtLayerASegCount.isEmpty()) { 0610 line += ' ' + isdbtLayerASegCount; 0611 } else { 0612 line += " AUTO"; 0613 } 0614 if (!isdbtLayerAInterleaving.isEmpty()) { 0615 line += ' ' + isdbtLayerAInterleaving; 0616 } else { 0617 line += " AUTO"; 0618 } 0619 // Layer B 0620 if (!isdbtLayerBModulation.isEmpty()) { 0621 line += ' ' + isdbtLayerBModulation.remove('/').replace("QAMAUTO", "AUTO"); 0622 } else { 0623 line += " AUTO"; 0624 } 0625 if (!isdbtLayerBFec.isEmpty()) { 0626 line += ' ' + isdbtLayerBFec; 0627 } else { 0628 line += " AUTO"; 0629 } 0630 if (!isdbtLayerBSegCount.isEmpty()) { 0631 line += ' ' + isdbtLayerBSegCount; 0632 } else { 0633 line += " AUTO"; 0634 } 0635 if (!isdbtLayerBInterleaving.isEmpty()) { 0636 line += ' ' + isdbtLayerBInterleaving; 0637 } else { 0638 line += " AUTO"; 0639 } 0640 // Layer C 0641 if (!isdbtLayerCModulation.isEmpty()) { 0642 line += ' ' + isdbtLayerCModulation.remove('/').replace("QAMAUTO", "AUTO"); 0643 } else { 0644 line += " AUTO"; 0645 } 0646 if (!isdbtLayerCFec.isEmpty()) { 0647 line += ' ' + isdbtLayerCFec; 0648 } else { 0649 line += " AUTO"; 0650 } 0651 if (!isdbtLayerCSegCount.isEmpty()) { 0652 line += ' ' + isdbtLayerCSegCount; 0653 } else { 0654 line += " AUTO"; 0655 } 0656 if (!isdbtLayerCInterleaving.isEmpty()) { 0657 line += ' ' + isdbtLayerCInterleaving; 0658 } else { 0659 line += " AUTO"; 0660 } 0661 return line; 0662 } 0663 } 0664 0665 return line; 0666 } 0667 0668 static QString parseLine(DvbTransponderBase::TransmissionType type, const QString &line, const QString &fileName) 0669 { 0670 switch (type) { 0671 case DvbTransponderBase::Invalid: 0672 break; 0673 case DvbTransponderBase::DvbC: { 0674 DvbCTransponder transponder; 0675 0676 if (!transponder.fromString(line)) { 0677 break; 0678 } 0679 if (transponder.modulation == DvbCTransponder::ModulationAuto) { 0680 qWarning() << "Warning: modulation == AUTO in file" << fileName; 0681 } 0682 0683 if (transponder.fecRate != DvbCTransponder::FecNone) { 0684 qWarning() << "Warning: fec rate != NONE in file" << fileName; 0685 } 0686 return transponder.toString(); 0687 } 0688 case DvbTransponderBase::DvbS: { 0689 DvbSTransponder transponder; 0690 0691 if (!transponder.fromString(line)) { 0692 break; 0693 } 0694 if (transponder.fecRate == DvbSTransponder::FecNone) { 0695 qWarning() << "Warning: fec rate == NONE in file" << fileName; 0696 } 0697 // fecRate == AUTO is ok 0698 0699 return transponder.toString(); 0700 } 0701 case DvbTransponderBase::DvbS2: { 0702 DvbS2Transponder transponder; 0703 0704 if (!transponder.fromString(line)) { 0705 break; 0706 } 0707 if (transponder.fecRate == DvbSTransponder::FecNone) { 0708 qWarning() << "Warning: fec rate == NONE in file" << fileName; 0709 } 0710 // fecRate == AUTO is ok 0711 0712 return transponder.toString(); 0713 } 0714 case DvbTransponderBase::DvbT2: { 0715 DvbT2Transponder transponder; 0716 0717 if (!transponder.fromString(line)) { 0718 break; 0719 } 0720 return transponder.toString(); 0721 } 0722 case DvbTransponderBase::DvbT: { 0723 DvbTTransponder transponder; 0724 0725 if (!transponder.fromString(line)) { 0726 break; 0727 } 0728 if (transponder.bandwidth == DvbTTransponder::BandwidthAuto) { 0729 qWarning() << "Warning: bandwidth == AUTO in file" << fileName; 0730 } 0731 0732 if ((transponder.modulation == DvbTTransponder::ModulationAuto) && !fileName.startsWith(QLatin1String("auto-"))) { 0733 qWarning() << "Warning: modulation == AUTO in file" << fileName; 0734 } 0735 0736 if (transponder.fecRateHigh == DvbTTransponder::FecNone) { 0737 qWarning() << "Warning: fec rate high == NONE in file" << fileName; 0738 } 0739 0740 // fecRateHigh == AUTO is ok 0741 0742 if (transponder.fecRateLow != DvbTTransponder::FecNone) { 0743 qWarning() << "Warning: fec rate low != NONE in file" << fileName; 0744 } 0745 0746 if ((transponder.transmissionMode == DvbTTransponder::TransmissionModeAuto) && !fileName.startsWith(QLatin1String("auto-"))) { 0747 qWarning() << "Warning: transmission mode == AUTO in file" << fileName; 0748 } 0749 0750 if ((transponder.guardInterval == DvbTTransponder::GuardIntervalAuto) && !fileName.startsWith(QLatin1String("auto-"))) { 0751 qWarning() << "Warning: guard interval == AUTO in file" << fileName; 0752 } 0753 0754 if (transponder.hierarchy != DvbTTransponder::HierarchyNone) { 0755 qWarning() << "Warning: hierarchy != NONE in file" << fileName; 0756 } 0757 return transponder.toString(); 0758 } 0759 case DvbTransponderBase::Atsc: { 0760 AtscTransponder transponder; 0761 0762 if (!transponder.fromString(line)) { 0763 break; 0764 } 0765 if (transponder.modulation == AtscTransponder::ModulationAuto) { 0766 qWarning() << "Warning: modulation == AUTO in file" << fileName; 0767 } 0768 return transponder.toString(); 0769 } 0770 case DvbTransponderBase::IsdbT: { 0771 IsdbTTransponder transponder; 0772 0773 if (!transponder.fromString(line)) { 0774 break; 0775 } 0776 0777 return transponder.toString(); 0778 } 0779 } 0780 0781 return QString(); 0782 } 0783 0784 static void readScanDirectory(QTextStream &out, const QString &path) 0785 { 0786 QDir dir; 0787 0788 dir.setPath(path); 0789 if (!dir.exists()) { 0790 qCritical() << "Error: can't open directory" << dir.path(); 0791 return; 0792 } 0793 0794 foreach (const QString &fileName, dir.entryList(QDir::Files, QDir::Name)) { 0795 QFile file(dir.filePath(fileName)); 0796 0797 if (!file.open(QIODevice::ReadOnly)) { 0798 qCritical() << "Error: can't open file" << file.fileName(); 0799 return; 0800 } 0801 0802 QTextStream stream(&file); 0803 stream.setCodec("UTF-8"); 0804 QList<QString> transponders; 0805 QString name = dir.dirName() + '/' + fileName; 0806 0807 parseDvbv5 parser(name); 0808 0809 while (!stream.atEnd()) { 0810 QString line = stream.readLine(); 0811 0812 if (!parser.parseInputLine(line) && !stream.atEnd()) 0813 continue; 0814 0815 if (!parser.hasTransponder) 0816 continue; 0817 0818 QString parsedLine = parser.outputLine(); 0819 parser.resetParser(); 0820 0821 QString string = parseLine(parser.type, parsedLine, fileName); 0822 0823 if (string.isEmpty()) { 0824 qCritical() << "Error: can't parse Transponder pos " << parser.getPos() << "line" << parsedLine << "in file" << name; 0825 continue; 0826 } 0827 0828 // reduce multiple spaces to one space 0829 0830 for (int i = 1; i < parsedLine.length(); ++i) { 0831 if (parsedLine.at(i - 1) != ' ') { 0832 continue; 0833 } 0834 0835 if (parsedLine.at(i) == ' ') { 0836 parsedLine.remove(i, 1); 0837 --i; 0838 } 0839 } 0840 if (parsedLine.at(parsedLine.length() - 1) == ' ') { 0841 parsedLine.remove(parsedLine.length() - 1, 1); 0842 } 0843 0844 if (parsedLine != string) { 0845 qWarning() << "Warning: suboptimal representation:"; 0846 qWarning() << parsedLine << "<-->"; 0847 qWarning() << string << "in file" << name; 0848 } 0849 0850 transponders.append(string); 0851 } 0852 0853 if (transponders.isEmpty()) { 0854 qWarning() << "Warning: no transponder found in file" << name; 0855 continue; 0856 } 0857 0858 if (parser.type == DvbTransponderBase::DvbS || 0859 parser.type == DvbTransponderBase::DvbS2) { 0860 // use upper case for orbital position 0861 name[name.size() - 1] = name.at(name.size() - 1).toUpper(); 0862 0863 QString source = name; 0864 source.remove(0, source.lastIndexOf('-') + 1); 0865 0866 bool ok = false; 0867 0868 if (source.endsWith('E')) { 0869 source.chop(1); 0870 source.toDouble(&ok); 0871 } else if (source.endsWith('W')) { 0872 source.chop(1); 0873 source.toDouble(&ok); 0874 } 0875 0876 if (!ok) { 0877 qWarning() << "Warning: invalid orbital position for file" << name; 0878 } 0879 } 0880 0881 out << '[' << name << "]\n"; 0882 0883 std::sort(transponders.begin(), transponders.end(), NumericalLessThan()); 0884 0885 foreach (const QString &transponder, transponders) { 0886 out << transponder << '\n'; 0887 } 0888 } 0889 } 0890 0891 int main(int argc, char *argv[]) 0892 { 0893 // QCoreApplication is needed for proper file name handling 0894 QCoreApplication app(argc, argv); 0895 0896 if (argc != 3) { 0897 qCritical() << "Syntax: convertscanfiles <scan file dir> <output file>"; 0898 return 1; 0899 } 0900 0901 QByteArray data; 0902 QTextStream out(&data); 0903 out.setCodec("UTF-8"); 0904 0905 out << "# this file is automatically generated from https://linuxtv.org/downloads/dtv-scan-tables\n"; 0906 out << "[date]\n"; 0907 out << QDate::currentDate().toString(Qt::ISODate) << '\n'; 0908 0909 QString path(argv[1]); 0910 0911 readScanDirectory(out, path + "/dvb-c"); 0912 readScanDirectory(out, path + "/dvb-s"); 0913 readScanDirectory(out, path + "/dvb-t"); 0914 readScanDirectory(out, path + "/atsc"); 0915 readScanDirectory(out, path + "/isdb-t"); 0916 0917 out.flush(); 0918 0919 QFile file(argv[2]); 0920 0921 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { 0922 qCritical() << "Error: can't open file" << file.fileName(); 0923 return 1; 0924 } 0925 0926 file.write(data); 0927 0928 QFile compressedFile(QString(argv[2]) + ".qz"); 0929 0930 if (!compressedFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { 0931 qCritical() << "Error: can't open file" << compressedFile.fileName(); 0932 return 1; 0933 } 0934 0935 compressedFile.write(qCompress(data, 9)); 0936 0937 return 0; 0938 }