libxcks  0.1.0.1
xcksfilereader_1.cpp
Go to the documentation of this file.
1 /*
2  * libxcks
3  * Copyright (C) 2022 Julien Couot
4  *
5  * This program is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13  * License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
24 //---------------------------------------------------------------------------
25 #include <boost/locale.hpp>
26 #include <cassert>
27 
28 #include "xcksfilereader_1.hpp"
29 #include "libxcks/ckfactory.hpp"
30 #include "libxcks/xcksver.hpp"
31 #include "pathutil.hpp"
32 #include "strutil.hpp"
33 //---------------------------------------------------------------------------
34 
36 using namespace std;
37 
39 using namespace boost::locale;
40 
42 using namespace std::filesystem;
43 //---------------------------------------------------------------------------
44 
45 
46 namespace libxcks
47 {
60 static bool isFileNameIsInStringSet(const StringSet& set, const string& filename)
61 {
62  #if defined(_WIN32) || defined(_WIN64)
63  bool notFound = true;
64  StringSet::const_iterator it = set.cbegin();
65 
66  while (notFound && it != set.cend())
67  {
68  if (compareFileName(*it, filename) == 0)
69  notFound = false;
70  else
71  it++;
72  }
73  return !notFound;
74  #else
75  return (find(set.cbegin(), set.cend(), filename) != set.cend());
76  #endif // defined(_WIN32) || defined(_WIN64)
77 }
78 //---------------------------------------------------------------------------
79 
80 
82 const string XCKS1FileHandler::parentDir = "..";
83 //---------------------------------------------------------------------------
84 
85 
93 XCKS1FileHandler::XCKS1FileHandler(XCKSReaderHandler& handler,
94  const std::filesystem::path& baseDir) : readerHandler(handler),
95  baseDirectory(baseDir),
96  baseDirectoryDirs(getDirectories(baseDirectory)),
97  possibleSumsAlgosName(getAvailableAlgorithmNames(Version::V1_0_0))
98 {
99  assert(baseDir.is_absolute());
103 }
104 //---------------------------------------------------------------------------
105 
106 
111 {
112 }
113 //---------------------------------------------------------------------------
114 
115 
124 {
125  if (str == "checksum")
126  return XMLTags::CHECKSUM;
127  else if (str == "file")
128  return XMLTags::FILE;
129  else if (str == "information")
130  return XMLTags::INFORMATION;
131  else if (str == "directory")
132  return XMLTags::DIRECTORY;
133  else if (str == "parentDirectory")
135  else if (str == "algorithm")
136  return XMLTags::ALGORITHM;
137  else if (str== "algorithms")
138  return XMLTags::ALGORITHMS;
139  else if (str == "localFiles")
140  return XMLTags::LOCALFILES;
141  else if (str == "generated")
142  return XMLTags::GENERATED;
143  else if (str == "checksumsFile")
144  return XMLTags::CHECKSUMSFILE;
145  else
146  return XMLTags::BAD_TAG;
147 }
148 //---------------------------------------------------------------------------
149 
150 
156 inline void XCKS1FileHandler::startGeneratedElement(const XMLParserAttributes& atts) noexcept(false)
157 {
158  if ((readTags.top() == XMLTags::CHECKSUMSFILE) && (tagInChecksumsFileTag == XMLTags::SEQ_BEGIN))
159  {
160  if (atts.getCount() == 3)
161  {
162  int byIdx = atts.getIndex("by"),
163  versionIdx = atts.getIndex("version"),
164  onIdx = atts.getIndex("on");
166  {
167  time_t on;
168  string onStr;
169  atts.getValue(onIdx, onStr);
170  if ((on = parseISO8601(onStr)) != Invalid_DateTime)
171  {
172  tagInChecksumsFileTag = XMLTags::GENERATED;
173  readTags.push(XMLTags::GENERATED);
174  string by, version;
175  atts.getValue(byIdx, by);
176  atts.getValue(versionIdx, version);
177  readerHandler.onGenerated(by, version, on);
178  }
179  else
180  {
181  throw XMLParserException(translate("The date/time of the creation of the checksums' file is invalid.").str(libxcks_domain));
182  }
183  }
184  else
185  {
186  throw XMLParserException(translate("The \"generated\" tag must have \"by\", \"version\", and \"on\" attributes.").str(libxcks_domain));
187  }
188  }
189  else
190  {
191  throw XMLParserException(translate("The \"generated\" tag must have \"by\", \"version\", and \"on\" attributes.").str(libxcks_domain));
192  }
193  }
194  else
195  {
196  throw XMLParserException(translate("Unexpected \"generated\" tag.").str(libxcks_domain));
197  }
198 }
199 //---------------------------------------------------------------------------
200 
201 
207 inline void XCKS1FileHandler::startAlgorithmsElement(const XMLParserAttributes& atts) noexcept(false)
208 {
209  if ((readTags.top() == XMLTags::CHECKSUMSFILE) &&
210  ((tagInChecksumsFileTag == XMLTags::SEQ_BEGIN) || (tagInChecksumsFileTag == XMLTags::GENERATED)))
211  {
212  if (atts.getCount() == 0)
213  {
214  tagInChecksumsFileTag = XMLTags::ALGORITHMS;
215  readTags.push(XMLTags::ALGORITHMS);
216  readerHandler.onAlgorithmsStart();
217  }
218  else
219  {
220  throw XMLParserException(translate("The \"algorithms\" tag mustn't have any attribute.").str(libxcks_domain));
221  }
222  }
223  else
224  {
225  throw XMLParserException(translate("Unexpected \"algorithms\" tag.").str(libxcks_domain));
226  }
227 }
228 //---------------------------------------------------------------------------
229 
230 
236 inline void XCKS1FileHandler::startAlgorithmElement(const XMLParserAttributes& atts) noexcept(false)
237 {
238  if (readTags.top() == XMLTags::ALGORITHMS)
239  {
240  if (atts.getCount() == 1)
241  {
242  string type;
243  if (atts.getValue("type", type))
244  {
245  if (possibleSumsAlgosName.find(type) != possibleSumsAlgosName.end())
246  {
247  ChecksumAlgoId ckId;
248  if (ChecksumFactory::getAlgorithmId(ckId, type, true))
249  {
250  if (find(sumsAlgos.cbegin(), sumsAlgos.cend(), ckId) == sumsAlgos.cend())
251  {
252  sumsAlgos.push_back(ckId);
253  readTags.push(XMLTags::ALGORITHM);
254  readerHandler.onAlgorithm(ckId);
255  }
256  else
257  {
258  throw XMLParserException((format(translate("The algorithm \"{1}\" has already been declared.").str(libxcks_domain)) % type).str());
259  }
260  }
261  else
262  {
263  throw XMLParserException((format(translate("This release doesn't support this checksum algorithm: {1}").str(libxcks_domain)) % type).str());
264  }
265  }
266  else
267  {
268  throw XMLParserException((format(translate("Invalid checksum's algorithm name: {1}.").str(libxcks_domain)) % type).str());
269  }
270  }
271  else
272  {
273  throw XMLParserException(translate("The \"algorithm\" tag must have a \"type\" attribute.").str(libxcks_domain));
274  }
275  }
276  else
277  {
278  throw XMLParserException(translate("The \"algorithm\" tag has only one attribute: \"type\" (which is mandatory).").str(libxcks_domain));
279  }
280  }
281  else
282  {
283  throw XMLParserException(translate("Unexpected \"algorithm\" tag.").str(libxcks_domain));
284  }
285 }
286 //---------------------------------------------------------------------------
287 
288 
294 inline void XCKS1FileHandler::startLocalFilesElement(const XMLParserAttributes& atts) noexcept(false)
295 {
296  if ((readTags.top() == XMLTags::CHECKSUMSFILE) && (tagInChecksumsFileTag == XMLTags::ALGORITHMS))
297  {
298  if (atts.getCount() == 0)
299  {
300  namesInDirectories.emplace(StringSet());
301  tagInChecksumsFileTag = XMLTags::LOCALFILES;
302  readTags.push(XMLTags::LOCALFILES);
303  readerHandler.onLocalFilesStart();
304  }
305  else
306  {
307  throw XMLParserException(translate("The \"localFiles\" tag mustn't have any attribute.").str(libxcks_domain));
308  }
309  }
310  else
311  {
312  throw XMLParserException(translate("Unexpected \"localFiles\" tag.").str(libxcks_domain));
313  }
314 }
315 //---------------------------------------------------------------------------
316 
317 
324 {
325  if ((readTags.top() == XMLTags::LOCALFILES) || (readTags.top() == XMLTags::PARENTDIRECTORY))
326  {
327  if (atts.getCount() == 0)
328  {
329  StringSet& filesAndDirsInDir = namesInDirectories.top();
330  if (!isFileNameIsInStringSet(filesAndDirsInDir, parentDir))
331  {
332  if (curBaseDirectoryDir >= 0)
333  {
334  filesAndDirsInDir.emplace(parentDir);
335  currentRelativeDirectory.emplace_back(parentDir); // works on Windows and Unix
336  namesInDirectories.emplace(StringSet());
337  namesInDirectories.top().emplace(from_u8string(baseDirectoryDirs[curBaseDirectoryDir].u8string()));
338  curBaseDirectoryDir--;
339  readTags.push(XMLTags::PARENTDIRECTORY);
340  readerHandler.onParentDirectoryStart();
341  readerHandler.onParentDirectoryStart(ensureEndsWithPathSeparator((baseDirectory / constructPath(currentRelativeDirectory)).lexically_normal()));
342  }
343  else
344  {
345  throw XMLParserException(translate("Want to go the parent directory, but we are at the root of the current volume.").str(libxcks_domain));
346  }
347  }
348  else
349  {
350  throw XMLParserException(translate("There is already a parent directory element in the current directory.").str(libxcks_domain));
351  }
352  }
353  else
354  {
355  throw XMLParserException(translate("The \"parentDirectory\" tag mustn't have any attribute.").str(libxcks_domain));
356  }
357  }
358  else
359  {
360  throw XMLParserException(translate("Unexpected \"parentDirectory\" tag.").str(libxcks_domain));
361  }
362 }
363 //---------------------------------------------------------------------------
364 
365 
371 inline void XCKS1FileHandler::startDirectoryElement(const XMLParserAttributes& atts) noexcept(false)
372 {
373  if ((readTags.top() == XMLTags::LOCALFILES) ||
374  (readTags.top() == XMLTags::PARENTDIRECTORY) ||
375  (readTags.top() == XMLTags::DIRECTORY))
376  {
377  if (atts.getCount() == 1)
378  {
379  string name;
380  if (atts.getValue("name", name))
381  {
382  if (isFileNameValid(name))
383  {
384  StringSet& filesAndDirsInDir = namesInDirectories.top();
385  if (!isFileNameIsInStringSet(filesAndDirsInDir, name))
386  {
387  filesAndDirsInDir.emplace(name);
388  namesInDirectories.emplace(StringSet());
389  currentRelativeDirectory.emplace_back(name);
390  readTags.push(XMLTags::DIRECTORY);
391  readerHandler.onDirectoryStart(name);
392  readerHandler.onDirectoryStart(ensureEndsWithPathSeparator((baseDirectory / constructPath(currentRelativeDirectory)).lexically_normal()));
393  }
394  else
395  {
396  throw XMLParserException((format(translate("There is already a file or a directory with the name \"{1}\" in the current directory.").str(libxcks_domain)) % name).str());
397  }
398  }
399  else
400  {
401  throw XMLParserException((format(translate("Invalid directory name: {1}.").str(libxcks_domain)) % name).str());
402  }
403  }
404  else
405  {
406  throw XMLParserException(translate("The \"directory\" tag must have a \"name\" attribute.").str(libxcks_domain));
407  }
408  }
409  else
410  {
411  throw XMLParserException(translate("The \"directory\" tag has only one attribute: \"name\" (which is mandatory).").str(libxcks_domain));
412  }
413  }
414  else
415  {
416  throw XMLParserException(translate("Unexpected \"directory\" tag.").str(libxcks_domain));
417  }
418 }
419 //---------------------------------------------------------------------------
420 
421 
427 inline void XCKS1FileHandler::startFileElement(const XMLParserAttributes& atts) noexcept(false)
428 {
429  if ((readTags.top() == XMLTags::LOCALFILES) ||
430  (readTags.top() == XMLTags::PARENTDIRECTORY) ||
431  (readTags.top() == XMLTags::DIRECTORY))
432  {
433  if (atts.getCount() == 1)
434  {
435  string name;
436  if (atts.getValue("name", name))
437  {
438  if (isFileNameValid(name))
439  {
440  StringSet& filesAndDirsInDir = namesInDirectories.top();
441  if (!isFileNameIsInStringSet(filesAndDirsInDir, name))
442  {
443  filesAndDirsInDir.emplace(name);
444  fileName = name;
445  tagInFileTag = XMLTags::SEQ_BEGIN;
446  fileLength = Invalid_File_Size;
447  lastFileModicationTime = Invalid_DateTime;
448  readChecksumsValues.clear();
449  algosToRead = sumsAlgos;
450  readTags.push(XMLTags::FILE);
451  readerHandler.onFileStart(fileName);
452  readerHandler.onFileStart((baseDirectory / constructPath(currentRelativeDirectory, fileName)).lexically_normal());
453  }
454  else
455  {
456  throw XMLParserException((format(translate("There is already a file or a directory with the name \"{1}\" in the current directory.").str(libxcks_domain)) % name).str());
457  }
458  }
459  else
460  {
461  throw XMLParserException((format(translate("Invalid file name: {1}.").str(libxcks_domain)) % name).str());
462  }
463  }
464  else
465  {
466  throw XMLParserException(translate("The \"file\" tag must have a \"name\" attribute.").str(libxcks_domain));
467  }
468  }
469  else
470  {
471  throw XMLParserException(translate("The \"file\" tag has only one attribute: \"name\" (which is mandatory).").str(libxcks_domain));
472  }
473  }
474  else
475  {
476  throw XMLParserException(translate("Unexpected \"file\" tag.").str(libxcks_domain));
477  }
478 }
479 //---------------------------------------------------------------------------
480 
481 
487 inline void XCKS1FileHandler::startInformationElement(const XMLParserAttributes& atts) noexcept(false)
488 {
489  if ((readTags.top() == XMLTags::FILE) && (tagInFileTag == XMLTags::SEQ_BEGIN))
490  {
491  if (atts.getCount() >= 0 && atts.getCount() <= 2)
492  {
493  string fileSize, fileDate;
494  for (size_t i = 0; i < atts.getCount(); i++)
495  {
496  string attName;
497  atts.getName(i, attName);
498  if (attName == "size")
499  atts.getValue(i, fileSize);
500  else if (attName == "date")
501  atts.getValue(i, fileDate);
502  else
503  throw XMLParserException((format(translate("Invalid attribute \"{1}\" for the \"information\" tag (valid values are \"size\" and \"date\").").str(libxcks_domain)) % attName).str());
504  }
505  if (!fileSize.empty())
506  {
507  bool ok = true;
508  try
509  {
510  unsigned long long fs = stoull(fileSize);
511  fileLength = static_cast<uintmax_t>(fs);
512  }
513  catch (logic_error&)
514  {
515  ok = false;
516  }
517  if (!ok)
518  throw XMLParserException((format(translate("The \"size\" attribute of the \"information\" tag has an invalid value: {1}.").str(libxcks_domain)) % fileSize).str());
519  }
520  if (!fileDate.empty())
521  if ((lastFileModicationTime = parseISO8601(fileDate)) == Invalid_DateTime)
522  throw XMLParserException((format(translate("The \"date\" attribute of the \"information\" tag has an invalid value: {1}.").str(libxcks_domain)) % fileDate).str());
523 
524  tagInFileTag = XMLTags::INFORMATION;
525  readTags.push(XMLTags::INFORMATION);
526  readerHandler.onFileInformation(fileLength, lastFileModicationTime);
527  }
528  else
529  {
530  throw XMLParserException(translate("The \"information\" tag could have none, one or two attributes.").str(libxcks_domain));
531  }
532  }
533  else
534  {
535  throw XMLParserException(translate("Unexpected \"information\" tag.").str(libxcks_domain));
536  }
537 }
538 //---------------------------------------------------------------------------
539 
540 
546 inline void XCKS1FileHandler::startChecksumElement(const XMLParserAttributes& atts) noexcept(false)
547 {
548  if ((readTags.top() == XMLTags::FILE) &&
549  ((tagInFileTag == XMLTags::SEQ_BEGIN) || (tagInFileTag == XMLTags::INFORMATION)))
550  {
551  if (!sumsAlgos.empty())
552  {
553  if (atts.getCount() == 2)
554  {
555  string type;
556  string value;
557  for (size_t i = 0; i < atts.getCount(); i++)
558  {
559  string attName;
560  atts.getName(i, attName);
561  if (attName == "type")
562  atts.getValue(i, type);
563  else if (attName == "value")
564  atts.getValue(i, value);
565  else
566  throw XMLParserException((format(translate("Invalid attribute \"{1}\" for the \"checksum\" tag (valid values are \"type\" and \"value\").").str(libxcks_domain)) % attName).str());
567  }
568 
569  if (possibleSumsAlgosName.find(type) != possibleSumsAlgosName.end())
570  {
571  ChecksumAlgoId ckId;
572  if (ChecksumFactory::getAlgorithmId(ckId, type, true))
573  {
574  if (!hasChecksumValueWithAlgoId(readChecksumsValues, ckId))
575  {
576  ArrayChecksumAlgoId::const_iterator itCkId;
577  if ((itCkId = find(algosToRead.cbegin(), algosToRead.cend(), ckId)) != algosToRead.cend())
578  {
579  ChecksumValue ckv(value, ckId);
581  if (ckv.getSize() == c.getSize())
582  {
583  readChecksumsValues.emplace_back(ckv);
584  algosToRead.erase(itCkId);
585  readTags.push(XMLTags::CHECKSUM);
586  readerHandler.onFileChecksum(ckv);
587  }
588  else
589  {
590  throw XMLParserException((format(translate("The value \"{1}\" of the checksum algorithm \"{2}\" is invalid.").str(libxcks_domain)) % value % type).str());
591  }
592  }
593  else
594  {
595  throw XMLParserException((format(translate("The algorithm \"{1}\" isn't present in the algorithms of the checksums' file.").str(libxcks_domain)) % type).str());
596  }
597  }
598  else
599  {
600  throw XMLParserException((format(translate("The algorithm \"{1}\" has been already read once for the file \"{2}\".").str(libxcks_domain)) % type % fileName).str());
601  }
602  }
603  else
604  {
605  throw XMLParserException((format(translate("This release doesn't support this checksum algorithm: {1}").str(libxcks_domain)) % type).str());
606  }
607  }
608  else
609  {
610  throw XMLParserException((format(translate("Invalid checksum's algorithm name: {1}.").str(libxcks_domain)) % type).str());
611  }
612  }
613  else
614  {
615  throw XMLParserException(translate("The \"algorithm\" tag has only one attribute: \"type\" (which is mandatory).").str(libxcks_domain));
616  }
617  }
618  else
619  {
620  throw XMLParserException((format(translate("The file \"{1}\" has already all its checkums.").str(libxcks_domain)) % fileName).str());
621  }
622  }
623  else
624  {
625  throw XMLParserException(translate("Unexpected \"checksum\" tag.").str(libxcks_domain));
626  }
627 }
628 //---------------------------------------------------------------------------
629 
630 
637 void XCKS1FileHandler::startElement(const string& name, const XMLParserAttributes& atts) noexcept(false)
638 {
639  XMLTags curTag = stringToXMLTags(name);
640  switch (curTag)
641  {
642  case XMLTags::GENERATED :
643  startGeneratedElement(atts);
644  break;
645 
646  case XMLTags::ALGORITHMS :
647  startAlgorithmsElement(atts);
648  break;
649 
650  case XMLTags::ALGORITHM :
651  startAlgorithmElement(atts);
652  break;
653 
654  case XMLTags::LOCALFILES :
655  startLocalFilesElement(atts);
656  break;
657 
658  case XMLTags::PARENTDIRECTORY :
659  startParentDirectoryElement(atts);
660  break;
661 
662  case XMLTags::DIRECTORY :
663  startDirectoryElement(atts);
664  break;
665 
666  case XMLTags::FILE :
667  startFileElement(atts);
668  break;
669 
670  case XMLTags::INFORMATION :
671  startInformationElement(atts);
672  break;
673 
674  case XMLTags::CHECKSUM :
675  startChecksumElement(atts);
676  break;
677 
678  default :
679  throw XMLParserException((format(translate("Unexpected tag (\"{1}\").").str(libxcks_domain)) % name).str());
680  }
681 }
682 //---------------------------------------------------------------------------
683 
684 
690 inline void XCKS1FileHandler::endFileElement() noexcept(false)
691 {
692  // Checks the number of read checksums for the file
693  if (!algosToRead.empty())
694  {
695  string algoName;
697  throw XMLParserException((format(translate("Missing checksum for \"{1}\" algorithm.").str(libxcks_domain)) % algoName).str());
698  }
699 
703 
704  fileName.clear();
705  /*tagInFileTag = XMLTags::SEQ_BEGIN;
706  fileLength = Invalid_File_Size;
707  lastFileModicationTime = Invalid_DateTime;*/
708  readChecksumsValues.clear();
709  algosToRead.clear();
710 }
711 //---------------------------------------------------------------------------
712 
713 
719 void XCKS1FileHandler::endElement(const string& name) noexcept(false)
720 {
721  XMLTags curTag = stringToXMLTags(name);
722  if (curTag != readTags.top())
723  throw XMLParserException((format(translate("Mismatching tag: \"{1}\".").str(libxcks_domain)) % name).str());
724  else
725  {
726  switch (curTag)
727  {
728  case XMLTags::GENERATED :
729  // Nothing to do
730  break;
731 
732  case XMLTags::ALGORITHMS :
733  readerHandler.onAlgorithmsEnd();
734  if (sumsAlgos.empty())
735  throw XMLParserException(translate("The checksums' file must specify at least one algorithm.").str(libxcks_domain));
736  else
737  {
738  readerHandler.onAlgorithms(sumsAlgos);
739  }
740  break;
741 
742  case XMLTags::ALGORITHM :
743  // Nothing to do
744  break;
745 
746  case XMLTags::LOCALFILES :
747  if (namesInDirectories.size() != 1)
748  {
749  throw XMLParserException((format("There should be only one list of filenames to pop, but there is {1}. This shouldn't happen.") % namesInDirectories.size()).str());
750  }
751  else
752  {
753  namesInDirectories.pop();
754  readerHandler.onLocalFilesEnd();
755  }
756  break;
757 
758  case XMLTags::PARENTDIRECTORY :
759  curBaseDirectoryDir++;
760  if (curBaseDirectoryDir >= static_cast<ssize_t>(baseDirectoryDirs.size()))
761  {
762  throw XMLParserException("Pointer to current directory of new checksums' file is out of bounds. This shouldn't happen.");
763  }
764  readerHandler.onParentDirectoryEnd();
765  // no break here
766  case XMLTags::DIRECTORY :
767  if (namesInDirectories.empty())
768  {
769  throw XMLParserException("There is no list of filenames to pop. This shouldn't happen.");
770  }
771  else
772  {
773  if (namesInDirectories.top().empty())
774  {
775  throw XMLParserException(translate("The directory is empty, it's forbidden by the XCKS file's specification.").str(libxcks_domain));
776  }
777  else
778  {
779  namesInDirectories.pop();
780  }
781  }
782  if (currentRelativeDirectory.empty())
783  {
784  throw XMLParserException("There is no directory to pop in the directories' list. This shouldn't happen.");
785  }
786  else
787  {
788  currentRelativeDirectory.pop_back();
789  }
790  if (curTag == XMLTags::DIRECTORY) // case shared with XMLTags::PARENTDIRECTORY
791  readerHandler.onDirectoryEnd();
792  break;
793 
794  case XMLTags::FILE :
795  endFileElement();
796  break;
797 
798  case XMLTags::INFORMATION :
799  // Nothing to do
800  break;
801 
802  case XMLTags::CHECKSUM :
803  // Nothing to do
804  break;
805 
806  default :
807  throw XMLParserException((format(translate("Mismatching tag: \"{1}\".").str(libxcks_domain)) % name).str());
808  }
809 
810  readTags.pop();
811  }
812 }
813 //---------------------------------------------------------------------------
814 
815 
821 void XCKS1FileHandler::characters(const string& chars) noexcept(false)
822 {
823  string s = trim_copy(chars);
824  if (!s.empty())
825  throw XMLParserException(translate("The file cannot contains characters between tags.").str(libxcks_domain));
826 }
827 //---------------------------------------------------------------------------
828 
829 
838 void XCKS1FileHandler::fatalError(XML_Error errorCode, const string& errorMessage, int line, int column) noexcept
839 {
840  readerHandler.onFatalError(errorMessage, line, column);
841 }
842 //---------------------------------------------------------------------------
843 } // namespace libxcks
844 //---------------------------------------------------------------------------
Classes for enumerate and create all the checksums' algorithms that the application knows.
bool LIBXCKS_SO_EXPORT hasChecksumValueWithAlgoId(const ArrayChecksumValue &ckvalues, const ChecksumAlgoId type)
Checks if the array as a value of the given type.
Definition: ckvalue.cpp:456
static ChecksumValue getNullValue(const ChecksumAlgoId id)
Gives null value of the specified checksum or hash identifier.
Definition: ckfactory.cpp:327
static bool getAlgorithmId(ChecksumAlgoId &id, const std::string &name, const bool lookInAltNames=true)
Gets the identifier of a checksum or hash algorithm from its name.
Definition: ckfactory.cpp:518
static bool getAlgorithmName(std::string &name, const ChecksumAlgoId id)
Gets the name of a checksum or hash algorithm from its identifier.
Definition: ckfactory.cpp:617
Stores the value of a checksum.
Definition: ckvalue.hpp:45
size_t getSize() const
Gets the size of the checksum's value.
Definition: ckvalue.cpp:424
void startDirectoryElement(const XMLParserAttributes &atts) noexcept(false)
Receives notification of the beginning of a "directory" element.
virtual ~XCKS1FileHandler()
Destructor.
ArrayChecksumValue readChecksumsValues
Read checksums values.
void fatalError(XML_Error errorCode, const std::string &errorMessage, int line, int column) noexcept override
Receive notification of a non-recoverable error.
void startLocalFilesElement(const XMLParserAttributes &atts) noexcept(false)
Receives notification of the beginning of a "localFiles" element.
XMLTags tagInChecksumsFileTag
Current tag in "checksumsFile" tag.
void startElement(const std::string &name, const XMLParserAttributes &atts) noexcept(false) override
Receives notification of the beginning of an element.
void endFileElement() noexcept(false)
Receives notification of the end of a "file" element.
void startGeneratedElement(const XMLParserAttributes &atts) noexcept(false)
Receives notification of the beginning of a "generated" element.
ArrayChecksumAlgoId algosToRead
Remaining algorithms to read for a file.
ssize_t curBaseDirectoryDir
Current directory in the base directory of the checksums' file name.
uintmax_t fileLength
The current file size.
std::string fileName
Name of checksums' file.
time_t lastFileModicationTime
The current last file modification time.
std::stack< XMLTags > readTags
Stack of read tags.
void startFileElement(const XMLParserAttributes &atts) noexcept(false)
Receives notification of the beginning of a "file" element.
void startAlgorithmElement(const XMLParserAttributes &atts) noexcept(false)
Receives notification of the beginning of a "algorithm" element.
@ SEQ_BEGIN
Beginning of a sequence.
@ CHECKSUMSFILE
checksumsFile element
@ PARENTDIRECTORY
parentDirectory element
@ INFORMATION
information element
void startChecksumElement(const XMLParserAttributes &atts) noexcept(false)
Receives notification of the beginning of a "checksum" element.
ArrayString currentRelativeDirectory
The current relative directory.
void startAlgorithmsElement(const XMLParserAttributes &atts) noexcept(false)
Receives notification of the beginning of a "algorithms" element.
void characters(const std::string &chars) noexcept(false) override
Receives notification of character data.
XMLTags stringToXMLTags(const std::string &str)
Gets a XML tag identifier from a string.
void startParentDirectoryElement(const XMLParserAttributes &atts) noexcept(false)
Receives notification of the beginning of a "parentDirectory" element.
const std::filesystem::path baseDirectory
The base directory of the checksums' file.
void startInformationElement(const XMLParserAttributes &atts) noexcept(false)
Receives notification of the beginning of a "information" element.
void endElement(const std::string &name) noexcept(false) override
Receives notification of the end of an element.
const std::vector< std::filesystem::path > baseDirectoryDirs
The base directory of the checksums' file directories.
XCKSReaderHandler & readerHandler
The XCKS file reader handler.
Handler for reading XCKS files.
Definition: handlers.hpp:50
virtual void onFile(const std::filesystem::path &path, const ArrayChecksumValue &checksums, const uintmax_t size=Invalid_File_Size, const time_t date=Invalid_DateTime)=0
Called on read file element.
virtual void onFileEnd()=0
Called on read file end tag.
Manages elements' attributes.
Definition: xmlparser.hpp:84
static constexpr int Not_Found
Not found index.
Definition: xmlparser.hpp:90
An exception class for the XML parser.
Definition: xmlparser.hpp:42
constexpr const char * libxcks_domain
Domain for translations (i18n).
Definition: defs.hpp:47
constexpr std::uintmax_t Invalid_File_Size
Invalid file size.
Definition: defs.hpp:37
constexpr std::time_t Invalid_DateTime
Invalid date/time.
Definition: defs.hpp:42
bool isFileNameValid(const std::string &filename)
Checks if the name of the file is valid.
Definition: pathutil.cpp:266
std::vector< std::filesystem::path > getDirectories(const std::filesystem::path &p)
Gets directories of a path.
Definition: pathutil.cpp:64
int compareFileName(const std::string &fn1, const std::string &fn2)
Compares two file names.
Definition: pathutil.cpp:108
std::filesystem::path constructPath(const ArrayString &dirs, const std::string &filename)
Constructs a path from an array of directories and an optional filename.
Definition: pathutil.cpp:170
std::filesystem::path ensureEndsWithPathSeparator(const std::filesystem::path &p)
Ensures the path ends with a path separator.
Definition: pathutil.cpp:209
Path utilities.
std::string trim_copy(std::string s)
Trim from both ends (copying).
Definition: strutil.cpp:123
time_t parseISO8601(const std::string &iso8601)
Parse ISO 8601 date/time.
Definition: strutil.cpp:265
std::string from_u8string(const std::string &s)
Returns an UTF-8 encoded string in an object of type std::string (C++17).
Definition: strutil.cpp:217
String utilities.
ChecksumAlgoId
Ids of algorithms of checksums.
Definition: types.hpp:65
Version
Known versions of XCKS file.
Definition: types.hpp:55
@ V1_0_0
Version 1.0.0.
std::set< std::string > StringSet
Set of strings.
Definition: types.hpp:39
Classes that read a XCKS file version 1.
Versions of (Z)XCKS files.
LIBXCKS_SO_EXPORT const StringSet getAvailableAlgorithmNames(const Version version)
Gets the available names of algorithm for a version of (Z)XCKS file.
Definition: xcksver.cpp:41