tagfile.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: tagfile.cc,v 1.37.2.2 2003/12/31 16:02:30 mdz Exp $
  4. /* ######################################################################
  5. Fast scanner for RFC-822 type header information
  6. This uses a rotating buffer to load the package information into.
  7. The scanner runs over it and isolates and indexes a single section.
  8. ##################################################################### */
  9. /*}}}*/
  10. // Include Files /*{{{*/
  11. #include<config.h>
  12. #include <apt-pkg/mmap.h>
  13. #include <apt-pkg/tagfile.h>
  14. #include <apt-pkg/tagfile-keys.h>
  15. #include <apt-pkg/error.h>
  16. #include <apt-pkg/strutl.h>
  17. #include <apt-pkg/fileutl.h>
  18. #include <apt-pkg/string_view.h>
  19. #include <list>
  20. #include <string>
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <apti18n.h>
  26. /*}}}*/
  27. using std::string;
  28. using APT::StringView;
  29. class APT_HIDDEN pkgTagFilePrivate /*{{{*/
  30. {
  31. public:
  32. void Reset(FileFd * const pFd, pkgTagFile::Flags const pFlags)
  33. {
  34. if (Map != NULL)
  35. delete Map;
  36. Map = NULL;
  37. Buffer = NULL;
  38. Fd = pFd;
  39. Flags = pFlags;
  40. Start = NULL;
  41. End = NULL;
  42. Done = false;
  43. iOffset = 0;
  44. }
  45. pkgTagFilePrivate(FileFd * const pFd, pkgTagFile::Flags const pFlags) : Map(NULL)
  46. {
  47. Reset(pFd, pFlags);
  48. }
  49. FileFd * Fd;
  50. pkgTagFile::Flags Flags;
  51. char *Buffer;
  52. char *Start;
  53. char *End;
  54. bool Done;
  55. unsigned long long iOffset;
  56. MMap *Map;
  57. ~pkgTagFilePrivate()
  58. {
  59. if (Map != NULL)
  60. delete Map;
  61. }
  62. };
  63. /*}}}*/
  64. class APT_HIDDEN pkgTagSectionPrivate /*{{{*/
  65. {
  66. public:
  67. pkgTagSectionPrivate()
  68. {
  69. }
  70. struct TagData {
  71. unsigned int StartTag;
  72. unsigned int EndTag;
  73. unsigned int StartValue;
  74. unsigned int NextInBucket;
  75. explicit TagData(unsigned int const StartTag) : StartTag(StartTag), EndTag(0), StartValue(0), NextInBucket(0) {}
  76. };
  77. std::vector<TagData> Tags;
  78. };
  79. /*}}}*/
  80. static unsigned long BetaHash(const char *Text, size_t Length) /*{{{*/
  81. {
  82. /* This very simple hash function for the last 8 letters gives
  83. very good performance on the debian package files */
  84. if (Length > 8)
  85. {
  86. Text += (Length - 8);
  87. Length = 8;
  88. }
  89. unsigned long Res = 0;
  90. for (size_t i = 0; i < Length; ++i)
  91. Res = ((unsigned long)(Text[i]) & 0xDF) ^ (Res << 1);
  92. return Res & 0x7F;
  93. }
  94. /*}}}*/
  95. // TagFile::pkgTagFile - Constructor /*{{{*/
  96. pkgTagFile::pkgTagFile(FileFd * const pFd,pkgTagFile::Flags const pFlags)
  97. : d(new pkgTagFilePrivate(pFd, pFlags))
  98. {
  99. Init(pFd, pFlags);
  100. }
  101. pkgTagFile::pkgTagFile(FileFd * const pFd)
  102. : pkgTagFile(pFd, pkgTagFile::STRICT)
  103. {
  104. }
  105. void pkgTagFile::Init(FileFd * const pFd, pkgTagFile::Flags const pFlags)
  106. {
  107. d->Reset(pFd, pFlags);
  108. if (d->Fd->IsOpen() == false || d->Fd->Size() == 0)
  109. _error->Discard();
  110. else {
  111. d->Map = new MMap(*d->Fd, MMap::ReadOnly);
  112. d->Buffer = static_cast<char *>(d->Map->Data());
  113. }
  114. if (d->Buffer == NULL)
  115. d->Done = true;
  116. else {
  117. d->Done = false;
  118. d->End = d->Buffer + d->Map->Size();
  119. }
  120. d->Start = d->Buffer;
  121. }
  122. void pkgTagFile::Init(FileFd * const pFd)
  123. {
  124. Init(pFd, pkgTagFile::STRICT);
  125. }
  126. /*}}}*/
  127. // TagFile::~pkgTagFile - Destructor /*{{{*/
  128. pkgTagFile::~pkgTagFile()
  129. {
  130. delete d;
  131. }
  132. /*}}}*/
  133. // TagFile::Offset - Return the current offset in the buffer /*{{{*/
  134. APT_PURE unsigned long pkgTagFile::Offset()
  135. {
  136. return d->iOffset;
  137. }
  138. /*}}}*/
  139. // TagFile::Step - Advance to the next section /*{{{*/
  140. // ---------------------------------------------------------------------
  141. /* If the Section Scanner fails we refill the buffer and try again.
  142. * If that fails too, double the buffer size and try again until a
  143. * maximum buffer is reached.
  144. */
  145. bool pkgTagFile::Step(pkgTagSection &Tag)
  146. {
  147. if(Tag.Scan(d->Start,d->End - d->Start,(d->Flags & SUPPORT_COMMENTS) != 0) == false)
  148. {
  149. if (d->Start == d->End)
  150. return false;
  151. else
  152. return _error->Warning(_("Unable to parse package file %s (%d)"),
  153. d->Fd->Name().c_str(), 1);
  154. }
  155. size_t tagSize = Tag.size();
  156. d->Start += tagSize;
  157. d->iOffset += tagSize;
  158. return true;
  159. }
  160. /*}}}*/
  161. // TagFile::Jump - Jump to a pre-recorded location in the file /*{{{*/
  162. // ---------------------------------------------------------------------
  163. /* This jumps to a pre-recorded file location and reads the record
  164. that is there */
  165. bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long long Offset)
  166. {
  167. unsigned int Size(d->Map->Size());
  168. if (Offset >= Size)
  169. return false;
  170. // Reposition and reload..
  171. d->iOffset = Offset;
  172. d->Done = false;
  173. d->Start = d->Buffer + d->iOffset;
  174. return Step(Tag);
  175. }
  176. /*}}}*/
  177. // pkgTagSection::pkgTagSection - Constructor /*{{{*/
  178. // ---------------------------------------------------------------------
  179. /* */
  180. APT_IGNORE_DEPRECATED_PUSH
  181. pkgTagSection::pkgTagSection()
  182. : Section(0), d(new pkgTagSectionPrivate()), Stop(0)
  183. {
  184. memset(&AlphaIndexes, 0, sizeof(AlphaIndexes));
  185. memset(&BetaIndexes, 0, sizeof(BetaIndexes));
  186. }
  187. APT_IGNORE_DEPRECATED_POP
  188. /*}}}*/
  189. // TagSection::Scan - Scan for the end of the header information /*{{{*/
  190. bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength,bool const SupportComments)
  191. {
  192. Section = Start;
  193. const char *End = Start + MaxLength;
  194. Stop = Section;
  195. if (d->Tags.empty() == false)
  196. {
  197. memset(&AlphaIndexes, 0, sizeof(AlphaIndexes));
  198. memset(&BetaIndexes, 0, sizeof(BetaIndexes));
  199. d->Tags.clear();
  200. }
  201. d->Tags.reserve(0x100);
  202. unsigned int TagCount = d->Tags.size();
  203. if (Stop == 0)
  204. return false;
  205. pkgTagSectionPrivate::TagData lastTagData(0);
  206. lastTagData.EndTag = 0;
  207. Key lastTagKey = Key::Unknown;
  208. unsigned int lastTagHash = 0;
  209. while (Stop < End)
  210. {
  211. TrimRecord(true,End,SupportComments);
  212. // this can happen when TrimRecord trims away the entire Record
  213. // (e.g. because it just contains comments)
  214. if(Stop == End)
  215. goto end;
  216. // Start a new index and add it to the hash
  217. if (isspace_ascii(Stop[0]) == 0)
  218. {
  219. // store the last found tag
  220. if (lastTagData.EndTag != 0)
  221. {
  222. if (lastTagKey != Key::Unknown) {
  223. AlphaIndexes[static_cast<size_t>(lastTagKey)] = TagCount;
  224. } else {
  225. if (BetaIndexes[lastTagHash] != 0)
  226. lastTagData.NextInBucket = BetaIndexes[lastTagHash];
  227. APT_IGNORE_DEPRECATED_PUSH
  228. BetaIndexes[lastTagHash] = TagCount;
  229. APT_IGNORE_DEPRECATED_POP
  230. }
  231. d->Tags.push_back(lastTagData);
  232. }
  233. APT_IGNORE_DEPRECATED(++TagCount;)
  234. lastTagData = pkgTagSectionPrivate::TagData(Stop - Section);
  235. // find the colon separating tag and value
  236. char const * Colon = (char const *) memchr(Stop, ':', End - Stop);
  237. if (Colon == NULL)
  238. return false;
  239. // find the end of the tag (which might or might not be the colon)
  240. char const * EndTag = Colon;
  241. --EndTag;
  242. for (; EndTag > Stop && isspace_ascii(*EndTag) != 0; --EndTag)
  243. ;
  244. ++EndTag;
  245. lastTagData.EndTag = EndTag - Section;
  246. lastTagKey = pkgTagHash(Stop, EndTag - Stop);
  247. if (lastTagKey == Key::Unknown)
  248. lastTagHash = BetaHash(Stop, EndTag - Stop);
  249. // find the beginning of the value
  250. Stop = Colon + 1;
  251. for (; Stop < End && isspace_ascii(*Stop) != 0; ++Stop)
  252. if (*Stop == '\n' && (Stop+1 == End || Stop[1] != ' '))
  253. break;
  254. lastTagData.StartValue = Stop - Section;
  255. }
  256. Stop = (const char *)memchr(Stop,'\n',End - Stop);
  257. if (Stop == 0) {
  258. Stop = End;
  259. goto end;
  260. }
  261. for (; Stop+1 < End && Stop[1] == '\r'; Stop++)
  262. /* nothing */
  263. ;
  264. // Double newline marks the end of the record
  265. if (Stop+1 < End && Stop[1] == '\n')
  266. end: {
  267. if (lastTagData.EndTag != 0)
  268. {
  269. if (lastTagKey != Key::Unknown) {
  270. AlphaIndexes[static_cast<size_t>(lastTagKey)] = TagCount;
  271. } else {
  272. if (BetaIndexes[lastTagHash] != 0)
  273. lastTagData.NextInBucket = BetaIndexes[lastTagHash];
  274. APT_IGNORE_DEPRECATED(BetaIndexes[lastTagHash] = TagCount;)
  275. }
  276. d->Tags.push_back(lastTagData);
  277. }
  278. if (d->Tags.empty())
  279. return false;
  280. pkgTagSectionPrivate::TagData const td(Stop - Section);
  281. d->Tags.push_back(td);
  282. TrimRecord(false,End,SupportComments);
  283. return true;
  284. }
  285. Stop++;
  286. }
  287. goto end;
  288. }
  289. /*}}}*/
  290. // TagSection::TrimRecord - Trim off any garbage before/after a record /*{{{*/
  291. // ---------------------------------------------------------------------
  292. /* There should be exactly 2 newline at the end of the record, no more. */
  293. void pkgTagSection::TrimRecord(bool BeforeRecord, const char*& End, bool SupportComments)
  294. { trim:
  295. if (BeforeRecord == false)
  296. for (; Stop < End && (Stop[0] == '\n' || Stop[0] == '\r'); Stop++);
  297. if (SupportComments && Stop < End && Stop[0] == '#') {
  298. Stop = (const char*) memchr(Stop,'\n',End-Stop) ?: End;
  299. goto trim;
  300. }
  301. }
  302. /*}}}*/
  303. // TagSection::Trim - Trim off any trailing garbage /*{{{*/
  304. // ---------------------------------------------------------------------
  305. /* There should be exactly 1 newline at the end of the buffer, no more. */
  306. void pkgTagSection::Trim()
  307. {
  308. for (; Stop > Section + 2 && (Stop[-2] == '\n' || Stop[-2] == '\r'); Stop--);
  309. }
  310. // TagSection::Exists - return True if a tag exists /*{{{*/
  311. bool pkgTagSection::Exists(StringView Tag) const
  312. {
  313. unsigned int tmp;
  314. return Find(Tag, tmp);
  315. }
  316. /*}}}*/
  317. // TagSection::Find - Locate a tag /*{{{*/
  318. // ---------------------------------------------------------------------
  319. /* This searches the section for a tag that matches the given string. */
  320. bool pkgTagSection::Find(Key key,unsigned int &Pos) const
  321. {
  322. auto Bucket = AlphaIndexes[static_cast<size_t>(key)];
  323. Pos = Bucket - 1;
  324. return Bucket != 0;
  325. }
  326. bool pkgTagSection::Find(StringView TagView,unsigned int &Pos) const
  327. {
  328. const char * const Tag = TagView.data();
  329. size_t const Length = TagView.length();
  330. auto key = pkgTagHash(Tag, Length);
  331. if (key != Key::Unknown)
  332. return Find(key, Pos);
  333. unsigned int Bucket = BetaIndexes[BetaHash(Tag, Length)];
  334. if (Bucket == 0)
  335. return false;
  336. for (; Bucket != 0; Bucket = d->Tags[Bucket - 1].NextInBucket)
  337. {
  338. if ((d->Tags[Bucket - 1].EndTag - d->Tags[Bucket - 1].StartTag) != Length)
  339. continue;
  340. char const * const St = Section + d->Tags[Bucket - 1].StartTag;
  341. if (strncasecmp(Tag,St,Length) != 0)
  342. continue;
  343. Pos = Bucket - 1;
  344. return true;
  345. }
  346. Pos = 0;
  347. return false;
  348. }
  349. bool pkgTagSection::FindInternal(unsigned int Pos, const char *&Start,
  350. const char *&End) const
  351. {
  352. Start = Section + d->Tags[Pos].StartValue;
  353. // Strip off the gunk from the end
  354. End = Section + d->Tags[Pos + 1].StartTag;
  355. if (unlikely(Start > End))
  356. return _error->Error("Internal parsing error");
  357. for (; End > Start && isspace_ascii(End[-1]) != 0; --End);
  358. return true;
  359. }
  360. bool pkgTagSection::Find(StringView Tag,const char *&Start,
  361. const char *&End) const
  362. {
  363. unsigned int Pos;
  364. return Find(Tag, Pos) && FindInternal(Pos, Start, End);
  365. }
  366. bool pkgTagSection::Find(Key key,const char *&Start,
  367. const char *&End) const
  368. {
  369. unsigned int Pos;
  370. return Find(key, Pos) && FindInternal(Pos, Start, End);
  371. }
  372. /*}}}*/
  373. // TagSection::FindS - Find a string /*{{{*/
  374. StringView pkgTagSection::Find(StringView Tag) const
  375. {
  376. const char *Start;
  377. const char *End;
  378. if (Find(Tag,Start,End) == false)
  379. return StringView();
  380. return StringView(Start, End - Start);
  381. }
  382. StringView pkgTagSection::Find(Key key) const
  383. {
  384. const char *Start;
  385. const char *End;
  386. if (Find(key,Start,End) == false)
  387. return StringView();
  388. return StringView(Start, End - Start);
  389. }
  390. /*}}}*/
  391. // TagSection::FindRawS - Find a string /*{{{*/
  392. StringView pkgTagSection::FindRawInternal(unsigned int Pos) const
  393. {
  394. char const *Start = (char const *) memchr(Section + d->Tags[Pos].EndTag, ':', d->Tags[Pos].StartValue - d->Tags[Pos].EndTag);
  395. ++Start;
  396. char const *End = Section + d->Tags[Pos + 1].StartTag;
  397. if (unlikely(Start > End))
  398. return "";
  399. for (; isspace_ascii(End[-1]) != 0 && End > Start; --End);
  400. return StringView(Start, End - Start);
  401. }
  402. StringView pkgTagSection::FindRaw(StringView Tag) const
  403. {
  404. unsigned int Pos;
  405. return Find(Tag, Pos) ? FindRawInternal(Pos) : "";
  406. }
  407. StringView pkgTagSection::FindRaw(Key key) const
  408. {
  409. unsigned int Pos;
  410. return Find(key, Pos) ? FindRawInternal(Pos) : "";
  411. }
  412. /*}}}*/
  413. // TagSection::FindI - Find an integer /*{{{*/
  414. // ---------------------------------------------------------------------
  415. /* */
  416. signed int pkgTagSection::FindIInternal(unsigned int Pos,signed long Default) const
  417. {
  418. const char *Start;
  419. const char *Stop;
  420. if (FindInternal(Pos,Start,Stop) == false)
  421. return Default;
  422. // Copy it into a temp buffer so we can use strtol
  423. char S[300];
  424. if ((unsigned)(Stop - Start) >= sizeof(S))
  425. return Default;
  426. strncpy(S,Start,Stop-Start);
  427. S[Stop - Start] = 0;
  428. errno = 0;
  429. char *End;
  430. signed long Result = strtol(S,&End,10);
  431. if (errno == ERANGE ||
  432. Result < std::numeric_limits<int>::min() || Result > std::numeric_limits<int>::max()) {
  433. errno = ERANGE;
  434. _error->Error(_("Cannot convert %s to integer: out of range"), S);
  435. }
  436. if (S == End)
  437. return Default;
  438. return Result;
  439. }
  440. signed int pkgTagSection::FindI(Key key,signed long Default) const
  441. {
  442. unsigned int Pos;
  443. return Find(key, Pos) ? FindIInternal(Pos) : Default;
  444. }
  445. signed int pkgTagSection::FindI(StringView Tag,signed long Default) const
  446. {
  447. unsigned int Pos;
  448. return Find(Tag, Pos) ? FindIInternal(Pos, Default) : Default;
  449. }
  450. /*}}}*/
  451. // TagSection::FindULL - Find an unsigned long long integer /*{{{*/
  452. // ---------------------------------------------------------------------
  453. /* */
  454. unsigned long long pkgTagSection::FindULLInternal(unsigned int Pos, unsigned long long const &Default) const
  455. {
  456. const char *Start;
  457. const char *Stop;
  458. if (FindInternal(Pos,Start,Stop) == false)
  459. return Default;
  460. // Copy it into a temp buffer so we can use strtoull
  461. char S[100];
  462. if ((unsigned)(Stop - Start) >= sizeof(S))
  463. return Default;
  464. strncpy(S,Start,Stop-Start);
  465. S[Stop - Start] = 0;
  466. char *End;
  467. unsigned long long Result = strtoull(S,&End,10);
  468. if (S == End)
  469. return Default;
  470. return Result;
  471. }
  472. unsigned long long pkgTagSection::FindULL(Key key, unsigned long long const &Default) const
  473. {
  474. unsigned int Pos;
  475. return Find(key, Pos) ? FindULLInternal(Pos, Default) : Default;
  476. }
  477. unsigned long long pkgTagSection::FindULL(StringView Tag, unsigned long long const &Default) const
  478. {
  479. unsigned int Pos;
  480. return Find(Tag, Pos) ? FindULLInternal(Pos, Default) : Default;
  481. }
  482. /*}}}*/
  483. // TagSection::FindB - Find boolean value /*{{{*/
  484. // ---------------------------------------------------------------------
  485. /* */
  486. bool pkgTagSection::FindBInternal(unsigned int Pos, bool Default) const
  487. {
  488. const char *Start, *Stop;
  489. if (FindInternal(Pos, Start, Stop) == false)
  490. return Default;
  491. return StringToBool(string(Start, Stop));
  492. }
  493. bool pkgTagSection::FindB(Key key, bool Default) const
  494. {
  495. unsigned int Pos;
  496. return Find(key, Pos) ? FindBInternal(Pos, Default): Default;
  497. }
  498. bool pkgTagSection::FindB(StringView Tag, bool Default) const
  499. {
  500. unsigned int Pos;
  501. return Find(Tag, Pos) ? FindBInternal(Pos, Default) : Default;
  502. }
  503. /*}}}*/
  504. // TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
  505. // ---------------------------------------------------------------------
  506. /* The bits marked in Flag are masked on/off in Flags */
  507. bool pkgTagSection::FindFlagInternal(unsigned int Pos, uint8_t &Flags,
  508. uint8_t const Flag) const
  509. {
  510. const char *Start;
  511. const char *Stop;
  512. if (FindInternal(Pos,Start,Stop) == false)
  513. return true;
  514. return FindFlag(Flags, Flag, Start, Stop);
  515. }
  516. bool pkgTagSection::FindFlag(Key key, uint8_t &Flags,
  517. uint8_t const Flag) const
  518. {
  519. unsigned int Pos;
  520. if (Find(key,Pos) == false)
  521. return true;
  522. return FindFlagInternal(Pos, Flags, Flag);
  523. }
  524. bool pkgTagSection::FindFlag(StringView Tag, uint8_t &Flags,
  525. uint8_t const Flag) const
  526. {
  527. unsigned int Pos;
  528. if (Find(Tag,Pos) == false)
  529. return true;
  530. return FindFlagInternal(Pos, Flags, Flag);
  531. }
  532. bool pkgTagSection::FindFlag(uint8_t &Flags, uint8_t const Flag,
  533. char const* const Start, char const* const Stop)
  534. {
  535. switch (StringToBool(string(Start, Stop)))
  536. {
  537. case 0:
  538. Flags &= ~Flag;
  539. return true;
  540. case 1:
  541. Flags |= Flag;
  542. return true;
  543. default:
  544. _error->Warning("Unknown flag value: %s",string(Start,Stop).c_str());
  545. return true;
  546. }
  547. return true;
  548. }
  549. bool pkgTagSection::FindFlagInternal(unsigned int Pos,unsigned long &Flags,
  550. unsigned long Flag) const
  551. {
  552. const char *Start;
  553. const char *Stop;
  554. if (FindInternal(Pos,Start,Stop) == false)
  555. return true;
  556. return FindFlag(Flags, Flag, Start, Stop);
  557. }
  558. bool pkgTagSection::FindFlag(Key key,unsigned long &Flags,
  559. unsigned long Flag) const
  560. {
  561. unsigned int Pos;
  562. return Find(key, Pos) ? FindFlagInternal(Pos, Flags, Flag) : true;
  563. }
  564. bool pkgTagSection::FindFlag(StringView Tag,unsigned long &Flags,
  565. unsigned long Flag) const
  566. {
  567. unsigned int Pos;
  568. return Find(Tag, Pos) ? FindFlagInternal(Pos, Flags, Flag) : true;
  569. }
  570. bool pkgTagSection::FindFlag(unsigned long &Flags, unsigned long Flag,
  571. char const* Start, char const* Stop)
  572. {
  573. switch (StringToBool(string(Start, Stop)))
  574. {
  575. case 0:
  576. Flags &= ~Flag;
  577. return true;
  578. case 1:
  579. Flags |= Flag;
  580. return true;
  581. default:
  582. _error->Warning("Unknown flag value: %s",string(Start,Stop).c_str());
  583. return true;
  584. }
  585. return true;
  586. }
  587. /*}}}*/
  588. void pkgTagSection::Get(const char *&Start,const char *&Stop,unsigned int I) const/*{{{*/
  589. {
  590. Start = Section + d->Tags[I].StartTag;
  591. Stop = Section + d->Tags[I+1].StartTag;
  592. }
  593. /*}}}*/
  594. APT_PURE unsigned int pkgTagSection::Count() const { /*{{{*/
  595. if (d->Tags.empty() == true)
  596. return 0;
  597. // the last element is just marking the end and isn't a real one
  598. return d->Tags.size() - 1;
  599. }
  600. /*}}}*/
  601. // TagSection::Write - Ordered (re)writing of fields /*{{{*/
  602. pkgTagSection::Tag pkgTagSection::Tag::Remove(std::string const &Name)
  603. {
  604. return Tag(REMOVE, Name, "");
  605. }
  606. pkgTagSection::Tag pkgTagSection::Tag::Rename(std::string const &OldName, std::string const &NewName)
  607. {
  608. return Tag(RENAME, OldName, NewName);
  609. }
  610. pkgTagSection::Tag pkgTagSection::Tag::Rewrite(std::string const &Name, std::string const &Data)
  611. {
  612. if (Data.empty() == true)
  613. return Tag(REMOVE, Name, "");
  614. else
  615. return Tag(REWRITE, Name, Data);
  616. }
  617. static bool WriteTag(FileFd &File, std::string Tag, StringView Value)
  618. {
  619. if (Value.empty() || isspace_ascii(Value[0]) != 0)
  620. Tag.append(":");
  621. else
  622. Tag.append(": ");
  623. Tag.append(Value.data(), Value.length());
  624. Tag.append("\n");
  625. return File.Write(Tag.c_str(), Tag.length());
  626. }
  627. static bool RewriteTags(FileFd &File, pkgTagSection const * const This, char const * const Tag,
  628. std::vector<pkgTagSection::Tag>::const_iterator &R,
  629. std::vector<pkgTagSection::Tag>::const_iterator const &REnd)
  630. {
  631. size_t const TagLen = strlen(Tag);
  632. for (; R != REnd; ++R)
  633. {
  634. std::string data;
  635. if (R->Name.length() == TagLen && strncasecmp(R->Name.c_str(), Tag, R->Name.length()) == 0)
  636. {
  637. if (R->Action != pkgTagSection::Tag::REWRITE)
  638. break;
  639. data = R->Data;
  640. }
  641. else if(R->Action == pkgTagSection::Tag::RENAME && R->Data.length() == TagLen &&
  642. strncasecmp(R->Data.c_str(), Tag, R->Data.length()) == 0)
  643. data = This->FindRaw(R->Name.c_str()).to_string();
  644. else
  645. continue;
  646. return WriteTag(File, Tag, data);
  647. }
  648. return true;
  649. }
  650. bool pkgTagSection::Write(FileFd &File, char const * const * const Order, std::vector<Tag> const &Rewrite) const
  651. {
  652. // first pass: Write everything we have an order for
  653. if (Order != NULL)
  654. {
  655. for (unsigned int I = 0; Order[I] != 0; ++I)
  656. {
  657. std::vector<Tag>::const_iterator R = Rewrite.begin();
  658. if (RewriteTags(File, this, Order[I], R, Rewrite.end()) == false)
  659. return false;
  660. if (R != Rewrite.end())
  661. continue;
  662. if (Exists(Order[I]) == false)
  663. continue;
  664. if (WriteTag(File, Order[I], FindRaw(Order[I])) == false)
  665. return false;
  666. }
  667. }
  668. // second pass: See if we have tags which aren't ordered
  669. if (d->Tags.empty() == false)
  670. {
  671. for (std::vector<pkgTagSectionPrivate::TagData>::const_iterator T = d->Tags.begin(); T != d->Tags.end() - 1; ++T)
  672. {
  673. char const * const fieldname = Section + T->StartTag;
  674. size_t fieldnamelen = T->EndTag - T->StartTag;
  675. if (Order != NULL)
  676. {
  677. unsigned int I = 0;
  678. for (; Order[I] != 0; ++I)
  679. {
  680. if (fieldnamelen == strlen(Order[I]) && strncasecmp(fieldname, Order[I], fieldnamelen) == 0)
  681. break;
  682. }
  683. if (Order[I] != 0)
  684. continue;
  685. }
  686. std::string const name(fieldname, fieldnamelen);
  687. std::vector<Tag>::const_iterator R = Rewrite.begin();
  688. if (RewriteTags(File, this, name.c_str(), R, Rewrite.end()) == false)
  689. return false;
  690. if (R != Rewrite.end())
  691. continue;
  692. if (WriteTag(File, name, FindRaw(name)) == false)
  693. return false;
  694. }
  695. }
  696. // last pass: see if there are any rewrites remaining we haven't done yet
  697. for (std::vector<Tag>::const_iterator R = Rewrite.begin(); R != Rewrite.end(); ++R)
  698. {
  699. if (R->Action == Tag::REMOVE)
  700. continue;
  701. std::string const name = ((R->Action == Tag::RENAME) ? R->Data : R->Name);
  702. if (Exists(name.c_str()))
  703. continue;
  704. if (Order != NULL)
  705. {
  706. unsigned int I = 0;
  707. for (; Order[I] != 0; ++I)
  708. {
  709. if (strncasecmp(name.c_str(), Order[I], name.length()) == 0 && name.length() == strlen(Order[I]))
  710. break;
  711. }
  712. if (Order[I] != 0)
  713. continue;
  714. }
  715. if (WriteTag(File, name, ((R->Action == Tag::RENAME) ? FindRaw(R->Name) : R->Data)) == false)
  716. return false;
  717. }
  718. return true;
  719. }
  720. /*}}}*/
  721. #include "tagfile-order.c"
  722. // TFRewrite - Rewrite a control record /*{{{*/
  723. // ---------------------------------------------------------------------
  724. /* This writes the control record to stdout rewriting it as necessary. The
  725. override map item specificies the rewriting rules to follow. This also
  726. takes the time to sort the feild list. */
  727. APT_IGNORE_DEPRECATED_PUSH
  728. bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[],
  729. TFRewriteData *Rewrite)
  730. {
  731. unsigned char Visited[256]; // Bit 1 is Order, Bit 2 is Rewrite
  732. for (unsigned I = 0; I != 256; I++)
  733. Visited[I] = 0;
  734. // Set new tag up as necessary.
  735. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  736. {
  737. if (Rewrite[J].NewTag == 0)
  738. Rewrite[J].NewTag = Rewrite[J].Tag;
  739. }
  740. // Write all all of the tags, in order.
  741. if (Order != NULL)
  742. {
  743. for (unsigned int I = 0; Order[I] != 0; I++)
  744. {
  745. bool Rewritten = false;
  746. // See if this is a field that needs to be rewritten
  747. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  748. {
  749. if (strcasecmp(Rewrite[J].Tag,Order[I]) == 0)
  750. {
  751. Visited[J] |= 2;
  752. if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
  753. {
  754. if (isspace_ascii(Rewrite[J].Rewrite[0]))
  755. fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  756. else
  757. fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  758. }
  759. Rewritten = true;
  760. break;
  761. }
  762. }
  763. // See if it is in the fragment
  764. unsigned Pos;
  765. if (Tags.Find(StringView(Order[I]),Pos) == false)
  766. continue;
  767. Visited[Pos] |= 1;
  768. if (Rewritten == true)
  769. continue;
  770. /* Write out this element, taking a moment to rewrite the tag
  771. in case of changes of case. */
  772. const char *Start;
  773. const char *Stop;
  774. Tags.Get(Start,Stop,Pos);
  775. if (fputs(Order[I],Output) < 0)
  776. return _error->Errno("fputs","IO Error to output");
  777. Start += strlen(Order[I]);
  778. if (fwrite(Start,Stop - Start,1,Output) != 1)
  779. return _error->Errno("fwrite","IO Error to output");
  780. if (Stop[-1] != '\n')
  781. fprintf(Output,"\n");
  782. }
  783. }
  784. // Now write all the old tags that were missed.
  785. for (unsigned int I = 0; I != Tags.Count(); I++)
  786. {
  787. if ((Visited[I] & 1) == 1)
  788. continue;
  789. const char *Start;
  790. const char *Stop;
  791. Tags.Get(Start,Stop,I);
  792. const char *End = Start;
  793. for (; End < Stop && *End != ':'; End++);
  794. // See if this is a field that needs to be rewritten
  795. bool Rewritten = false;
  796. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  797. {
  798. if (stringcasecmp(Start,End,Rewrite[J].Tag) == 0)
  799. {
  800. Visited[J] |= 2;
  801. if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
  802. {
  803. if (isspace_ascii(Rewrite[J].Rewrite[0]))
  804. fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  805. else
  806. fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  807. }
  808. Rewritten = true;
  809. break;
  810. }
  811. }
  812. if (Rewritten == true)
  813. continue;
  814. // Write out this element
  815. if (fwrite(Start,Stop - Start,1,Output) != 1)
  816. return _error->Errno("fwrite","IO Error to output");
  817. if (Stop[-1] != '\n')
  818. fprintf(Output,"\n");
  819. }
  820. // Now write all the rewrites that were missed
  821. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  822. {
  823. if ((Visited[J] & 2) == 2)
  824. continue;
  825. if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
  826. {
  827. if (isspace_ascii(Rewrite[J].Rewrite[0]))
  828. fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  829. else
  830. fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  831. }
  832. }
  833. return true;
  834. }
  835. APT_IGNORE_DEPRECATED_POP
  836. /*}}}*/
  837. pkgTagSection::~pkgTagSection() { delete d; }