File indexing completed on 2024-05-12 05:10:17

0001 /***************************************************************************
0002     Copyright (C) 2005-2009 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include "upcvalidator.h"
0026 #include "isbnvalidator.h"
0027 
0028 using Tellico::UPCValidator;
0029 
0030 UPCValidator::UPCValidator(QObject* parent_)
0031     : QValidator(parent_), m_checkISBN(false), m_isbn(false) {
0032 }
0033 
0034 QValidator::State UPCValidator::validate(QString& input_, int& pos_) const {
0035   // check if it's a cuecat first
0036   State catState = CueCat::decode(input_);
0037   if(catState == Acceptable) {
0038     pos_ = input_.length();
0039     return catState;
0040   }
0041 
0042   // no spaces allowed
0043   if(input_.contains(QLatin1Char(' '))) {
0044     return QValidator::Invalid;
0045   }
0046 
0047   // no real checking, just if starts with 978, use isbnvalidator
0048   const uint len = input_.length();
0049   if(len < 10) {
0050     m_isbn = false;
0051   }
0052 
0053   if(!m_checkISBN || (!m_isbn && len < 13)) {
0054     return QValidator::Intermediate;
0055   }
0056 
0057   // once it gets converted to an ISBN, remember that, and use it for later
0058   if(input_.startsWith(QLatin1String("978")) || input_.startsWith(QLatin1String("979"))) {
0059     ISBNValidator val;
0060     QValidator::State s = val.validate(input_, pos_);
0061     if(s == QValidator::Acceptable) {
0062       m_isbn = true;
0063       emit signalISBN();
0064     }
0065     return s;
0066   }
0067 
0068   // TODO: return QValidator::Acceptable if check sum is correct
0069   return QValidator::Intermediate;
0070 }
0071 
0072 void UPCValidator::fixup(QString& input_) const {
0073   if(input_.isEmpty()) {
0074     return;
0075   }
0076   input_ = input_.trimmed();
0077 
0078   int pos = input_.indexOf(QLatin1Char(' '));
0079   if(pos > -1) {
0080     input_ = input_.left(pos);
0081   }
0082 
0083   if(!m_checkISBN) {
0084     return;
0085   }
0086 
0087   const uint len = input_.length();
0088   if(len > 12 && (input_.startsWith(QLatin1String("978")) || input_.startsWith(QLatin1String("979")))) {
0089     QString s = input_;
0090     ISBNValidator val;
0091     int p = 0;
0092     int state = val.validate(s, p);
0093     if(state == QValidator::Acceptable) {
0094       emit signalISBN();
0095       input_ = s;
0096     }
0097   }
0098 }
0099 
0100 QValidator::State Tellico::CueCat::decode(QString& input_) {
0101   if(input_.length() < 3) {
0102     return QValidator::Intermediate;
0103   }
0104  if(!input_.startsWith(QLatin1String(".C3"))) { // all cuecat codes start with .C3
0105     return QValidator::Invalid;
0106   }
0107   const int periods = input_.count(QLatin1Char('.'));
0108   if(periods < 4) {
0109     return QValidator::Intermediate; // not enough yet
0110   } else if(periods > 4) {
0111     return QValidator::Invalid;
0112   }
0113 
0114   // ok, let's have a go, take the third token
0115   QString code = input_.section(QLatin1Char('.'), 2, 2, QString::SectionSkipEmpty);
0116   while(code.length() % 4 > 0) {
0117     code += QLatin1Char('=');
0118   }
0119 
0120   for(int i = 0; i < code.length(); ++i) {
0121     if(code[i] >= QLatin1Char('A') && code[i] <= QLatin1Char('Z')) {
0122       code.replace(i, 1, code[i].toLower());
0123     } else if(code[i] >= QLatin1Char('a') && code[i] <= QLatin1Char('z')) {
0124       code.replace(i, 1, code[i].toUpper());
0125     }
0126   }
0127 
0128   code = QString::fromLatin1(QByteArray::fromBase64(code.toLatin1()));
0129 
0130   for(int i = 0; i < code.length(); ++i) {
0131     char c = code[i].toLatin1() ^ 'C';
0132     code.replace(i, 1, QLatin1Char(c));
0133   }
0134 
0135   input_ = code;
0136   return QValidator::Acceptable;
0137 }