]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
debListParser: Micro-optimize AvailableDescriptionLanguages()
[apt.git] / apt-pkg / deb / deblistparser.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: deblistparser.cc,v 1.29.2.5 2004/01/06 01:43:44 mdz Exp $
4 /* ######################################################################
5
6 Package Cache Generator - Generator for the cache structure.
7
8 This builds the cache structure from the abstract package list parser.
9
10 ##################################################################### */
11 /*}}}*/
12 // Include Files /*{{{*/
13 #include <config.h>
14
15 #include <apt-pkg/deblistparser.h>
16 #include <apt-pkg/error.h>
17 #include <apt-pkg/configuration.h>
18 #include <apt-pkg/cachefilter.h>
19 #include <apt-pkg/aptconfiguration.h>
20 #include <apt-pkg/strutl.h>
21 #include <apt-pkg/crc-16.h>
22 #include <apt-pkg/md5.h>
23 #include <apt-pkg/pkgcache.h>
24 #include <apt-pkg/cacheiterators.h>
25 #include <apt-pkg/tagfile.h>
26 #include <apt-pkg/tagfile-keys.h>
27 #include <apt-pkg/macros.h>
28
29 #include <stddef.h>
30 #include <string.h>
31 #include <algorithm>
32 #include <string>
33 #include <vector>
34 #include <ctype.h>
35 /*}}}*/
36
37 using std::string;
38 using APT::StringView;
39
40 static const debListParser::WordList PrioList[] = {
41 {"required",pkgCache::State::Required},
42 {"important",pkgCache::State::Important},
43 {"standard",pkgCache::State::Standard},
44 {"optional",pkgCache::State::Optional},
45 {"extra",pkgCache::State::Extra},
46 {"", 0}};
47
48 // ListParser::debListParser - Constructor /*{{{*/
49 // ---------------------------------------------------------------------
50 /* Provide an architecture and only this one and "all" will be accepted
51 in Step(), if no Architecture is given we will accept every arch
52 we would accept in general with checkArchitecture() */
53 debListParser::debListParser(FileFd *File) :
54 pkgCacheListParser(), Tags(File)
55 {
56 // this dance allows an empty value to override the default
57 if (_config->Exists("pkgCacheGen::ForceEssential"))
58 {
59 forceEssential = _config->FindVector("pkgCacheGen::ForceEssential");
60 if (forceEssential.empty() == false && _config->Find("pkgCacheGen::ForceEssential").empty())
61 forceEssential.emplace_back("apt");
62 }
63 else
64 forceEssential.emplace_back("apt");
65 forceImportant = _config->FindVector("pkgCacheGen::ForceImportant");
66 }
67 /*}}}*/
68 // ListParser::Package - Return the package name /*{{{*/
69 // ---------------------------------------------------------------------
70 /* This is to return the name of the package this section describes */
71 string debListParser::Package() {
72 string Result = Section.Find(pkgTagSection::Key::Package).to_string();
73
74 // Normalize mixed case package names to lower case, like dpkg does
75 // See Bug#807012 for details
76 std::transform(Result.begin(), Result.end(), Result.begin(), tolower_ascii);
77
78 if(unlikely(Result.empty() == true))
79 _error->Error("Encountered a section with no Package: header");
80 return Result;
81 }
82 /*}}}*/
83 // ListParser::Architecture - Return the package arch /*{{{*/
84 // ---------------------------------------------------------------------
85 /* This will return the Architecture of the package this section describes */
86 APT::StringView debListParser::Architecture() {
87 auto const Arch = Section.Find(pkgTagSection::Key::Architecture);
88 return Arch.empty() ? "none" : Arch;
89 }
90 /*}}}*/
91 // ListParser::ArchitectureAll /*{{{*/
92 // ---------------------------------------------------------------------
93 /* */
94 bool debListParser::ArchitectureAll() {
95 return Section.Find(pkgTagSection::Key::Architecture) == "all";
96 }
97 /*}}}*/
98 // ListParser::Version - Return the version string /*{{{*/
99 // ---------------------------------------------------------------------
100 /* This is to return the string describing the version in debian form,
101 epoch:upstream-release. If this returns the blank string then the
102 entry is assumed to only describe package properties */
103 APT::StringView debListParser::Version()
104 {
105 return Section.Find(pkgTagSection::Key::Version);
106 }
107 /*}}}*/
108 unsigned char debListParser::ParseMultiArch(bool const showErrors) /*{{{*/
109 {
110 unsigned char MA;
111 auto const MultiArch = Section.Find(pkgTagSection::Key::Multi_Arch);
112 if (MultiArch.empty() == true || MultiArch == "no")
113 MA = pkgCache::Version::No;
114 else if (MultiArch == "same") {
115 if (ArchitectureAll() == true)
116 {
117 if (showErrors == true)
118 _error->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
119 Section.FindS("Package").c_str());
120 MA = pkgCache::Version::No;
121 }
122 else
123 MA = pkgCache::Version::Same;
124 }
125 else if (MultiArch == "foreign")
126 MA = pkgCache::Version::Foreign;
127 else if (MultiArch == "allowed")
128 MA = pkgCache::Version::Allowed;
129 else
130 {
131 if (showErrors == true)
132 _error->Warning("Unknown Multi-Arch type '%s' for package '%s'",
133 MultiArch.to_string().c_str(), Section.FindS("Package").c_str());
134 MA = pkgCache::Version::No;
135 }
136
137 if (ArchitectureAll() == true)
138 MA |= pkgCache::Version::All;
139
140 return MA;
141 }
142 /*}}}*/
143 // ListParser::NewVersion - Fill in the version structure /*{{{*/
144 // ---------------------------------------------------------------------
145 /* */
146 bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
147 {
148 const char *Start;
149 const char *Stop;
150
151 // Parse the section
152 if (Section.Find(pkgTagSection::Key::Section,Start,Stop) == true)
153 {
154 map_stringitem_t const idx = StoreString(pkgCacheGenerator::SECTION, Start, Stop - Start);
155 Ver->Section = idx;
156 }
157 // Parse the source package name
158 pkgCache::GrpIterator G = Ver.ParentPkg().Group();
159 Ver->SourcePkgName = G->Name;
160 Ver->SourceVerStr = Ver->VerStr;
161 if (Section.Find(pkgTagSection::Key::Source,Start,Stop) == true)
162 {
163 const char * const Space = (const char * const) memchr(Start, ' ', Stop - Start);
164 pkgCache::VerIterator V;
165
166 if (Space != NULL)
167 {
168 const char * const Open = (const char * const) memchr(Space, '(', Stop - Space);
169 if (likely(Open != NULL))
170 {
171 const char * const Close = (const char * const) memchr(Open, ')', Stop - Open);
172 if (likely(Close != NULL))
173 {
174 APT::StringView const version(Open + 1, (Close - Open) - 1);
175 if (version != Ver.VerStr())
176 {
177 map_stringitem_t const idx = StoreString(pkgCacheGenerator::VERSIONNUMBER, version);
178 G = Ver.ParentPkg().Group();
179 Ver->SourceVerStr = idx;
180 }
181 }
182 }
183 Stop = Space;
184 }
185
186 APT::StringView const pkgname(Start, Stop - Start);
187 if (pkgname != G.Name())
188 {
189 for (pkgCache::PkgIterator P = G.PackageList(); P.end() == false; P = G.NextPkg(P))
190 {
191 for (V = P.VersionList(); V.end() == false; ++V)
192 {
193 if (pkgname == V.SourcePkgName())
194 {
195 Ver->SourcePkgName = V->SourcePkgName;
196 break;
197 }
198 }
199 if (V.end() == false)
200 break;
201 }
202 if (V.end() == true)
203 {
204 map_stringitem_t const idx = StoreString(pkgCacheGenerator::PKGNAME, pkgname);
205 G = Ver.ParentPkg().Group();
206 Ver->SourcePkgName = idx;
207 }
208 }
209 }
210
211 Ver->MultiArch = ParseMultiArch(true);
212 // Archive Size
213 Ver->Size = Section.FindULL(pkgTagSection::Key::Size);
214 // Unpacked Size (in K)
215 Ver->InstalledSize = Section.FindULL(pkgTagSection::Key::Installed_Size);
216 Ver->InstalledSize *= 1024;
217
218 // Priority
219 if (Section.Find(pkgTagSection::Key::Priority,Start,Stop) == true)
220 {
221 if (GrabWord(StringView(Start,Stop-Start),PrioList,Ver->Priority) == false)
222 Ver->Priority = pkgCache::State::Extra;
223 }
224
225 if (ParseDepends(Ver,pkgTagSection::Key::Pre_Depends,pkgCache::Dep::PreDepends) == false)
226 return false;
227 if (ParseDepends(Ver,pkgTagSection::Key::Depends,pkgCache::Dep::Depends) == false)
228 return false;
229 if (ParseDepends(Ver,pkgTagSection::Key::Conflicts,pkgCache::Dep::Conflicts) == false)
230 return false;
231 if (ParseDepends(Ver,pkgTagSection::Key::Breaks,pkgCache::Dep::DpkgBreaks) == false)
232 return false;
233 if (ParseDepends(Ver,pkgTagSection::Key::Recommends,pkgCache::Dep::Recommends) == false)
234 return false;
235 if (ParseDepends(Ver,pkgTagSection::Key::Suggests,pkgCache::Dep::Suggests) == false)
236 return false;
237 if (ParseDepends(Ver,pkgTagSection::Key::Replaces,pkgCache::Dep::Replaces) == false)
238 return false;
239 if (ParseDepends(Ver,pkgTagSection::Key::Enhances,pkgCache::Dep::Enhances) == false)
240 return false;
241 // Obsolete.
242 if (ParseDepends(Ver,pkgTagSection::Key::Optional,pkgCache::Dep::Suggests) == false)
243 return false;
244
245 if (ParseProvides(Ver) == false)
246 return false;
247
248 return true;
249 }
250 /*}}}*/
251 // ListParser::AvailableDescriptionLanguages /*{{{*/
252 std::vector<std::string> debListParser::AvailableDescriptionLanguages()
253 {
254 std::vector<std::string> const understood = APT::Configuration::getLanguages();
255 std::vector<std::string> avail;
256 static constexpr int prefixLen = 12;
257 char buf[32] = "Description-";
258 if (Section.Exists("Description") == true)
259 avail.push_back("");
260 for (std::vector<std::string>::const_iterator lang = understood.begin(); lang != understood.end(); ++lang)
261 {
262 if (unlikely(lang->size() > sizeof(buf) - prefixLen)) {
263 _error->Warning("Ignoring translated description %s", lang->c_str());
264 continue;
265 }
266 memcpy(buf + prefixLen, lang->c_str(), lang->size());
267 if (Section.Exists(StringView(buf, prefixLen + lang->size())) == true)
268 avail.push_back(*lang);
269 }
270 return avail;
271 }
272 /*}}}*/
273 // ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
274 // ---------------------------------------------------------------------
275 /* This is to return the md5 string to allow the check if it is the right
276 description. If no Description-md5 is found in the section it will be
277 calculated.
278 */
279 MD5SumValue debListParser::Description_md5()
280 {
281 StringView const value = Section.Find(pkgTagSection::Key::Description_md5);
282 if (value.empty() == true)
283 {
284 StringView const desc = Section.Find(pkgTagSection::Key::Description);
285 if (desc == "\n")
286 return MD5SumValue();
287
288 MD5Summation md5;
289 md5.Add(desc.data(), desc.size());
290 md5.Add("\n");
291 return md5.Result();
292 }
293 else if (likely(value.size() == 32))
294 {
295 MD5SumValue sumvalue;
296 if (sumvalue.Set(value))
297 return sumvalue;
298
299 _error->Error("Malformed Description-md5 line; includes invalid character '%.*s'", (int)value.length(), value.data());
300 return MD5SumValue();
301 }
302 _error->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value.size(), (int)value.length(), value.data());
303 return MD5SumValue();
304 }
305 /*}}}*/
306 // ListParser::UsePackage - Update a package structure /*{{{*/
307 // ---------------------------------------------------------------------
308 /* This is called to update the package with any new information
309 that might be found in the section */
310 bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
311 pkgCache::VerIterator &Ver)
312 {
313 string const static myArch = _config->Find("APT::Architecture");
314 // Possible values are: "all", "native", "installed" and "none"
315 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
316 string const static essential = _config->Find("pkgCacheGen::Essential", "all");
317 if (essential == "all" ||
318 (essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()))
319 if (Section.FindFlag(pkgTagSection::Key::Essential,Pkg->Flags,pkgCache::Flag::Essential) == false)
320 return false;
321 if (Section.FindFlag(pkgTagSection::Key::Important,Pkg->Flags,pkgCache::Flag::Important) == false)
322 return false;
323
324 if (std::find(forceEssential.begin(), forceEssential.end(), Pkg.Name()) != forceEssential.end())
325 {
326 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
327 essential == "all")
328 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
329 else
330 Pkg->Flags |= pkgCache::Flag::Important;
331 }
332 else if (std::find(forceImportant.begin(), forceImportant.end(), Pkg.Name()) != forceImportant.end())
333 Pkg->Flags |= pkgCache::Flag::Important;
334
335 if (ParseStatus(Pkg,Ver) == false)
336 return false;
337 return true;
338 }
339 /*}}}*/
340 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
341 // ---------------------------------------------------------------------
342 /* */
343 unsigned short debListParser::VersionHash()
344 {
345 static constexpr pkgTagSection::Key Sections[] ={
346 pkgTagSection::Key::Installed_Size,
347 pkgTagSection::Key::Depends,
348 pkgTagSection::Key::Pre_Depends,
349 // pkgTagSection::Key::Suggests,
350 // pkgTagSection::Key::Recommends",
351 pkgTagSection::Key::Conflicts,
352 pkgTagSection::Key::Breaks,
353 pkgTagSection::Key::Replaces};
354 unsigned long Result = INIT_FCS;
355 for (auto I : Sections)
356 {
357 const char *Start;
358 const char *End;
359 if (Section.Find(I,Start,End) == false)
360 continue;
361
362 /* Strip out any spaces from the text, this undoes dpkgs reformatting
363 of certain fields. dpkg also has the rather interesting notion of
364 reformatting depends operators < -> <=, so we drop all = from the
365 string to make that not matter. */
366 for (; Start != End; ++Start)
367 {
368 if (isspace_ascii(*Start) != 0 || *Start == '=')
369 continue;
370 Result = AddCRC16Byte(Result, tolower_ascii_unsafe(*Start));
371 }
372
373
374 }
375
376 return Result;
377 }
378 /*}}}*/
379 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
380 // ---------------------------------------------------------------------
381 /* Status lines are of the form,
382 Status: want flag status
383 want = unknown, install, hold, deinstall, purge
384 flag = ok, reinstreq
385 status = not-installed, config-files, half-installed, unpacked,
386 half-configured, triggers-awaited, triggers-pending, installed
387 */
388 bool debListParser::ParseStatus(pkgCache::PkgIterator &,
389 pkgCache::VerIterator &)
390 {
391 return true;
392 }
393 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
394 pkgCache::VerIterator &Ver)
395 {
396 const char *Start;
397 const char *Stop;
398 if (Section.Find(pkgTagSection::Key::Status,Start,Stop) == false)
399 return true;
400
401 // UsePackage() is responsible for setting the flag in the default case
402 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
403 if (essential == true &&
404 Section.FindFlag(pkgTagSection::Key::Essential,Pkg->Flags,pkgCache::Flag::Essential) == false)
405 return false;
406
407 // Isolate the first word
408 const char *I = Start;
409 for(; I < Stop && *I != ' '; I++);
410 if (I >= Stop || *I != ' ')
411 return _error->Error("Malformed Status line");
412
413 // Process the want field
414 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
415 {"install",pkgCache::State::Install},
416 {"hold",pkgCache::State::Hold},
417 {"deinstall",pkgCache::State::DeInstall},
418 {"purge",pkgCache::State::Purge},
419 {"", 0}};
420 if (GrabWord(StringView(Start,I-Start),WantList,Pkg->SelectedState) == false)
421 return _error->Error("Malformed 1st word in the Status line");
422
423 // Isloate the next word
424 I++;
425 Start = I;
426 for(; I < Stop && *I != ' '; I++);
427 if (I >= Stop || *I != ' ')
428 return _error->Error("Malformed status line, no 2nd word");
429
430 // Process the flag field
431 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
432 {"reinstreq",pkgCache::State::ReInstReq},
433 {"hold",pkgCache::State::HoldInst},
434 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
435 {"", 0}};
436 if (GrabWord(StringView(Start,I-Start),FlagList,Pkg->InstState) == false)
437 return _error->Error("Malformed 2nd word in the Status line");
438
439 // Isloate the last word
440 I++;
441 Start = I;
442 for(; I < Stop && *I != ' '; I++);
443 if (I != Stop)
444 return _error->Error("Malformed Status line, no 3rd word");
445
446 // Process the flag field
447 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
448 {"config-files",pkgCache::State::ConfigFiles},
449 {"half-installed",pkgCache::State::HalfInstalled},
450 {"unpacked",pkgCache::State::UnPacked},
451 {"half-configured",pkgCache::State::HalfConfigured},
452 {"triggers-awaited",pkgCache::State::TriggersAwaited},
453 {"triggers-pending",pkgCache::State::TriggersPending},
454 {"installed",pkgCache::State::Installed},
455 {"", 0}};
456 if (GrabWord(StringView(Start,I-Start),StatusList,Pkg->CurrentState) == false)
457 return _error->Error("Malformed 3rd word in the Status line");
458
459 /* A Status line marks the package as indicating the current
460 version as well. Only if it is actually installed.. Otherwise
461 the interesting dpkg handling of the status file creates bogus
462 entries. */
463 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
464 Pkg->CurrentState == pkgCache::State::ConfigFiles))
465 {
466 if (Ver.end() == true)
467 _error->Warning("Encountered status field in a non-version description");
468 else
469 Pkg->CurrentVer = Ver.Index();
470 }
471
472 return true;
473 }
474
475 const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
476 {
477 // Determine the operator
478 switch (*I)
479 {
480 case '<':
481 I++;
482 if (*I == '=')
483 {
484 I++;
485 Op = pkgCache::Dep::LessEq;
486 break;
487 }
488
489 if (*I == '<')
490 {
491 I++;
492 Op = pkgCache::Dep::Less;
493 break;
494 }
495
496 // < is the same as <= and << is really Cs < for some reason
497 Op = pkgCache::Dep::LessEq;
498 break;
499
500 case '>':
501 I++;
502 if (*I == '=')
503 {
504 I++;
505 Op = pkgCache::Dep::GreaterEq;
506 break;
507 }
508
509 if (*I == '>')
510 {
511 I++;
512 Op = pkgCache::Dep::Greater;
513 break;
514 }
515
516 // > is the same as >= and >> is really Cs > for some reason
517 Op = pkgCache::Dep::GreaterEq;
518 break;
519
520 case '=':
521 Op = pkgCache::Dep::Equals;
522 I++;
523 break;
524
525 // HACK around bad package definitions
526 default:
527 Op = pkgCache::Dep::Equals;
528 break;
529 }
530 return I;
531 }
532 /*}}}*/
533 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
534 // ---------------------------------------------------------------------
535 /* This parses the dependency elements out of a standard string in place,
536 bit by bit. */
537 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
538 std::string &Package,std::string &Ver,unsigned int &Op)
539 { return ParseDepends(Start, Stop, Package, Ver, Op, false, true, false); }
540 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
541 std::string &Package,std::string &Ver,unsigned int &Op,
542 bool const &ParseArchFlags)
543 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, true, false); }
544 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
545 std::string &Package,std::string &Ver,unsigned int &Op,
546 bool const &ParseArchFlags, bool const &StripMultiArch)
547 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, StripMultiArch, false); }
548 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
549 string &Package,string &Ver,
550 unsigned int &Op, bool const &ParseArchFlags,
551 bool const &StripMultiArch,
552 bool const &ParseRestrictionsList)
553 {
554 StringView PackageView;
555 StringView VerView;
556
557 auto res = ParseDepends(Start, Stop, PackageView, VerView, Op, (bool)ParseArchFlags,
558 (bool) StripMultiArch, (bool) ParseRestrictionsList);
559 Package = PackageView.to_string();
560 Ver = VerView.to_string();
561
562 return res;
563 }
564 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
565 StringView &Package,StringView &Ver,
566 unsigned int &Op, bool ParseArchFlags,
567 bool StripMultiArch,
568 bool ParseRestrictionsList)
569 {
570 // Strip off leading space
571 for (;Start != Stop && isspace_ascii(*Start) != 0; ++Start);
572
573 // Parse off the package name
574 const char *I = Start;
575 for (;I != Stop && isspace_ascii(*I) == 0 && *I != '(' && *I != ')' &&
576 *I != ',' && *I != '|' && *I != '[' && *I != ']' &&
577 *I != '<' && *I != '>'; ++I);
578
579 // Malformed, no '('
580 if (I != Stop && *I == ')')
581 return 0;
582
583 if (I == Start)
584 return 0;
585
586 // Stash the package name
587 Package = StringView(Start, I - Start);
588
589 // We don't want to confuse library users which can't handle MultiArch
590 if (StripMultiArch == true) {
591 string const arch = _config->Find("APT::Architecture");
592 size_t const found = Package.rfind(':');
593 if (found != StringView::npos &&
594 (Package.substr(found) == ":any" ||
595 Package.substr(found) == ":native" ||
596 Package.substr(found +1) == arch))
597 Package = Package.substr(0,found);
598 }
599
600 // Skip white space to the '('
601 for (;I != Stop && isspace_ascii(*I) != 0 ; I++);
602
603 // Parse a version
604 if (I != Stop && *I == '(')
605 {
606 // Skip the '('
607 for (I++; I != Stop && isspace_ascii(*I) != 0 ; I++);
608 if (I + 3 >= Stop)
609 return 0;
610 I = ConvertRelation(I,Op);
611
612 // Skip whitespace
613 for (;I != Stop && isspace_ascii(*I) != 0; I++);
614 Start = I;
615 I = (const char*) memchr(I, ')', Stop - I);
616 if (I == NULL || Start == I)
617 return 0;
618
619 // Skip trailing whitespace
620 const char *End = I;
621 for (; End > Start && isspace_ascii(End[-1]); End--);
622
623 Ver = StringView(Start,End-Start);
624 I++;
625 }
626 else
627 {
628 Ver = StringView();
629 Op = pkgCache::Dep::NoOp;
630 }
631
632 // Skip whitespace
633 for (;I != Stop && isspace_ascii(*I) != 0; I++);
634
635 if (unlikely(ParseArchFlags == true))
636 {
637 string const arch = _config->Find("APT::Architecture");
638 APT::CacheFilter::PackageArchitectureMatchesSpecification matchesArch(arch, false);
639
640 // Parse an architecture
641 if (I != Stop && *I == '[')
642 {
643 ++I;
644 // malformed
645 if (unlikely(I == Stop))
646 return 0;
647
648 const char *End = I;
649 bool Found = false;
650 bool NegArch = false;
651 while (I != Stop)
652 {
653 // look for whitespace or ending ']'
654 for (;End != Stop && !isspace_ascii(*End) && *End != ']'; ++End);
655
656 if (unlikely(End == Stop))
657 return 0;
658
659 if (*I == '!')
660 {
661 NegArch = true;
662 ++I;
663 }
664
665 std::string const arch(I, End);
666 if (arch.empty() == false && matchesArch(arch.c_str()) == true)
667 {
668 Found = true;
669 if (I[-1] != '!')
670 NegArch = false;
671 // we found a match, so fast-forward to the end of the wildcards
672 for (; End != Stop && *End != ']'; ++End);
673 }
674
675 if (*End++ == ']') {
676 I = End;
677 break;
678 }
679
680 I = End;
681 for (;I != Stop && isspace_ascii(*I) != 0; I++);
682 }
683
684 if (NegArch == true)
685 Found = !Found;
686
687 if (Found == false)
688 Package = ""; /* not for this arch */
689 }
690
691 // Skip whitespace
692 for (;I != Stop && isspace_ascii(*I) != 0; I++);
693 }
694
695 if (unlikely(ParseRestrictionsList == true))
696 {
697 // Parse a restrictions formula which is in disjunctive normal form:
698 // (foo AND bar) OR (blub AND bla)
699
700 std::vector<string> const profiles = APT::Configuration::getBuildProfiles();
701
702 // if the next character is a restriction list, then by default the
703 // dependency does not apply and the conditions have to be checked
704 // if the next character is not a restriction list, then by default the
705 // dependency applies
706 bool applies1 = (*I != '<');
707 while (I != Stop)
708 {
709 if (*I != '<')
710 break;
711
712 ++I;
713 // malformed
714 if (unlikely(I == Stop))
715 return 0;
716
717 const char *End = I;
718
719 // if of the prior restriction list is already fulfilled, then
720 // we can just skip to the end of the current list
721 if (applies1) {
722 for (;End != Stop && *End != '>'; ++End);
723 I = ++End;
724 // skip whitespace
725 for (;I != Stop && isspace_ascii(*I) != 0; I++);
726 } else {
727 bool applies2 = true;
728 // all the conditions inside a restriction list have to be
729 // met so once we find one that is not met, we can skip to
730 // the end of this list
731 while (I != Stop)
732 {
733 // look for whitespace or ending '>'
734 // End now points to the character after the current term
735 for (;End != Stop && !isspace_ascii(*End) && *End != '>'; ++End);
736
737 if (unlikely(End == Stop))
738 return 0;
739
740 bool NegRestriction = false;
741 if (*I == '!')
742 {
743 NegRestriction = true;
744 ++I;
745 }
746
747 std::string const restriction(I, End);
748 if (restriction.empty() == false && profiles.empty() == false &&
749 std::find(profiles.begin(), profiles.end(), restriction) != profiles.end())
750 {
751 if (NegRestriction) {
752 applies2 = false;
753 // since one of the terms does not apply we don't have to check the others
754 for (; End != Stop && *End != '>'; ++End);
755 }
756 } else {
757 if (!NegRestriction) {
758 applies2 = false;
759 // since one of the terms does not apply we don't have to check the others
760 for (; End != Stop && *End != '>'; ++End);
761 }
762 }
763
764 if (*End++ == '>') {
765 I = End;
766 // skip whitespace
767 for (;I != Stop && isspace_ascii(*I) != 0; I++);
768 break;
769 }
770
771 I = End;
772 // skip whitespace
773 for (;I != Stop && isspace_ascii(*I) != 0; I++);
774 }
775 if (applies2) {
776 applies1 = true;
777 }
778 }
779 }
780
781 if (applies1 == false) {
782 Package = ""; //not for this restriction
783 }
784 }
785
786 if (I != Stop && *I == '|')
787 Op |= pkgCache::Dep::Or;
788
789 if (I == Stop || *I == ',' || *I == '|')
790 {
791 if (I != Stop)
792 for (I++; I != Stop && isspace_ascii(*I) != 0; I++);
793 return I;
794 }
795
796 return 0;
797 }
798 /*}}}*/
799 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
800 // ---------------------------------------------------------------------
801 /* This is the higher level depends parser. It takes a tag and generates
802 a complete depends tree for the given version. */
803 bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
804 pkgTagSection::Key Key,unsigned int Type)
805 {
806 const char *Start;
807 const char *Stop;
808 if (Section.Find(Key,Start,Stop) == false || Start == Stop)
809 return true;
810
811 string const pkgArch = Ver.Arch();
812
813 while (1)
814 {
815 StringView Package;
816 StringView Version;
817 unsigned int Op;
818
819 Start = ParseDepends(Start, Stop, Package, Version, Op, false, false, false);
820 if (Start == 0)
821 return _error->Error("Problem parsing dependency %zu",static_cast<size_t>(Key)); // TODO
822 size_t const found = Package.rfind(':');
823
824 if (found == string::npos)
825 {
826 if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
827 return false;
828 }
829 else if (Package.substr(found) == ":any")
830 {
831 if (NewDepends(Ver,Package,"any",Version,Op,Type) == false)
832 return false;
833 }
834 else
835 {
836 // Such dependencies are not supposed to be accepted …
837 // … but this is probably the best thing to do anyway
838 if (Package.substr(found + 1) == "native")
839 {
840 std::string const Pkg = Package.substr(0, found).to_string() + ':' + Ver.Cache()->NativeArch();
841 if (NewDepends(Ver, Pkg, "any", Version, Op | pkgCache::Dep::ArchSpecific, Type) == false)
842 return false;
843 }
844 else if (NewDepends(Ver, Package, "any", Version, Op | pkgCache::Dep::ArchSpecific, Type) == false)
845 return false;
846 }
847
848 if (Start == Stop)
849 break;
850 }
851 return true;
852 }
853 /*}}}*/
854 // ListParser::ParseProvides - Parse the provides list /*{{{*/
855 // ---------------------------------------------------------------------
856 /* */
857 bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
858 {
859 /* it is unlikely, but while parsing dependencies, we might have already
860 picked up multi-arch implicit provides which we do not want to duplicate here */
861 bool hasProvidesAlready = false;
862 std::string const spzName = Ver.ParentPkg().FullName(false);
863 {
864 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
865 {
866 if (Prv.IsMultiArchImplicit() == false || (Prv->Flags & pkgCache::Flag::ArchSpecific) == 0)
867 continue;
868 if (spzName != Prv.OwnerPkg().FullName(false))
869 continue;
870 hasProvidesAlready = true;
871 break;
872 }
873 }
874
875 string const Arch = Ver.Arch();
876 const char *Start;
877 const char *Stop;
878 if (Section.Find(pkgTagSection::Key::Provides,Start,Stop) == true)
879 {
880 StringView Package;
881 StringView Version;
882 unsigned int Op;
883
884 do
885 {
886 Start = ParseDepends(Start,Stop,Package,Version,Op, false, false, false);
887 const size_t archfound = Package.rfind(':');
888 if (Start == 0)
889 return _error->Error("Problem parsing Provides line");
890 if (unlikely(Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals)) {
891 _error->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package.to_string().c_str());
892 } else if (archfound != string::npos) {
893 StringView spzArch = Package.substr(archfound + 1);
894 if (spzArch != "any")
895 {
896 if (NewProvides(Ver, Package.substr(0, archfound), spzArch, Version, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
897 return false;
898 }
899 if (NewProvides(Ver, Package, "any", Version, pkgCache::Flag::ArchSpecific) == false)
900 return false;
901 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
902 if (APT::Configuration::checkArchitecture(Arch))
903 {
904 if (NewProvidesAllArch(Ver, Package, Version, 0) == false)
905 return false;
906 }
907 else if (NewProvides(Ver, Package, Arch, Version, 0) == false)
908 return false;
909 } else {
910 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
911 {
912 if (NewProvides(Ver, Package.to_string().append(":any"), "any", Version, pkgCache::Flag::MultiArchImplicit) == false)
913 return false;
914 }
915 if (NewProvides(Ver, Package, Arch, Version, 0) == false)
916 return false;
917 }
918 if (archfound == std::string::npos)
919 {
920 string spzName = Package.to_string();
921 spzName.push_back(':');
922 spzName.append(Ver.ParentPkg().Arch());
923 pkgCache::PkgIterator const spzPkg = Ver.Cache()->FindPkg(spzName, "any");
924 if (spzPkg.end() == false)
925 {
926 if (NewProvides(Ver, spzName, "any", Version, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
927 return false;
928 }
929 }
930 } while (Start != Stop);
931 }
932
933 if (APT::Configuration::checkArchitecture(Arch))
934 {
935 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
936 {
937 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
938 if (NewProvides(Ver, Package, "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit) == false)
939 return false;
940 }
941 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
942 {
943 if (NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr(), pkgCache::Flag::MultiArchImplicit) == false)
944 return false;
945 }
946 }
947
948 if (hasProvidesAlready == false)
949 {
950 pkgCache::PkgIterator const spzPkg = Ver.Cache()->FindPkg(spzName, "any");
951 if (spzPkg.end() == false)
952 {
953 if (NewProvides(Ver, spzName, "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
954 return false;
955 }
956 }
957 return true;
958 }
959 /*}}}*/
960 // ListParser::GrabWord - Matches a word and returns /*{{{*/
961 // ---------------------------------------------------------------------
962 /* Looks for a word in a list of words - for ParseStatus */
963 bool debListParser::GrabWord(StringView Word, WordList const *List, unsigned char &Out)
964 {
965 for (unsigned int C = 0; List[C].Str.empty() == false; C++)
966 {
967 if (Word.length() == List[C].Str.length() &&
968 strncasecmp(Word.data(), List[C].Str.data(), Word.length()) == 0)
969 {
970 Out = List[C].Val;
971 return true;
972 }
973 }
974 return false;
975 }
976 /*}}}*/
977 // ListParser::Step - Move to the next section in the file /*{{{*/
978 // ---------------------------------------------------------------------
979 /* This has to be careful to only process the correct architecture */
980 bool debListParser::Step()
981 {
982 iOffset = Tags.Offset();
983 return Tags.Step(Section);
984 }
985 /*}}}*/
986 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
987 // ---------------------------------------------------------------------
988 /* */
989 unsigned char debListParser::GetPrio(string Str)
990 {
991 unsigned char Out;
992 if (GrabWord(Str,PrioList,Out) == false)
993 Out = pkgCache::State::Extra;
994
995 return Out;
996 }
997 /*}}}*/
998 bool debListParser::SameVersion(unsigned short const Hash, /*{{{*/
999 pkgCache::VerIterator const &Ver)
1000 {
1001 if (pkgCacheListParser::SameVersion(Hash, Ver) == false)
1002 return false;
1003 // status file has no (Download)Size, but all others are fair game
1004 // status file is parsed last, so the first version we encounter is
1005 // probably also the version we have downloaded
1006 unsigned long long const Size = Section.FindULL(pkgTagSection::Key::Size);
1007 if (Size != 0 && Ver->Size != 0 && Size != Ver->Size)
1008 return false;
1009 // available everywhere, but easier to check here than to include in VersionHash
1010 unsigned char MultiArch = ParseMultiArch(false);
1011 if (MultiArch != Ver->MultiArch)
1012 return false;
1013 // for all practical proposes (we can check): same version
1014 return true;
1015 }
1016 /*}}}*/
1017
1018 debDebFileParser::debDebFileParser(FileFd *File, std::string const &DebFile)
1019 : debListParser(File), DebFile(DebFile)
1020 {
1021 }
1022
1023 bool debDebFileParser::UsePackage(pkgCache::PkgIterator &Pkg,
1024 pkgCache::VerIterator &Ver)
1025 {
1026 bool res = debListParser::UsePackage(Pkg, Ver);
1027 // we use the full file path as a provides so that the file is found
1028 // by its name
1029 if(NewProvides(Ver, DebFile, Pkg.Cache()->NativeArch(), Ver.VerStr(), 0) == false)
1030 return false;
1031 return res;
1032 }
1033
1034 debListParser::~debListParser() {}