tagfile.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  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/tagfile.h>
  13. #include <apt-pkg/error.h>
  14. #include <apt-pkg/strutl.h>
  15. #include <apt-pkg/fileutl.h>
  16. #include <string>
  17. #include <stdio.h>
  18. #include <ctype.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <apti18n.h>
  22. /*}}}*/
  23. using std::string;
  24. class pkgTagFilePrivate
  25. {
  26. public:
  27. pkgTagFilePrivate(FileFd *pFd, unsigned long long Size) : Fd(*pFd), Buffer(NULL),
  28. Start(NULL), End(NULL),
  29. Done(false), iOffset(0),
  30. Size(Size)
  31. {
  32. }
  33. FileFd &Fd;
  34. char *Buffer;
  35. char *Start;
  36. char *End;
  37. bool Done;
  38. unsigned long long iOffset;
  39. unsigned long long Size;
  40. };
  41. class pkgTagSectionPrivate
  42. {
  43. public:
  44. pkgTagSectionPrivate()
  45. {
  46. }
  47. struct TagData {
  48. unsigned int StartTag;
  49. unsigned int EndTag;
  50. unsigned int StartValue;
  51. unsigned int NextInBucket;
  52. TagData(unsigned int const StartTag) : StartTag(StartTag), EndTag(0), StartValue(0), NextInBucket(0) {}
  53. };
  54. std::vector<TagData> Tags;
  55. };
  56. static unsigned long AlphaHash(const char *Text, size_t Length) /*{{{*/
  57. {
  58. /* This very simple hash function for the last 8 letters gives
  59. very good performance on the debian package files */
  60. if (Length > 8)
  61. {
  62. Text += (Length - 8);
  63. Length = 8;
  64. }
  65. unsigned long Res = 0;
  66. for (size_t i = 0; i < Length; ++i)
  67. Res = ((unsigned long)(Text[i]) & 0xDF) ^ (Res << 1);
  68. return Res & 0xFF;
  69. }
  70. /*}}}*/
  71. // TagFile::pkgTagFile - Constructor /*{{{*/
  72. // ---------------------------------------------------------------------
  73. /* */
  74. pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long long Size)
  75. : d(NULL)
  76. {
  77. Init(pFd, Size);
  78. }
  79. void pkgTagFile::Init(FileFd *pFd,unsigned long long Size)
  80. {
  81. /* The size is increased by 4 because if we start with the Size of the
  82. filename we need to try to read 1 char more to see an EOF faster, 1
  83. char the end-pointer can be on and maybe 2 newlines need to be added
  84. to the end of the file -> 4 extra chars */
  85. Size += 4;
  86. if(d != NULL)
  87. {
  88. free(d->Buffer);
  89. delete d;
  90. }
  91. d = new pkgTagFilePrivate(pFd, Size);
  92. if (d->Fd.IsOpen() == false)
  93. d->Start = d->End = d->Buffer = 0;
  94. else
  95. d->Buffer = (char*)malloc(sizeof(char) * Size);
  96. if (d->Buffer == NULL)
  97. d->Done = true;
  98. else
  99. d->Done = false;
  100. d->Start = d->End = d->Buffer;
  101. d->iOffset = 0;
  102. if (d->Done == false)
  103. Fill();
  104. }
  105. /*}}}*/
  106. // TagFile::~pkgTagFile - Destructor /*{{{*/
  107. // ---------------------------------------------------------------------
  108. /* */
  109. pkgTagFile::~pkgTagFile()
  110. {
  111. free(d->Buffer);
  112. delete d;
  113. }
  114. /*}}}*/
  115. // TagFile::Offset - Return the current offset in the buffer /*{{{*/
  116. APT_PURE unsigned long pkgTagFile::Offset()
  117. {
  118. return d->iOffset;
  119. }
  120. /*}}}*/
  121. // TagFile::Resize - Resize the internal buffer /*{{{*/
  122. // ---------------------------------------------------------------------
  123. /* Resize the internal buffer (double it in size). Fail if a maximum size
  124. * size is reached.
  125. */
  126. bool pkgTagFile::Resize()
  127. {
  128. // fail is the buffer grows too big
  129. if(d->Size > 1024*1024+1)
  130. return false;
  131. return Resize(d->Size * 2);
  132. }
  133. bool pkgTagFile::Resize(unsigned long long const newSize)
  134. {
  135. unsigned long long const EndSize = d->End - d->Start;
  136. // get new buffer and use it
  137. char* newBuffer = (char*)realloc(d->Buffer, sizeof(char) * newSize);
  138. if (newBuffer == NULL)
  139. return false;
  140. d->Buffer = newBuffer;
  141. d->Size = newSize;
  142. // update the start/end pointers to the new buffer
  143. d->Start = d->Buffer;
  144. d->End = d->Start + EndSize;
  145. return true;
  146. }
  147. /*}}}*/
  148. // TagFile::Step - Advance to the next section /*{{{*/
  149. // ---------------------------------------------------------------------
  150. /* If the Section Scanner fails we refill the buffer and try again.
  151. * If that fails too, double the buffer size and try again until a
  152. * maximum buffer is reached.
  153. */
  154. bool pkgTagFile::Step(pkgTagSection &Tag)
  155. {
  156. if(Tag.Scan(d->Start,d->End - d->Start) == false)
  157. {
  158. do
  159. {
  160. if (Fill() == false)
  161. return false;
  162. if(Tag.Scan(d->Start,d->End - d->Start, false))
  163. break;
  164. if (Resize() == false)
  165. return _error->Error(_("Unable to parse package file %s (1)"),
  166. d->Fd.Name().c_str());
  167. } while (Tag.Scan(d->Start,d->End - d->Start, false) == false);
  168. }
  169. d->Start += Tag.size();
  170. d->iOffset += Tag.size();
  171. Tag.Trim();
  172. return true;
  173. }
  174. /*}}}*/
  175. // TagFile::Fill - Top up the buffer /*{{{*/
  176. // ---------------------------------------------------------------------
  177. /* This takes the bit at the end of the buffer and puts it at the start
  178. then fills the rest from the file */
  179. bool pkgTagFile::Fill()
  180. {
  181. unsigned long long EndSize = d->End - d->Start;
  182. unsigned long long Actual = 0;
  183. memmove(d->Buffer,d->Start,EndSize);
  184. d->Start = d->Buffer;
  185. d->End = d->Buffer + EndSize;
  186. if (d->Done == false)
  187. {
  188. // See if only a bit of the file is left
  189. unsigned long long const dataSize = d->Size - ((d->End - d->Buffer) + 1);
  190. if (d->Fd.Read(d->End, dataSize, &Actual) == false)
  191. return false;
  192. if (Actual != dataSize)
  193. d->Done = true;
  194. d->End += Actual;
  195. }
  196. if (d->Done == true)
  197. {
  198. if (EndSize <= 3 && Actual == 0)
  199. return false;
  200. if (d->Size - (d->End - d->Buffer) < 4)
  201. return true;
  202. // Append a double new line if one does not exist
  203. unsigned int LineCount = 0;
  204. for (const char *E = d->End - 1; E - d->End < 6 && (*E == '\n' || *E == '\r'); E--)
  205. if (*E == '\n')
  206. LineCount++;
  207. if (LineCount < 2)
  208. {
  209. if ((unsigned)(d->End - d->Buffer) >= d->Size)
  210. Resize(d->Size + 3);
  211. for (; LineCount < 2; LineCount++)
  212. *d->End++ = '\n';
  213. }
  214. return true;
  215. }
  216. return true;
  217. }
  218. /*}}}*/
  219. // TagFile::Jump - Jump to a pre-recorded location in the file /*{{{*/
  220. // ---------------------------------------------------------------------
  221. /* This jumps to a pre-recorded file location and reads the record
  222. that is there */
  223. bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long long Offset)
  224. {
  225. // We are within a buffer space of the next hit..
  226. if (Offset >= d->iOffset && d->iOffset + (d->End - d->Start) > Offset)
  227. {
  228. unsigned long long Dist = Offset - d->iOffset;
  229. d->Start += Dist;
  230. d->iOffset += Dist;
  231. // if we have seen the end, don't ask for more
  232. if (d->Done == true)
  233. return Tag.Scan(d->Start, d->End - d->Start);
  234. else
  235. return Step(Tag);
  236. }
  237. // Reposition and reload..
  238. d->iOffset = Offset;
  239. d->Done = false;
  240. if (d->Fd.Seek(Offset) == false)
  241. return false;
  242. d->End = d->Start = d->Buffer;
  243. if (Fill() == false)
  244. return false;
  245. if (Tag.Scan(d->Start, d->End - d->Start) == true)
  246. return true;
  247. // This appends a double new line (for the real eof handling)
  248. if (Fill() == false)
  249. return false;
  250. if (Tag.Scan(d->Start, d->End - d->Start, false) == false)
  251. return _error->Error(_("Unable to parse package file %s (2)"),d->Fd.Name().c_str());
  252. return true;
  253. }
  254. /*}}}*/
  255. // pkgTagSection::pkgTagSection - Constructor /*{{{*/
  256. // ---------------------------------------------------------------------
  257. /* */
  258. APT_IGNORE_DEPRECATED_PUSH
  259. pkgTagSection::pkgTagSection()
  260. : Section(0), d(NULL), Stop(0)
  261. {
  262. d = new pkgTagSectionPrivate();
  263. #if APT_PKG_ABI < 413
  264. TagCount = 0;
  265. memset(&Indexes, 0, sizeof(Indexes));
  266. #endif
  267. memset(&AlphaIndexes, 0, sizeof(AlphaIndexes));
  268. }
  269. APT_IGNORE_DEPRECATED_POP
  270. /*}}}*/
  271. // TagSection::Scan - Scan for the end of the header information /*{{{*/
  272. #if APT_PKG_ABI < 413
  273. bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
  274. {
  275. return Scan(Start, MaxLength, true);
  276. }
  277. #endif
  278. bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength, bool const Restart)
  279. {
  280. Section = Start;
  281. const char *End = Start + MaxLength;
  282. if (Restart == false && d->Tags.empty() == false)
  283. {
  284. Stop = Section + d->Tags.back().StartTag;
  285. if (End <= Stop)
  286. return false;
  287. Stop = (const char *)memchr(Stop,'\n',End - Stop);
  288. if (Stop == NULL)
  289. return false;
  290. ++Stop;
  291. }
  292. else
  293. {
  294. Stop = Section;
  295. if (d->Tags.empty() == false)
  296. {
  297. memset(&AlphaIndexes, 0, sizeof(AlphaIndexes));
  298. d->Tags.clear();
  299. }
  300. d->Tags.reserve(0x100);
  301. }
  302. #if APT_PKG_ABI >= 413
  303. unsigned int TagCount = d->Tags.size();
  304. #else
  305. APT_IGNORE_DEPRECATED(TagCount = d->Tags.size();)
  306. #endif
  307. if (Stop == 0)
  308. return false;
  309. pkgTagSectionPrivate::TagData lastTagData(0);
  310. lastTagData.EndTag = 0;
  311. unsigned long lastTagHash = 0;
  312. while (Stop < End)
  313. {
  314. TrimRecord(true,End);
  315. // this can happen when TrimRecord trims away the entire Record
  316. // (e.g. because it just contains comments)
  317. if(Stop == End)
  318. return true;
  319. // Start a new index and add it to the hash
  320. if (isspace(Stop[0]) == 0)
  321. {
  322. // store the last found tag
  323. if (lastTagData.EndTag != 0)
  324. {
  325. if (AlphaIndexes[lastTagHash] != 0)
  326. lastTagData.NextInBucket = AlphaIndexes[lastTagHash];
  327. APT_IGNORE_DEPRECATED_PUSH
  328. AlphaIndexes[lastTagHash] = TagCount;
  329. #if APT_PKG_ABI < 413
  330. if (d->Tags.size() < sizeof(Indexes)/sizeof(Indexes[0]))
  331. Indexes[d->Tags.size()] = lastTagData.StartTag;
  332. #endif
  333. APT_IGNORE_DEPRECATED_POP
  334. d->Tags.push_back(lastTagData);
  335. }
  336. APT_IGNORE_DEPRECATED(++TagCount;)
  337. lastTagData = pkgTagSectionPrivate::TagData(Stop - Section);
  338. // find the colon separating tag and value
  339. char const * Colon = (char const *) memchr(Stop, ':', End - Stop);
  340. if (Colon == NULL)
  341. return false;
  342. // find the end of the tag (which might or might not be the colon)
  343. char const * EndTag = Colon;
  344. --EndTag;
  345. for (; EndTag > Stop && isspace(*EndTag) != 0; --EndTag)
  346. ;
  347. ++EndTag;
  348. lastTagData.EndTag = EndTag - Section;
  349. lastTagHash = AlphaHash(Stop, EndTag - Stop);
  350. // find the beginning of the value
  351. Stop = Colon + 1;
  352. for (; isspace(*Stop) != 0; ++Stop);
  353. if (Stop >= End)
  354. return false;
  355. lastTagData.StartValue = Stop - Section;
  356. }
  357. Stop = (const char *)memchr(Stop,'\n',End - Stop);
  358. if (Stop == 0)
  359. return false;
  360. for (; Stop+1 < End && Stop[1] == '\r'; Stop++)
  361. /* nothing */
  362. ;
  363. // Double newline marks the end of the record
  364. if (Stop+1 < End && Stop[1] == '\n')
  365. {
  366. if (lastTagData.EndTag != 0)
  367. {
  368. if (AlphaIndexes[lastTagHash] != 0)
  369. lastTagData.NextInBucket = AlphaIndexes[lastTagHash];
  370. APT_IGNORE_DEPRECATED(AlphaIndexes[lastTagHash] = TagCount;)
  371. #if APT_PKG_ABI < 413
  372. APT_IGNORE_DEPRECATED(Indexes[d->Tags.size()] = lastTagData.StartTag;)
  373. #endif
  374. d->Tags.push_back(lastTagData);
  375. }
  376. pkgTagSectionPrivate::TagData const td(Stop - Section);
  377. #if APT_PKG_ABI < 413
  378. APT_IGNORE_DEPRECATED(Indexes[d->Tags.size()] = td.StartTag;)
  379. #endif
  380. d->Tags.push_back(td);
  381. TrimRecord(false,End);
  382. return true;
  383. }
  384. Stop++;
  385. }
  386. return false;
  387. }
  388. /*}}}*/
  389. // TagSection::TrimRecord - Trim off any garbage before/after a record /*{{{*/
  390. // ---------------------------------------------------------------------
  391. /* There should be exactly 2 newline at the end of the record, no more. */
  392. void pkgTagSection::TrimRecord(bool BeforeRecord, const char*& End)
  393. {
  394. if (BeforeRecord == true)
  395. return;
  396. for (; Stop < End && (Stop[0] == '\n' || Stop[0] == '\r'); Stop++);
  397. }
  398. /*}}}*/
  399. // TagSection::Trim - Trim off any trailing garbage /*{{{*/
  400. // ---------------------------------------------------------------------
  401. /* There should be exactly 1 newline at the end of the buffer, no more. */
  402. void pkgTagSection::Trim()
  403. {
  404. for (; Stop > Section + 2 && (Stop[-2] == '\n' || Stop[-2] == '\r'); Stop--);
  405. }
  406. /*}}}*/
  407. // TagSection::Exists - return True if a tag exists /*{{{*/
  408. #if APT_PKG_ABI >= 413
  409. bool pkgTagSection::Exists(const char* const Tag) const
  410. #else
  411. bool pkgTagSection::Exists(const char* const Tag)
  412. #endif
  413. {
  414. unsigned int tmp;
  415. return Find(Tag, tmp);
  416. }
  417. /*}}}*/
  418. // TagSection::Find - Locate a tag /*{{{*/
  419. // ---------------------------------------------------------------------
  420. /* This searches the section for a tag that matches the given string. */
  421. bool pkgTagSection::Find(const char *Tag,unsigned int &Pos) const
  422. {
  423. size_t const Length = strlen(Tag);
  424. unsigned int Bucket = AlphaIndexes[AlphaHash(Tag, Length)];
  425. if (Bucket == 0)
  426. return false;
  427. for (; Bucket != 0; Bucket = d->Tags[Bucket - 1].NextInBucket)
  428. {
  429. if ((d->Tags[Bucket - 1].EndTag - d->Tags[Bucket - 1].StartTag) != Length)
  430. continue;
  431. char const * const St = Section + d->Tags[Bucket - 1].StartTag;
  432. if (strncasecmp(Tag,St,Length) != 0)
  433. continue;
  434. Pos = Bucket - 1;
  435. return true;
  436. }
  437. Pos = 0;
  438. return false;
  439. }
  440. bool pkgTagSection::Find(const char *Tag,const char *&Start,
  441. const char *&End) const
  442. {
  443. unsigned int Pos;
  444. if (Find(Tag, Pos) == false)
  445. return false;
  446. Start = Section + d->Tags[Pos].StartValue;
  447. // Strip off the gunk from the end
  448. End = Section + d->Tags[Pos + 1].StartTag;
  449. if (unlikely(Start > End))
  450. return _error->Error("Internal parsing error");
  451. for (; isspace(End[-1]) != 0 && End > Start; --End);
  452. return true;
  453. }
  454. /*}}}*/
  455. // TagSection::FindS - Find a string /*{{{*/
  456. // ---------------------------------------------------------------------
  457. /* */
  458. string pkgTagSection::FindS(const char *Tag) const
  459. {
  460. const char *Start;
  461. const char *End;
  462. if (Find(Tag,Start,End) == false)
  463. return string();
  464. return string(Start,End);
  465. }
  466. /*}}}*/
  467. // TagSection::FindI - Find an integer /*{{{*/
  468. // ---------------------------------------------------------------------
  469. /* */
  470. signed int pkgTagSection::FindI(const char *Tag,signed long Default) const
  471. {
  472. const char *Start;
  473. const char *Stop;
  474. if (Find(Tag,Start,Stop) == false)
  475. return Default;
  476. // Copy it into a temp buffer so we can use strtol
  477. char S[300];
  478. if ((unsigned)(Stop - Start) >= sizeof(S))
  479. return Default;
  480. strncpy(S,Start,Stop-Start);
  481. S[Stop - Start] = 0;
  482. char *End;
  483. signed long Result = strtol(S,&End,10);
  484. if (S == End)
  485. return Default;
  486. return Result;
  487. }
  488. /*}}}*/
  489. // TagSection::FindULL - Find an unsigned long long integer /*{{{*/
  490. // ---------------------------------------------------------------------
  491. /* */
  492. unsigned long long pkgTagSection::FindULL(const char *Tag, unsigned long long const &Default) const
  493. {
  494. const char *Start;
  495. const char *Stop;
  496. if (Find(Tag,Start,Stop) == false)
  497. return Default;
  498. // Copy it into a temp buffer so we can use strtoull
  499. char S[100];
  500. if ((unsigned)(Stop - Start) >= sizeof(S))
  501. return Default;
  502. strncpy(S,Start,Stop-Start);
  503. S[Stop - Start] = 0;
  504. char *End;
  505. unsigned long long Result = strtoull(S,&End,10);
  506. if (S == End)
  507. return Default;
  508. return Result;
  509. }
  510. /*}}}*/
  511. // TagSection::FindB - Find boolean value /*{{{*/
  512. // ---------------------------------------------------------------------
  513. /* */
  514. bool pkgTagSection::FindB(const char *Tag, bool const &Default) const
  515. {
  516. const char *Start, *Stop;
  517. if (Find(Tag, Start, Stop) == false)
  518. return Default;
  519. return StringToBool(string(Start, Stop));
  520. }
  521. /*}}}*/
  522. // TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
  523. // ---------------------------------------------------------------------
  524. /* The bits marked in Flag are masked on/off in Flags */
  525. bool pkgTagSection::FindFlag(const char *Tag,unsigned long &Flags,
  526. unsigned long Flag) const
  527. {
  528. const char *Start;
  529. const char *Stop;
  530. if (Find(Tag,Start,Stop) == false)
  531. return true;
  532. return FindFlag(Flags, Flag, Start, Stop);
  533. }
  534. bool pkgTagSection::FindFlag(unsigned long &Flags, unsigned long Flag,
  535. char const* Start, char const* Stop)
  536. {
  537. switch (StringToBool(string(Start, Stop)))
  538. {
  539. case 0:
  540. Flags &= ~Flag;
  541. return true;
  542. case 1:
  543. Flags |= Flag;
  544. return true;
  545. default:
  546. _error->Warning("Unknown flag value: %s",string(Start,Stop).c_str());
  547. return true;
  548. }
  549. return true;
  550. }
  551. /*}}}*/
  552. void pkgTagSection::Get(const char *&Start,const char *&Stop,unsigned int I) const
  553. {
  554. Start = Section + d->Tags[I].StartTag;
  555. Stop = Section + d->Tags[I+1].StartTag;
  556. }
  557. APT_PURE unsigned int pkgTagSection::Count() const { /*{{{*/
  558. if (d->Tags.empty() == true)
  559. return 0;
  560. // the last element is just marking the end and isn't a real one
  561. return d->Tags.size() - 1;
  562. }
  563. /*}}}*/
  564. // TFRewrite - Rewrite a control record /*{{{*/
  565. // ---------------------------------------------------------------------
  566. /* This writes the control record to stdout rewriting it as necessary. The
  567. override map item specificies the rewriting rules to follow. This also
  568. takes the time to sort the feild list. */
  569. /* The order of this list is taken from dpkg source lib/parse.c the fieldinfos
  570. array. */
  571. static const char *iTFRewritePackageOrder[] = {
  572. "Package",
  573. "Essential",
  574. "Status",
  575. "Priority",
  576. "Section",
  577. "Installed-Size",
  578. "Maintainer",
  579. "Original-Maintainer",
  580. "Architecture",
  581. "Source",
  582. "Version",
  583. "Revision", // Obsolete
  584. "Config-Version", // Obsolete
  585. "Replaces",
  586. "Provides",
  587. "Depends",
  588. "Pre-Depends",
  589. "Recommends",
  590. "Suggests",
  591. "Conflicts",
  592. "Breaks",
  593. "Conffiles",
  594. "Filename",
  595. "Size",
  596. "MD5sum",
  597. "SHA1",
  598. "SHA256",
  599. "SHA512",
  600. "MSDOS-Filename", // Obsolete
  601. "Description",
  602. 0};
  603. static const char *iTFRewriteSourceOrder[] = {"Package",
  604. "Source",
  605. "Binary",
  606. "Version",
  607. "Priority",
  608. "Section",
  609. "Maintainer",
  610. "Original-Maintainer",
  611. "Build-Depends",
  612. "Build-Depends-Indep",
  613. "Build-Conflicts",
  614. "Build-Conflicts-Indep",
  615. "Architecture",
  616. "Standards-Version",
  617. "Format",
  618. "Directory",
  619. "Files",
  620. 0};
  621. /* Two levels of initialization are used because gcc will set the symbol
  622. size of an array to the length of the array, causing dynamic relinking
  623. errors. Doing this makes the symbol size constant */
  624. const char **TFRewritePackageOrder = iTFRewritePackageOrder;
  625. const char **TFRewriteSourceOrder = iTFRewriteSourceOrder;
  626. bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[],
  627. TFRewriteData *Rewrite)
  628. {
  629. unsigned char Visited[256]; // Bit 1 is Order, Bit 2 is Rewrite
  630. for (unsigned I = 0; I != 256; I++)
  631. Visited[I] = 0;
  632. // Set new tag up as necessary.
  633. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  634. {
  635. if (Rewrite[J].NewTag == 0)
  636. Rewrite[J].NewTag = Rewrite[J].Tag;
  637. }
  638. // Write all all of the tags, in order.
  639. if (Order != NULL)
  640. {
  641. for (unsigned int I = 0; Order[I] != 0; I++)
  642. {
  643. bool Rewritten = false;
  644. // See if this is a field that needs to be rewritten
  645. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  646. {
  647. if (strcasecmp(Rewrite[J].Tag,Order[I]) == 0)
  648. {
  649. Visited[J] |= 2;
  650. if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
  651. {
  652. if (isspace(Rewrite[J].Rewrite[0]))
  653. fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  654. else
  655. fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  656. }
  657. Rewritten = true;
  658. break;
  659. }
  660. }
  661. // See if it is in the fragment
  662. unsigned Pos;
  663. if (Tags.Find(Order[I],Pos) == false)
  664. continue;
  665. Visited[Pos] |= 1;
  666. if (Rewritten == true)
  667. continue;
  668. /* Write out this element, taking a moment to rewrite the tag
  669. in case of changes of case. */
  670. const char *Start;
  671. const char *Stop;
  672. Tags.Get(Start,Stop,Pos);
  673. if (fputs(Order[I],Output) < 0)
  674. return _error->Errno("fputs","IO Error to output");
  675. Start += strlen(Order[I]);
  676. if (fwrite(Start,Stop - Start,1,Output) != 1)
  677. return _error->Errno("fwrite","IO Error to output");
  678. if (Stop[-1] != '\n')
  679. fprintf(Output,"\n");
  680. }
  681. }
  682. // Now write all the old tags that were missed.
  683. for (unsigned int I = 0; I != Tags.Count(); I++)
  684. {
  685. if ((Visited[I] & 1) == 1)
  686. continue;
  687. const char *Start;
  688. const char *Stop;
  689. Tags.Get(Start,Stop,I);
  690. const char *End = Start;
  691. for (; End < Stop && *End != ':'; End++);
  692. // See if this is a field that needs to be rewritten
  693. bool Rewritten = false;
  694. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  695. {
  696. if (stringcasecmp(Start,End,Rewrite[J].Tag) == 0)
  697. {
  698. Visited[J] |= 2;
  699. if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
  700. {
  701. if (isspace(Rewrite[J].Rewrite[0]))
  702. fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  703. else
  704. fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  705. }
  706. Rewritten = true;
  707. break;
  708. }
  709. }
  710. if (Rewritten == true)
  711. continue;
  712. // Write out this element
  713. if (fwrite(Start,Stop - Start,1,Output) != 1)
  714. return _error->Errno("fwrite","IO Error to output");
  715. if (Stop[-1] != '\n')
  716. fprintf(Output,"\n");
  717. }
  718. // Now write all the rewrites that were missed
  719. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  720. {
  721. if ((Visited[J] & 2) == 2)
  722. continue;
  723. if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
  724. {
  725. if (isspace(Rewrite[J].Rewrite[0]))
  726. fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  727. else
  728. fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  729. }
  730. }
  731. return true;
  732. }
  733. /*}}}*/
  734. pkgTagSection::~pkgTagSection() { delete d; }