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

0001 /***************************************************************************
0002     Copyright (C) 2002-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 #ifndef TELLICO_ISBNVALIDATOR_H
0026 #define TELLICO_ISBNVALIDATOR_H
0027 
0028 #include <QValidator>
0029 
0030 namespace Tellico {
0031 
0032 /**
0033  * @author Robby Stephenson
0034  *
0035  * @see https://web.archive.org/web/20130126042049/http://www.isbn.org/standards/home/isbn/international/hyphenation-instructions.asp
0036  * @see https://www.eblong.com/zarf/bookscan/
0037  * @see https://doc.qt.io/archives/qq/qq01-seriously-weird-qregexp.html
0038  */
0039 class ISBNValidator : public QValidator {
0040 Q_OBJECT
0041 
0042 public:
0043   ISBNValidator(QObject* parent = nullptr);
0044 
0045   /**
0046    * Certain conditions are checked. Character, length and position
0047    * restrictions are checked. Certain cases where the user is deleting
0048    * characters are caught and compensated for. The string is then passed to
0049    * @ref fixup. Finally, the text is @ref Valid if it is a certain length and
0050    * @ref Intermediate if not.
0051    *
0052    * @param input The text to validate
0053    * @param pos The position of the cursor
0054    * @return The condition of the text
0055    */
0056   virtual QValidator::State validate(QString& input, int& pos) const Q_DECL_OVERRIDE;
0057 
0058   /**
0059    * The input string is examined. Hyphens are inserted appropriately,
0060    * and the checksum is calculated.
0061    *
0062    * For correct presentation, the 10 digits of an ISBN must
0063    * be divided, by hyphens, into four parts:
0064    * @li Part 1: The country or group of countries identifier
0065    * @li Part 2: The publisher identifier
0066    * @li Part 3: The title identifier
0067    * @li Part 4: The check digit
0068    * For details
0069    * @see https://web.archive.org/web/20130126042049/http://www.isbn.org/standards/home/isbn/international/hyphenation-instructions.asp
0070    * For details on ranges
0071    * @see https://www.isbn-international.org/range_file_generation
0072    * For info on group codes
0073    * @see https://web.archive.org/web/20030609050408/http://www.isbn.spk-berlin.de/html/prefix/allpref.htm
0074    * For info on French language publisher codes
0075    * @see https://www.afnil.org/
0076    * <pre>
0077    *  Group Identifiers    First Hyphen After
0078    *  -----------------------------------------
0079    *  0........7              1st digit
0080    *  80.......94             2nd   "
0081    *  950......993            3rd   "
0082    *  9940.....9989           4th   "
0083    *  99900....99999          5th   "
0084    *
0085    *  Group                   Insert Hyphens
0086    *  Identifier "0"            After
0087    *  -----------------------------------------
0088    *  00.......19          1st  3rd  9th digit
0089    *  200......699          "   4th       "
0090    *  7000.....8499         "   5th       "
0091    *  85000....89999        "   6th       "
0092    *  900000...949999       "   7th       "
0093    *  9500000..9999999      "   8th       "
0094    *
0095    *
0096    *  Group                  Insert Hyphens
0097    *  Identifier "1"           After
0098    *  ----------------------------------------
0099    *  0........54999           illegal
0100    *  55000....86979      1st  6th  9th digit
0101    *  869800...998999      "   7th       "
0102    *  9990000..9999999     "   8th       "
0103    *
0104    *
0105    *  Group                   Insert Hyphens
0106    *  Identifier "2"            After
0107    *  -----------------------------------------
0108    *  00.......19          1st  3rd  9th digit
0109    *  200......349          "   4th       "
0110    *  34000....39999        "   6th       "
0111    *  400......699          "   4th       "
0112    *  7000.....8399         "   5th       "
0113    *  84000....89999        "   6th       "
0114    *  900000...949999       "   7th       "
0115    *  9500000..9999999      "   8th       "
0116    *
0117    *  The position of the hyphens are determined by the publisher
0118    *  prefix range established by each national agency in accordance
0119    *  with the industry needs. The knowledge of the prefix ranges for
0120    *  each country or group of countries is necessary to develop the
0121    *  hyphenation output program. For groups 3 through 99999, the hyphenation
0122    *  rules are currently unknown. So just leave out the hyphen between
0123    *  the publisher and title for now, but allow it if the user inserts it.
0124    * </pre>
0125    *
0126    * @param input The raw string, hyphens included
0127    */
0128   virtual void fixup(QString& input) const Q_DECL_OVERRIDE;
0129 
0130   static void staticFixup(QString& input);
0131   static void fixup10(QString& input);
0132   static void fixup13(QString& input);
0133 
0134   static QString isbn10(QString isbn13);
0135   static QString isbn13(QString isbn10);
0136   static QString cleanValue(QString isbn);
0137   // returns the values in list1 that are not in list2
0138   static QStringList listDifference(const QStringList& list1, const QStringList& list2);
0139 
0140 private:
0141   static struct isbn_band {
0142     unsigned long MaxValue;
0143     int First;
0144     int Mid;
0145     int Last;
0146   } bands[];
0147 
0148   QValidator::State validate10(QString& input, int& pos) const;
0149   QValidator::State validate13(QString& input, int& pos) const;
0150 
0151   /**
0152    * This function calculates and returns the ISBN checksum. The
0153    * algorithm is based on some code by Andrew Plotkin, available at
0154    * https://www.eblong.com/zarf/bookscan/
0155    *
0156    * @see https://www.eblong.com/zarf/bookscan/
0157    *
0158    * @param input The raw string, with no hyphens
0159    */
0160   static QChar checkSum10(const QString& input);
0161   static QChar checkSum13(const QString& input);
0162 };
0163 
0164 class ISBNComparison {
0165 public:
0166   bool operator()(const QString& value1, const QString& value2) const;
0167 };
0168 
0169 } // end namespace
0170 #endif