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 #include "isbnvalidator.h" 0026 #include "upcvalidator.h" 0027 0028 #include <QStringList> 0029 #include <QRegularExpression> 0030 0031 using Tellico::ISBNValidator; 0032 0033 //static 0034 QString ISBNValidator::isbn10(QString isbn13) { 0035 QString original = isbn13; 0036 isbn13.remove(QLatin1Char('-')); 0037 if(isbn13.length() == 10) { 0038 fixup10(isbn13); 0039 return isbn13; 0040 } 0041 if(!isbn13.startsWith(QStringLiteral("978"))) { 0042 return original; 0043 } 0044 if(isbn13.length() < 13) { 0045 fixup10(isbn13); 0046 return isbn13; 0047 } 0048 isbn13 = isbn13.mid(3); 0049 // remove checksum 0050 isbn13.truncate(isbn13.length()-1); 0051 // add new checksum 0052 isbn13 += checkSum10(isbn13); 0053 fixup10(isbn13); 0054 return isbn13; 0055 } 0056 0057 QString ISBNValidator::isbn13(QString isbn10) { 0058 isbn10.remove(QLatin1Char('-')); 0059 if(isbn10.length() < 10) { 0060 return isbn10; 0061 } 0062 if(isbn10.length() > 10) { 0063 // assume it's already an isbn13 value 0064 fixup13(isbn10); 0065 return isbn10; 0066 } 0067 // remove checksum 0068 isbn10.truncate(isbn10.length()-1); 0069 // begins with 978 0070 isbn10.prepend(QStringLiteral("978")); 0071 // add new checksum 0072 isbn10 += checkSum13(isbn10); 0073 fixup13(isbn10); 0074 return isbn10; 0075 } 0076 0077 QStringList ISBNValidator::listDifference(const QStringList& list1_, const QStringList& list2_) { 0078 ISBNComparison comp; 0079 0080 QStringList notFound; 0081 foreach(const QString& value1, list1_) { 0082 bool found = false; 0083 foreach(const QString& value2, list2_) { 0084 if(comp(value1, value2)) { 0085 found = true; 0086 break; 0087 } 0088 } 0089 if(!found) { 0090 notFound.append(value1); 0091 } 0092 } 0093 return notFound; 0094 } 0095 0096 QString ISBNValidator::cleanValue(QString isbn) { 0097 static const QRegularExpression badChars(QStringLiteral("[^xX0123456789]")); 0098 isbn.remove(badChars); 0099 return isbn; 0100 } 0101 0102 ISBNValidator::ISBNValidator(QObject* parent_) 0103 : QValidator(parent_) { 0104 } 0105 0106 QValidator::State ISBNValidator::validate(QString& input_, int& pos_) const { 0107 // check if it's a cuecat first 0108 State catState = CueCat::decode(input_); 0109 if(catState != Invalid) { 0110 pos_ = input_.length(); 0111 return catState; 0112 } 0113 0114 if(input_.startsWith(QStringLiteral("978")) || 0115 input_.startsWith(QStringLiteral("979"))) { 0116 return validate13(input_, pos_); 0117 } else { 0118 return validate10(input_, pos_); 0119 } 0120 } 0121 0122 void ISBNValidator::fixup(QString& input_) const { 0123 staticFixup(input_); 0124 } 0125 0126 void ISBNValidator::staticFixup(QString& input_) { 0127 if((input_.startsWith(QStringLiteral("978")) 0128 || input_.startsWith(QStringLiteral("979"))) 0129 && input_.count(QRegularExpression(QStringLiteral("\\d"))) > 10) { 0130 fixup13(input_); 0131 } else { 0132 fixup10(input_); 0133 } 0134 } 0135 0136 QValidator::State ISBNValidator::validate10(QString& input_, int& pos_) const { 0137 int len = input_.length(); 0138 /* 0139 // Don't do this since the hyphens may be in the wrong place, can't put that in a regexp 0140 if(isbn.exactMatch(input_) // put the exactMatch() first since I use matchedLength() later 0141 && (len == 12 || len == 13) 0142 && input_[len-1] == checkSum(input_)) { 0143 return QValidator::Acceptable; 0144 } 0145 */ 0146 // two easy invalid cases are too many hyphens and the 'X' not in the last position 0147 if(input_.count(QLatin1Char('-')) > 3 0148 || input_.count(QLatin1Char('X'), Qt::CaseInsensitive) > 1 0149 || (input_.indexOf(QLatin1Char('X'), 0, Qt::CaseInsensitive) != -1 && input_[len-1].toUpper() != QLatin1Char('X'))) { 0150 return QValidator::Invalid; 0151 } 0152 0153 // remember if the cursor is at the end 0154 bool atEnd = (pos_ == static_cast<int>(len)); 0155 0156 // fix the case where the user attempts to delete a character from a non-checksum 0157 // position; the solution is to delete the checksum, but only if it's X 0158 if(!atEnd && input_[len-1].toUpper() == QLatin1Char('X')) { 0159 input_.truncate(len-1); 0160 --len; 0161 } 0162 0163 // fix the case where the user attempts to delete the checksum; the 0164 // solution is to delete the last digit as well 0165 static const QRegularExpression digit(QStringLiteral("\\d")); 0166 if(atEnd && input_.count(digit) == 9 && input_[len-1] == QLatin1Char('-')) { 0167 input_.truncate(len-2); 0168 pos_ -= 2; 0169 } 0170 0171 // now fixup the hyphens and maybe add a checksum 0172 fixup10(input_); 0173 len = input_.length(); // might have changed in fixup() 0174 if(atEnd) { 0175 pos_ = len; 0176 } 0177 0178 // first check to see if it's a "perfect" ISBN 0179 // A perfect ISBN has 9 digits plus either an 'X' or another digit 0180 // A perfect ISBN may have 2 or 3 hyphens 0181 // The final digit or 'X' is the correct check sum 0182 static const QRegularExpression isbn(QStringLiteral("^(\\d-?){9,11}-[\\dX]$")); 0183 if(isbn.match(input_).hasMatch() && (len == 12 || len == 13)) { 0184 return QValidator::Acceptable; 0185 } else { 0186 return QValidator::Intermediate; 0187 } 0188 } 0189 0190 QValidator::State ISBNValidator::validate13(QString& input_, int& pos_) const { 0191 int len = input_.length(); 0192 0193 const uint countX = input_.count(QLatin1Char('X'), Qt::CaseInsensitive); 0194 // two easy invalid cases are too many hyphens or 'X' 0195 if(input_.count(QLatin1Char('-')) > 4 || countX > 1) { 0196 return QValidator::Invalid; 0197 } 0198 0199 // now, it's not certain that we're getting a EAN-13, 0200 // it could be a ISBN-10 from Nigeria or Indonesia 0201 if(countX > 0 && (len > 13 || input_[len-1].toUpper() != QLatin1Char('X'))) { 0202 return QValidator::Invalid; 0203 } 0204 0205 // remember if the cursor is at the end 0206 bool atEnd = (pos_ == len); 0207 0208 // fix the case where the user attempts to delete a character from a non-checksum 0209 // position; the solution is to delete the checksum, but only if it's X 0210 if(!atEnd && input_[len-1].toUpper() == QLatin1Char('X')) { 0211 input_.truncate(len-1); 0212 --len; 0213 } 0214 0215 // fix the case where the user attempts to delete the checksum; the 0216 // solution is to delete the last digit as well 0217 static const QRegularExpression digit(QStringLiteral("\\d")); 0218 const uint countN = input_.count(digit); 0219 if(atEnd && (countN == 12 || countN == 9) && input_[len-1] == QLatin1Char('-')) { 0220 input_.truncate(len-2); 0221 pos_ -= 2; 0222 } 0223 0224 // now fixup the hyphens and maybe add a checksum 0225 if(countN > 10) { 0226 fixup13(input_); 0227 } else { 0228 fixup10(input_); 0229 } 0230 0231 len = input_.length(); // might have changed in fixup() 0232 if(atEnd) { 0233 pos_ = len; 0234 } 0235 0236 // first check to see if it's a "perfect" ISBN13 0237 // A perfect ISBN13 has 13 digits 0238 // A perfect ISBN13 may have 3 or 4 hyphens 0239 // The final digit is the correct check sum 0240 static const QRegularExpression isbn(QStringLiteral("^(\\d-?){13,17}$")); 0241 if(isbn.match(input_).hasMatch()) { 0242 return QValidator::Acceptable; 0243 } else { 0244 return QValidator::Intermediate; 0245 } 0246 } 0247 0248 void ISBNValidator::fixup10(QString& input_) { 0249 if(input_.isEmpty()) { 0250 return; 0251 } 0252 0253 //replace "x" with "X" 0254 input_.replace(QLatin1Char('x'), QLatin1Char('X')); 0255 0256 // remove invalid chars 0257 static const QRegularExpression badChars(QStringLiteral("[^\\d\\-X]")); 0258 input_.remove(badChars); 0259 0260 // special case for EAN values that start with 978 or 979. That's the case 0261 // for things like barcode readers that essentially 'type' the string at 0262 // once. The simulated typing has already caused the input to be normalized, 0263 // so strip that off, as well as the generated checksum. Then continue as normal. 0264 // If someone were to input a regular 978- or 979- ISBN _including_ the 0265 // checksum, it will be regarded as barcode input and the input will be stripped accordingly. 0266 // I consider the likelihood that someone wants to input an EAN to be higher than someone 0267 // using a Nigerian ISBN and not noticing that the checksum gets added automatically. 0268 if(input_.length() > 12 0269 && (input_.startsWith(QStringLiteral("978")) 0270 || input_.startsWith(QStringLiteral("979")))) { 0271 // Strip the first 3 characters (the invalid publisher) 0272 // input_ = input_.right(input_.length() - 3); 0273 } 0274 0275 // hyphen placement for some languages publishers is well-defined 0276 // remove all hyphens, and insert them ourselves 0277 // some countries have ill-defined second hyphen positions, and if 0278 // the user inserts one, then be sure to put it back 0279 0280 // Find the first hyphen. If there is none, 0281 // input_.indexOf('-') returns -1 and hyphen1_position = -1 0282 int hyphen1_position = input_.indexOf(QLatin1Char('-')); 0283 0284 // Find the second one. If none, hyphen2_position = -2 0285 int hyphen2_position = input_.indexOf(QLatin1Char('-'), hyphen1_position+1) - 1; 0286 0287 // The second hyphen can not be in the last character 0288 if(hyphen2_position >= 9) { 0289 hyphen2_position = 0; 0290 } 0291 0292 const bool hyphenAtEnd = input_.endsWith(QLatin1Char('-')); 0293 0294 // Remove all existing hyphens. We will insert ours. 0295 input_.remove(QLatin1Char('-')); 0296 // the only place that 'X' can be is last spot 0297 for(int xpos = input_.indexOf(QLatin1Char('X')); xpos > -1; xpos = input_.indexOf(QLatin1Char('X'), xpos+1)) { 0298 if(xpos < 9) { // remove if not 10th char 0299 input_.remove(xpos, 1); 0300 --xpos; 0301 } 0302 } 0303 input_.truncate(10); 0304 0305 // If we can find it, add the checksum 0306 // but only if not started with 978 or 979 0307 if(input_.length() > 8 0308 && !input_.startsWith(QStringLiteral("978")) 0309 && !input_.startsWith(QStringLiteral("979"))) { 0310 if(input_.length() == 9) input_.resize(10); 0311 input_[9] = checkSum10(input_); 0312 } 0313 0314 ulong range = input_.leftJustified(9, QLatin1Char('0'), true).toULong(); 0315 0316 // now find which band the range falls in 0317 int band = 0; 0318 while(range >= bands[band].MaxValue) { 0319 ++band; 0320 } 0321 0322 // if we have space to put the first hyphen, do it 0323 if(input_.length() > bands[band].First) { 0324 input_.insert(bands[band].First, QLatin1Char('-')); 0325 } 0326 0327 //add 1 since one "-" character has already been inserted 0328 if(bands[band].Mid != 0) { 0329 hyphen2_position = bands[band].Mid; 0330 if(static_cast<int>(input_.length()) > (hyphen2_position + 1)) { 0331 input_.insert(hyphen2_position + 1, QLatin1Char('-')); 0332 } 0333 // or put back user's hyphen 0334 } else if(hyphen2_position > 0 && static_cast<int>(input_.length()) >= (hyphen2_position + 1)) { 0335 input_.insert(hyphen2_position + 1, QLatin1Char('-')); 0336 } 0337 0338 // add a "-" before the checkdigit and another one if the middle "-" exists 0339 const int trueLast = bands[band].Last + 1 + (hyphen2_position > 0 ? 1 : 0); 0340 if(input_.length() > trueLast) { 0341 input_.insert(trueLast, QLatin1Char('-')); 0342 } else if(hyphenAtEnd && !input_.endsWith(QLatin1Char('-'))) { 0343 input_ += QLatin1Char('-'); 0344 } 0345 } 0346 0347 void ISBNValidator::fixup13(QString& input_) { 0348 if(input_.isEmpty()) { 0349 return; 0350 } 0351 0352 // remove invalid chars 0353 static const QRegularExpression badChars(QStringLiteral("[^\\d-]")); 0354 input_.remove(badChars); 0355 0356 // hyphen placement for some languages publishers is well-defined 0357 // remove all hyphens, and insert them ourselves 0358 // some countries have ill-defined second hyphen positions, and if 0359 // the user inserts one, then be sure to put it back 0360 0361 QString after = input_.mid(3); 0362 if(after[0] == QLatin1Char('-')) { 0363 after = after.mid(1); 0364 } 0365 0366 // Find the first hyphen. If there is none, 0367 // input_.indexOf('-') returns -1 and hyphen1_position = -1 0368 int hyphen1_position = after.indexOf(QLatin1Char('-')); 0369 0370 // Find the second one. If none, hyphen2_position = -2 0371 int hyphen2_position = after.indexOf(QLatin1Char('-'), hyphen1_position+1) - 1; 0372 0373 // The second hyphen can not be in the last characters 0374 if(hyphen2_position >= 9) { 0375 hyphen2_position = 0; 0376 } 0377 0378 // Remove all existing hyphens. We will insert ours. 0379 after.remove(QLatin1Char('-')); 0380 after.truncate(10); 0381 0382 // add the checksum 0383 if(after.length() > 8) { 0384 if(after.length() == 9) after.resize(10); 0385 after[9] = checkSum13(input_.left(3) + after); 0386 } 0387 0388 ulong range = after.leftJustified(9, QLatin1Char('0'), true).toULong(); 0389 0390 // now find which band the range falls in 0391 int band = 0; 0392 while(range >= bands[band].MaxValue) { 0393 ++band; 0394 } 0395 0396 // if we have space to put the first hyphen, do it 0397 if(after.length() > bands[band].First) { 0398 after.insert(bands[band].First, QLatin1Char('-')); 0399 } 0400 0401 //add 1 since one "-" has already been inserted 0402 if(bands[band].Mid != 0) { 0403 hyphen2_position = bands[band].Mid; 0404 if(static_cast<int>(after.length()) > (hyphen2_position + 1)) { 0405 after.insert(hyphen2_position + 1, QLatin1Char('-')); 0406 } 0407 // or put back user's hyphen 0408 } else if(hyphen2_position > 0 && static_cast<int>(after.length()) >= (hyphen2_position + 1)) { 0409 after.insert(hyphen2_position + 1, QLatin1Char('-')); 0410 } 0411 0412 // add a "-" before the checkdigit and another one if the middle "-" exists 0413 int trueLast = bands[band].Last + 1 + (hyphen2_position > 0 ? 1 : 0); 0414 if(after.length() > trueLast) { 0415 after.insert(trueLast, QLatin1Char('-')); 0416 } 0417 input_ = input_.left(3) + QLatin1Char('-') + after; 0418 } 0419 0420 QChar ISBNValidator::checkSum10(const QString& input_) { 0421 uint sum = 0; 0422 uint multiplier = 10; 0423 0424 // hyphens are already gone, only use first nine digits 0425 for(int i = 0; i < input_.length() && multiplier > 1; ++i) { 0426 sum += input_[i].digitValue() * multiplier--; 0427 } 0428 sum %= 11; 0429 sum = 11-sum; 0430 0431 QChar c; 0432 if(sum == 10) { 0433 c = QLatin1Char('X'); 0434 } else if(sum == 11) { 0435 c = QLatin1Char('0'); 0436 } else { 0437 c = QString::number(sum)[0]; 0438 } 0439 return c; 0440 } 0441 0442 QChar ISBNValidator::checkSum13(const QString& input_) { 0443 uint sum = 0; 0444 0445 const int len = qMin(12, input_.length()); 0446 // hyphens are already gone, only use first twelve digits 0447 for(int i = 0; i < len; ++i) { 0448 sum += input_[i].digitValue() * (1 + 2*(i%2)); 0449 // multiplier goes 1, 3, 1, 3, etc... 0450 } 0451 sum %= 10; 0452 sum = 10-sum; 0453 0454 QChar c; 0455 if(sum == 10) { 0456 c = QLatin1Char('0'); 0457 } else { 0458 c = QString::number(sum)[0]; 0459 } 0460 return c; 0461 } 0462 0463 // ISBN code from Regis Boudin 0464 #define ISBNGRP_1DIGIT(digit, max, middle, last) \ 0465 {((digit)*100000000) + (max), 1, middle, last} 0466 #define ISBNGRP_2DIGIT(digit, max, middle, last) \ 0467 {((digit)*10000000) + ((max)/10), 2, middle, last} 0468 #define ISBNGRP_3DIGIT(digit, max, middle, last) \ 0469 {((digit)*1000000) + ((max)/100), 3, middle, last} 0470 #define ISBNGRP_4DIGIT(digit, max, middle, last) \ 0471 {((digit)*100000) + ((max)/1000), 4, middle, last} 0472 #define ISBNGRP_5DIGIT(digit, max, middle, last) \ 0473 {((digit)*10000) + ((max)/10000), 5, middle, last} 0474 0475 #define ISBNPUB_2DIGIT(grp) (((grp)+1)*1000000) 0476 #define ISBNPUB_3DIGIT(grp) (((grp)+1)*100000) 0477 #define ISBNPUB_4DIGIT(grp) (((grp)+1)*10000) 0478 #define ISBNPUB_5DIGIT(grp) (((grp)+1)*1000) 0479 #define ISBNPUB_6DIGIT(grp) (((grp)+1)*100) 0480 #define ISBNPUB_7DIGIT(grp) (((grp)+1)*10) 0481 #define ISBNPUB_8DIGIT(grp) (((grp)+1)*1) 0482 0483 // how to format an ISBN, after categorising it into a range of numbers. 0484 struct ISBNValidator::isbn_band ISBNValidator::bands[] = { 0485 /* Groups 0 & 1 : English */ 0486 ISBNGRP_1DIGIT(0, ISBNPUB_2DIGIT(19), 3, 9), 0487 ISBNGRP_1DIGIT(0, ISBNPUB_3DIGIT(699), 4, 9), 0488 ISBNGRP_1DIGIT(0, ISBNPUB_4DIGIT(8499), 5, 9), 0489 ISBNGRP_1DIGIT(0, ISBNPUB_5DIGIT(89999), 6, 9), 0490 ISBNGRP_1DIGIT(0, ISBNPUB_6DIGIT(949999), 7, 9), 0491 ISBNGRP_1DIGIT(0, ISBNPUB_7DIGIT(9999999), 8, 9), 0492 0493 ISBNGRP_1DIGIT(1, ISBNPUB_5DIGIT(54999), 6, 9), 0494 ISBNGRP_1DIGIT(1, ISBNPUB_5DIGIT(86979), 6, 9), 0495 ISBNGRP_1DIGIT(1, ISBNPUB_6DIGIT(998999), 7, 9), 0496 ISBNGRP_1DIGIT(1, ISBNPUB_7DIGIT(9999999), 8, 9), 0497 /* Group 2 : French */ 0498 ISBNGRP_1DIGIT(2, ISBNPUB_2DIGIT(19), 3, 9), 0499 ISBNGRP_1DIGIT(2, ISBNPUB_3DIGIT(349), 4, 9), 0500 ISBNGRP_1DIGIT(2, ISBNPUB_5DIGIT(39999), 6, 9), 0501 ISBNGRP_1DIGIT(2, ISBNPUB_3DIGIT(699), 4, 9), 0502 ISBNGRP_1DIGIT(2, ISBNPUB_4DIGIT(8399), 5, 9), 0503 ISBNGRP_1DIGIT(2, ISBNPUB_5DIGIT(89999), 6, 9), 0504 ISBNGRP_1DIGIT(2, ISBNPUB_6DIGIT(949999), 7, 9), 0505 ISBNGRP_1DIGIT(2, ISBNPUB_7DIGIT(9999999), 8, 9), 0506 0507 /* Group 2 : German */ 0508 ISBNGRP_1DIGIT(3, ISBNPUB_2DIGIT(19), 3, 9), 0509 ISBNGRP_1DIGIT(3, ISBNPUB_3DIGIT(699), 4, 9), 0510 ISBNGRP_1DIGIT(3, ISBNPUB_4DIGIT(8499), 5, 9), 0511 ISBNGRP_1DIGIT(3, ISBNPUB_5DIGIT(89999), 6, 9), 0512 ISBNGRP_1DIGIT(3, ISBNPUB_6DIGIT(949999), 7, 9), 0513 ISBNGRP_1DIGIT(3, ISBNPUB_7DIGIT(9999999), 8, 9), 0514 0515 ISBNGRP_1DIGIT(7, ISBNPUB_2DIGIT(99), 0, 9), 0516 /* Group 80 : Czech */ 0517 ISBNGRP_2DIGIT(80, ISBNPUB_2DIGIT(19), 4, 9), 0518 ISBNGRP_2DIGIT(80, ISBNPUB_3DIGIT(699), 5, 9), 0519 ISBNGRP_2DIGIT(80, ISBNPUB_4DIGIT(8499), 6, 9), 0520 ISBNGRP_2DIGIT(80, ISBNPUB_5DIGIT(89999), 7, 9), 0521 ISBNGRP_2DIGIT(80, ISBNPUB_6DIGIT(949999), 8, 9), 0522 0523 /* Group 83 : Poland */ 0524 ISBNGRP_2DIGIT(83, ISBNPUB_2DIGIT(19), 4, 9), 0525 ISBNGRP_2DIGIT(83, ISBNPUB_3DIGIT(599), 5, 9), 0526 ISBNGRP_2DIGIT(83, ISBNPUB_5DIGIT(69999), 7, 9), 0527 ISBNGRP_2DIGIT(83, ISBNPUB_4DIGIT(8499), 6, 9), 0528 ISBNGRP_2DIGIT(83, ISBNPUB_5DIGIT(89999), 7, 9), 0529 ISBNGRP_2DIGIT(83, ISBNPUB_6DIGIT(949999), 8, 9), 0530 0531 /* Group 90 * Netherlands */ 0532 ISBNGRP_2DIGIT(90, ISBNPUB_2DIGIT(19), 4, 9), 0533 ISBNGRP_2DIGIT(90, ISBNPUB_3DIGIT(499), 5, 9), 0534 ISBNGRP_2DIGIT(90, ISBNPUB_4DIGIT(6999), 6, 9), 0535 ISBNGRP_2DIGIT(90, ISBNPUB_5DIGIT(79999), 7, 9), 0536 ISBNGRP_2DIGIT(90, ISBNPUB_6DIGIT(849999), 8, 9), 0537 ISBNGRP_2DIGIT(90, ISBNPUB_4DIGIT(8999), 6, 9), 0538 ISBNGRP_2DIGIT(90, ISBNPUB_7DIGIT(9999999), 9, 9), 0539 0540 ISBNGRP_2DIGIT(94, ISBNPUB_2DIGIT(99), 0, 9), 0541 ISBNGRP_3DIGIT(993, ISBNPUB_2DIGIT(99), 0, 9), 0542 ISBNGRP_4DIGIT(9989, ISBNPUB_2DIGIT(99), 0, 9), 0543 ISBNGRP_5DIGIT(99999, ISBNPUB_2DIGIT(99), 0, 9) 0544 }; 0545 0546 bool Tellico::ISBNComparison::operator()(const QString& value1_, const QString& value2_) const { 0547 QString value1 = ISBNValidator::cleanValue(value1_).toUpper(); 0548 QString value2 = ISBNValidator::cleanValue(value2_).toUpper(); 0549 0550 if(value1 == value2) { 0551 return true; 0552 } 0553 const int len1 = value1.length(); 0554 const int len2 = value2.length(); 0555 if(len1 < 10 || len2 < 10) { 0556 // they're not ISBN values at all 0557 return false; 0558 } 0559 if(len1 == 13) { 0560 ISBNValidator::fixup13(value1); 0561 } else { 0562 value1 = ISBNValidator::isbn13(value1); 0563 } 0564 if(len2 == 13) { 0565 ISBNValidator::fixup13(value2); 0566 } else { 0567 value2 = ISBNValidator::isbn13(value2); 0568 } 0569 return value1 == value2; 0570 }