1 /***************************************************************************
2     Copyright (C) 2002-2009 Robby Stephenson <robby@periapsis.org>
3  ***************************************************************************/
4 
5 /***************************************************************************
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or         *
8  *   modify it under the terms of the GNU General Public License as        *
9  *   published by the Free Software Foundation; either version 2 of        *
10  *   the License or (at your option) version 3 or any later version        *
11  *   accepted by the membership of KDE e.V. (or its successor approved     *
12  *   by the membership of KDE e.V.), which shall act as a proxy            *
13  *   defined in Section 14 of version 3 of the license.                    *
14  *                                                                         *
15  *   This program is distributed in the hope that it will be useful,       *
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  *   GNU General Public License for more details.                          *
19  *                                                                         *
20  *   You should have received a copy of the GNU General Public License     *
21  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
22  *                                                                         *
23  ***************************************************************************/
24 
25 #ifndef TELLICO_ISBNVALIDATOR_H
26 #define TELLICO_ISBNVALIDATOR_H
27 
28 #include <QValidator>
29 
30 namespace Tellico {
31 
32 /**
33  * @author Robby Stephenson
34  *
35  * @see https://web.archive.org/web/20130126042049/http://www.isbn.org/standards/home/isbn/international/hyphenation-instructions.asp
36  * @see https://www.eblong.com/zarf/bookscan/
37  * @see https://doc.qt.io/archives/qq/qq01-seriously-weird-qregexp.html
38  */
39 class ISBNValidator : public QValidator {
40 Q_OBJECT
41 
42 public:
43   ISBNValidator(QObject* parent = nullptr);
44 
45   /**
46    * Certain conditions are checked. Character, length and position
47    * restrictions are checked. Certain cases where the user is deleting
48    * characters are caught and compensated for. The string is then passed to
49    * @ref fixup. Finally, the text is @ref Valid if it is a certain length and
50    * @ref Intermediate if not.
51    *
52    * @param input The text to validate
53    * @param pos The position of the cursor
54    * @return The condition of the text
55    */
56   virtual QValidator::State validate(QString& input, int& pos) const Q_DECL_OVERRIDE;
57 
58   /**
59    * The input string is examined. Hyphens are inserted appropriately,
60    * and the checksum is calculated.
61    *
62    * For correct presentation, the 10 digits of an ISBN must
63    * be divided, by hyphens, into four parts:
64    * @li Part 1: The country or group of countries identifier
65    * @li Part 2: The publisher identifier
66    * @li Part 3: The title identifier
67    * @li Part 4: The check digit
68    * For details
69    * @see https://web.archive.org/web/20130126042049/http://www.isbn.org/standards/home/isbn/international/hyphenation-instructions.asp
70    * For details on ranges
71    * @see https://www.isbn-international.org/range_file_generation
72    * For info on group codes
73    * @see https://web.archive.org/web/20030609050408/http://www.isbn.spk-berlin.de/html/prefix/allpref.htm
74    * For info on French language publisher codes
75    * @see https://www.afnil.org/
76    * <pre>
77    *  Group Identifiers    First Hyphen After
78    *  -----------------------------------------
79    *  0........7              1st digit
80    *  80.......94             2nd   "
81    *  950......993            3rd   "
82    *  9940.....9989           4th   "
83    *  99900....99999          5th   "
84    *
85    *  Group                   Insert Hyphens
86    *  Identifier "0"            After
87    *  -----------------------------------------
88    *  00.......19          1st  3rd  9th digit
89    *  200......699          "   4th       "
90    *  7000.....8499         "   5th       "
91    *  85000....89999        "   6th       "
92    *  900000...949999       "   7th       "
93    *  9500000..9999999      "   8th       "
94    *
95    *
96    *  Group                  Insert Hyphens
97    *  Identifier "1"           After
98    *  ----------------------------------------
99    *  0........54999           illegal
100    *  55000....86979      1st  6th  9th digit
101    *  869800...998999      "   7th       "
102    *  9990000..9999999     "   8th       "
103    *
104    *
105    *  Group                   Insert Hyphens
106    *  Identifier "2"            After
107    *  -----------------------------------------
108    *  00.......19          1st  3rd  9th digit
109    *  200......349          "   4th       "
110    *  34000....39999        "   6th       "
111    *  400......699          "   4th       "
112    *  7000.....8399         "   5th       "
113    *  84000....89999        "   6th       "
114    *  900000...949999       "   7th       "
115    *  9500000..9999999      "   8th       "
116    *
117    *  The position of the hyphens are determined by the publisher
118    *  prefix range established by each national agency in accordance
119    *  with the industry needs. The knowledge of the prefix ranges for
120    *  each country or group of countries is necessary to develop the
121    *  hyphenation output program. For groups 3 through 99999, the hyphenation
122    *  rules are currently unknown. So just leave out the hyphen between
123    *  the publisher and title for now, but allow it if the user inserts it.
124    * </pre>
125    *
126    * @param input The raw string, hyphens included
127    */
128   virtual void fixup(QString& input) const Q_DECL_OVERRIDE;
129 
130   static void staticFixup(QString& input);
131   static void fixup10(QString& input);
132   static void fixup13(QString& input);
133 
134   static QString isbn10(QString isbn13);
135   static QString isbn13(QString isbn10);
136   static QString cleanValue(QString isbn);
137   // returns the values in list1 that are not in list2
138   static QStringList listDifference(const QStringList& list1, const QStringList& list2);
139 
140 private:
141   static struct isbn_band {
142     unsigned long MaxValue;
143     int First;
144     int Mid;
145     int Last;
146   } bands[];
147 
148   QValidator::State validate10(QString& input, int& pos) const;
149   QValidator::State validate13(QString& input, int& pos) const;
150 
151   /**
152    * This function calculates and returns the ISBN checksum. The
153    * algorithm is based on some code by Andrew Plotkin, available at
154    * https://www.eblong.com/zarf/bookscan/
155    *
156    * @see https://www.eblong.com/zarf/bookscan/
157    *
158    * @param input The raw string, with no hyphens
159    */
160   static QChar checkSum10(const QString& input);
161   static QChar checkSum13(const QString& input);
162 };
163 
164 class ISBNComparison {
165 public:
166   bool operator()(const QString& value1, const QString& value2) const;
167 };
168 
169 } // end namespace
170 #endif
171