tagfile.cc 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  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 <apt-pkg/string_view.h>
  17. #include <list>
  18. #include <string>
  19. #include <stdio.h>
  20. #include <ctype.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <apti18n.h>
  24. /*}}}*/
  25. using std::string;
  26. using APT::StringView;
  27. class APT_HIDDEN pkgTagFilePrivate /*{{{*/
  28. {
  29. public:
  30. void Reset(FileFd * const pFd, unsigned long long const pSize, pkgTagFile::Flags const pFlags)
  31. {
  32. if (Buffer != NULL)
  33. free(Buffer);
  34. Buffer = NULL;
  35. Fd = pFd;
  36. Flags = pFlags;
  37. Start = NULL;
  38. End = NULL;
  39. Done = false;
  40. iOffset = 0;
  41. Size = pSize;
  42. isCommentedLine = false;
  43. chunks.clear();
  44. }
  45. pkgTagFilePrivate(FileFd * const pFd, unsigned long long const Size, pkgTagFile::Flags const pFlags) : Buffer(NULL)
  46. {
  47. Reset(pFd, Size, 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. unsigned long long Size;
  57. bool isCommentedLine;
  58. struct FileChunk
  59. {
  60. bool const good;
  61. size_t length;
  62. FileChunk(bool const pgood, size_t const plength) : good(pgood), length(plength) {}
  63. };
  64. std::list<FileChunk> chunks;
  65. ~pkgTagFilePrivate()
  66. {
  67. if (Buffer != NULL)
  68. free(Buffer);
  69. }
  70. };
  71. /*}}}*/
  72. class APT_HIDDEN pkgTagSectionPrivate /*{{{*/
  73. {
  74. public:
  75. pkgTagSectionPrivate()
  76. {
  77. }
  78. struct TagData {
  79. unsigned int StartTag;
  80. unsigned int EndTag;
  81. unsigned int StartValue;
  82. unsigned int NextInBucket;
  83. explicit TagData(unsigned int const StartTag) : StartTag(StartTag), EndTag(0), StartValue(0), NextInBucket(0) {}
  84. };
  85. std::vector<TagData> Tags;
  86. };
  87. /*}}}*/
  88. static unsigned long AlphaHash(const char *Text, size_t Length) /*{{{*/
  89. {
  90. /* This very simple hash function for the last 8 letters gives
  91. very good performance on the debian package files */
  92. if (Length > 8)
  93. {
  94. Text += (Length - 8);
  95. Length = 8;
  96. }
  97. unsigned long Res = 0;
  98. for (size_t i = 0; i < Length; ++i)
  99. Res = ((unsigned long)(Text[i]) & 0xDF) ^ (Res << 1);
  100. return Res & 0xFF;
  101. }
  102. /*}}}*/
  103. // TagFile::pkgTagFile - Constructor /*{{{*/
  104. pkgTagFile::pkgTagFile(FileFd * const pFd,pkgTagFile::Flags const pFlags, unsigned long long const Size)
  105. : d(new pkgTagFilePrivate(pFd, Size + 4, pFlags))
  106. {
  107. Init(pFd, pFlags, Size);
  108. }
  109. pkgTagFile::pkgTagFile(FileFd * const pFd,unsigned long long const Size)
  110. : pkgTagFile(pFd, pkgTagFile::STRICT, Size)
  111. {
  112. }
  113. void pkgTagFile::Init(FileFd * const pFd, pkgTagFile::Flags const pFlags, unsigned long long Size)
  114. {
  115. /* The size is increased by 4 because if we start with the Size of the
  116. filename we need to try to read 1 char more to see an EOF faster, 1
  117. char the end-pointer can be on and maybe 2 newlines need to be added
  118. to the end of the file -> 4 extra chars */
  119. Size += 4;
  120. d->Reset(pFd, Size, pFlags);
  121. if (d->Fd->IsOpen() == false)
  122. d->Start = d->End = d->Buffer = 0;
  123. else
  124. d->Buffer = (char*)malloc(sizeof(char) * Size);
  125. if (d->Buffer == NULL)
  126. d->Done = true;
  127. else
  128. d->Done = false;
  129. d->Start = d->End = d->Buffer;
  130. d->iOffset = 0;
  131. if (d->Done == false)
  132. Fill();
  133. }
  134. void pkgTagFile::Init(FileFd * const pFd,unsigned long long Size)
  135. {
  136. Init(pFd, pkgTagFile::STRICT, Size);
  137. }
  138. /*}}}*/
  139. // TagFile::~pkgTagFile - Destructor /*{{{*/
  140. pkgTagFile::~pkgTagFile()
  141. {
  142. delete d;
  143. }
  144. /*}}}*/
  145. // TagFile::Offset - Return the current offset in the buffer /*{{{*/
  146. APT_PURE unsigned long pkgTagFile::Offset()
  147. {
  148. return d->iOffset;
  149. }
  150. /*}}}*/
  151. // TagFile::Resize - Resize the internal buffer /*{{{*/
  152. // ---------------------------------------------------------------------
  153. /* Resize the internal buffer (double it in size). Fail if a maximum size
  154. * size is reached.
  155. */
  156. bool pkgTagFile::Resize()
  157. {
  158. // fail is the buffer grows too big
  159. if(d->Size > 1024*1024+1)
  160. return false;
  161. return Resize(d->Size * 2);
  162. }
  163. bool pkgTagFile::Resize(unsigned long long const newSize)
  164. {
  165. unsigned long long const EndSize = d->End - d->Start;
  166. // get new buffer and use it
  167. char* const newBuffer = static_cast<char*>(realloc(d->Buffer, sizeof(char) * newSize));
  168. if (newBuffer == NULL)
  169. return false;
  170. d->Buffer = newBuffer;
  171. d->Size = newSize;
  172. // update the start/end pointers to the new buffer
  173. d->Start = d->Buffer;
  174. d->End = d->Start + EndSize;
  175. return true;
  176. }
  177. /*}}}*/
  178. // TagFile::Step - Advance to the next section /*{{{*/
  179. // ---------------------------------------------------------------------
  180. /* If the Section Scanner fails we refill the buffer and try again.
  181. * If that fails too, double the buffer size and try again until a
  182. * maximum buffer is reached.
  183. */
  184. bool pkgTagFile::Step(pkgTagSection &Tag)
  185. {
  186. if(Tag.Scan(d->Start,d->End - d->Start) == false)
  187. {
  188. do
  189. {
  190. if (Fill() == false)
  191. return false;
  192. if(Tag.Scan(d->Start,d->End - d->Start, false))
  193. break;
  194. if (Resize() == false)
  195. return _error->Error(_("Unable to parse package file %s (%d)"),
  196. d->Fd->Name().c_str(), 1);
  197. } while (Tag.Scan(d->Start,d->End - d->Start, false) == false);
  198. }
  199. size_t tagSize = Tag.size();
  200. d->Start += tagSize;
  201. if ((d->Flags & pkgTagFile::SUPPORT_COMMENTS) == 0)
  202. d->iOffset += tagSize;
  203. else
  204. {
  205. auto first = d->chunks.begin();
  206. for (; first != d->chunks.end(); ++first)
  207. {
  208. if (first->good == false)
  209. d->iOffset += first->length;
  210. else
  211. {
  212. if (tagSize < first->length)
  213. {
  214. first->length -= tagSize;
  215. d->iOffset += tagSize;
  216. break;
  217. }
  218. else
  219. {
  220. tagSize -= first->length;
  221. d->iOffset += first->length;
  222. }
  223. }
  224. }
  225. d->chunks.erase(d->chunks.begin(), first);
  226. }
  227. Tag.Trim();
  228. return true;
  229. }
  230. /*}}}*/
  231. // TagFile::Fill - Top up the buffer /*{{{*/
  232. // ---------------------------------------------------------------------
  233. /* This takes the bit at the end of the buffer and puts it at the start
  234. then fills the rest from the file */
  235. static bool FillBuffer(pkgTagFilePrivate * const d)
  236. {
  237. unsigned long long Actual = 0;
  238. // See if only a bit of the file is left
  239. unsigned long long const dataSize = d->Size - ((d->End - d->Buffer) + 1);
  240. if (d->Fd->Read(d->End, dataSize, &Actual) == false)
  241. return false;
  242. if (Actual != dataSize)
  243. d->Done = true;
  244. d->End += Actual;
  245. return true;
  246. }
  247. static void RemoveCommentsFromBuffer(pkgTagFilePrivate * const d)
  248. {
  249. // look for valid comments in the buffer
  250. char * good_start = nullptr, * bad_start = nullptr;
  251. char * current = d->Start;
  252. if (d->isCommentedLine == false)
  253. {
  254. if (d->Start == d->Buffer)
  255. {
  256. // the start of the buffer is a newline as a record can't start
  257. // in the middle of a line by definition.
  258. if (*d->Start == '#')
  259. {
  260. d->isCommentedLine = true;
  261. ++current;
  262. if (current > d->End)
  263. d->chunks.emplace_back(false, 1);
  264. }
  265. }
  266. if (d->isCommentedLine == false)
  267. good_start = d->Start;
  268. else
  269. bad_start = d->Start;
  270. }
  271. else
  272. bad_start = d->Start;
  273. std::vector<std::pair<char*, size_t>> good_parts;
  274. while (current <= d->End)
  275. {
  276. size_t const restLength = (d->End - current);
  277. if (d->isCommentedLine == false)
  278. {
  279. current = static_cast<char*>(memchr(current, '#', restLength));
  280. if (current == nullptr)
  281. {
  282. size_t const goodLength = d->End - good_start;
  283. d->chunks.emplace_back(true, goodLength);
  284. if (good_start != d->Start)
  285. good_parts.push_back(std::make_pair(good_start, goodLength));
  286. break;
  287. }
  288. bad_start = current;
  289. --current;
  290. // ensure that this is really a comment and not a '#' in the middle of a line
  291. if (*current == '\n')
  292. {
  293. size_t const goodLength = (current - good_start) + 1;
  294. d->chunks.emplace_back(true, goodLength);
  295. good_parts.push_back(std::make_pair(good_start, goodLength));
  296. good_start = nullptr;
  297. d->isCommentedLine = true;
  298. }
  299. current += 2;
  300. }
  301. else // the current line is a comment
  302. {
  303. current = static_cast<char*>(memchr(current, '\n', restLength));
  304. if (current == nullptr)
  305. {
  306. d->chunks.emplace_back(false, (d->End - bad_start));
  307. break;
  308. }
  309. ++current;
  310. // is the next line a comment, too?
  311. if (current >= d->End || *current != '#')
  312. {
  313. d->chunks.emplace_back(false, (current - bad_start));
  314. good_start = current;
  315. bad_start = nullptr;
  316. d->isCommentedLine = false;
  317. }
  318. ++current;
  319. }
  320. }
  321. if (good_parts.empty() == false)
  322. {
  323. // we found comments, so move later parts over them
  324. current = d->Start;
  325. for (auto const &good: good_parts)
  326. {
  327. memmove(current, good.first, good.second);
  328. current += good.second;
  329. }
  330. d->End = current;
  331. }
  332. if (d->isCommentedLine == true)
  333. {
  334. // deal with a buffer containing only comments
  335. // or an (unfinished) comment at the end
  336. if (good_parts.empty() == true)
  337. d->End = d->Start;
  338. else
  339. d->Start = d->End;
  340. }
  341. else
  342. {
  343. // the buffer was all comment, but ended with the buffer
  344. if (good_parts.empty() == true && good_start >= d->End)
  345. d->End = d->Start;
  346. else
  347. d->Start = d->End;
  348. }
  349. }
  350. bool pkgTagFile::Fill()
  351. {
  352. unsigned long long const EndSize = d->End - d->Start;
  353. if (EndSize != 0)
  354. {
  355. memmove(d->Buffer,d->Start,EndSize);
  356. d->Start = d->End = d->Buffer + EndSize;
  357. }
  358. else
  359. d->Start = d->End = d->Buffer;
  360. unsigned long long Actual = 0;
  361. while (d->Done == false && d->Size > (Actual + 1))
  362. {
  363. if (FillBuffer(d) == false)
  364. return false;
  365. if ((d->Flags & pkgTagFile::SUPPORT_COMMENTS) != 0)
  366. RemoveCommentsFromBuffer(d);
  367. Actual = d->End - d->Buffer;
  368. }
  369. d->Start = d->Buffer;
  370. if (d->Done == true)
  371. {
  372. if (EndSize <= 3 && Actual == 0)
  373. return false;
  374. if (d->Size - (d->End - d->Buffer) < 4)
  375. return true;
  376. // Append a double new line if one does not exist
  377. unsigned int LineCount = 0;
  378. for (const char *E = d->End - 1; E - d->End < 6 && (*E == '\n' || *E == '\r'); E--)
  379. if (*E == '\n')
  380. ++LineCount;
  381. if (LineCount < 2)
  382. {
  383. if (static_cast<unsigned long long>(d->End - d->Buffer) >= d->Size)
  384. Resize(d->Size + 3);
  385. for (; LineCount < 2; ++LineCount)
  386. *d->End++ = '\n';
  387. }
  388. }
  389. return true;
  390. }
  391. /*}}}*/
  392. // TagFile::Jump - Jump to a pre-recorded location in the file /*{{{*/
  393. // ---------------------------------------------------------------------
  394. /* This jumps to a pre-recorded file location and reads the record
  395. that is there */
  396. bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long long Offset)
  397. {
  398. if ((d->Flags & pkgTagFile::SUPPORT_COMMENTS) == 0 &&
  399. // We are within a buffer space of the next hit..
  400. Offset >= d->iOffset && d->iOffset + (d->End - d->Start) > Offset)
  401. {
  402. unsigned long long Dist = Offset - d->iOffset;
  403. d->Start += Dist;
  404. d->iOffset += Dist;
  405. // if we have seen the end, don't ask for more
  406. if (d->Done == true)
  407. return Tag.Scan(d->Start, d->End - d->Start);
  408. else
  409. return Step(Tag);
  410. }
  411. // Reposition and reload..
  412. d->iOffset = Offset;
  413. d->Done = false;
  414. if (d->Fd->Seek(Offset) == false)
  415. return false;
  416. d->End = d->Start = d->Buffer;
  417. d->isCommentedLine = false;
  418. d->chunks.clear();
  419. if (Fill() == false)
  420. return false;
  421. if (Tag.Scan(d->Start, d->End - d->Start) == true)
  422. return true;
  423. // This appends a double new line (for the real eof handling)
  424. if (Fill() == false)
  425. return false;
  426. if (Tag.Scan(d->Start, d->End - d->Start, false) == false)
  427. return _error->Error(_("Unable to parse package file %s (%d)"),d->Fd->Name().c_str(), 2);
  428. return true;
  429. }
  430. /*}}}*/
  431. // pkgTagSection::pkgTagSection - Constructor /*{{{*/
  432. // ---------------------------------------------------------------------
  433. /* */
  434. APT_IGNORE_DEPRECATED_PUSH
  435. pkgTagSection::pkgTagSection()
  436. : Section(0), d(new pkgTagSectionPrivate()), Stop(0)
  437. {
  438. memset(&AlphaIndexes, 0, sizeof(AlphaIndexes));
  439. }
  440. APT_IGNORE_DEPRECATED_POP
  441. /*}}}*/
  442. // TagSection::Scan - Scan for the end of the header information /*{{{*/
  443. bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength, bool const Restart)
  444. {
  445. Section = Start;
  446. const char *End = Start + MaxLength;
  447. if (Restart == false && d->Tags.empty() == false)
  448. {
  449. Stop = Section + d->Tags.back().StartTag;
  450. if (End <= Stop)
  451. return false;
  452. Stop = (const char *)memchr(Stop,'\n',End - Stop);
  453. if (Stop == NULL)
  454. return false;
  455. ++Stop;
  456. }
  457. else
  458. {
  459. Stop = Section;
  460. if (d->Tags.empty() == false)
  461. {
  462. memset(&AlphaIndexes, 0, sizeof(AlphaIndexes));
  463. d->Tags.clear();
  464. }
  465. d->Tags.reserve(0x100);
  466. }
  467. unsigned int TagCount = d->Tags.size();
  468. if (Stop == 0)
  469. return false;
  470. pkgTagSectionPrivate::TagData lastTagData(0);
  471. lastTagData.EndTag = 0;
  472. unsigned long lastTagHash = 0;
  473. while (Stop < End)
  474. {
  475. TrimRecord(true,End);
  476. // this can happen when TrimRecord trims away the entire Record
  477. // (e.g. because it just contains comments)
  478. if(Stop == End)
  479. return true;
  480. // Start a new index and add it to the hash
  481. if (isspace_ascii(Stop[0]) == 0)
  482. {
  483. // store the last found tag
  484. if (lastTagData.EndTag != 0)
  485. {
  486. if (AlphaIndexes[lastTagHash] != 0)
  487. lastTagData.NextInBucket = AlphaIndexes[lastTagHash];
  488. APT_IGNORE_DEPRECATED_PUSH
  489. AlphaIndexes[lastTagHash] = TagCount;
  490. APT_IGNORE_DEPRECATED_POP
  491. d->Tags.push_back(lastTagData);
  492. }
  493. APT_IGNORE_DEPRECATED(++TagCount;)
  494. lastTagData = pkgTagSectionPrivate::TagData(Stop - Section);
  495. // find the colon separating tag and value
  496. char const * Colon = (char const *) memchr(Stop, ':', End - Stop);
  497. if (Colon == NULL)
  498. return false;
  499. // find the end of the tag (which might or might not be the colon)
  500. char const * EndTag = Colon;
  501. --EndTag;
  502. for (; EndTag > Stop && isspace_ascii(*EndTag) != 0; --EndTag)
  503. ;
  504. ++EndTag;
  505. lastTagData.EndTag = EndTag - Section;
  506. lastTagHash = AlphaHash(Stop, EndTag - Stop);
  507. // find the beginning of the value
  508. Stop = Colon + 1;
  509. for (; Stop < End && isspace_ascii(*Stop) != 0; ++Stop)
  510. if (*Stop == '\n' && Stop[1] != ' ')
  511. break;
  512. if (Stop >= End)
  513. return false;
  514. lastTagData.StartValue = Stop - Section;
  515. }
  516. Stop = (const char *)memchr(Stop,'\n',End - Stop);
  517. if (Stop == 0)
  518. return false;
  519. for (; Stop+1 < End && Stop[1] == '\r'; Stop++)
  520. /* nothing */
  521. ;
  522. // Double newline marks the end of the record
  523. if (Stop+1 < End && Stop[1] == '\n')
  524. {
  525. if (lastTagData.EndTag != 0)
  526. {
  527. if (AlphaIndexes[lastTagHash] != 0)
  528. lastTagData.NextInBucket = AlphaIndexes[lastTagHash];
  529. APT_IGNORE_DEPRECATED(AlphaIndexes[lastTagHash] = TagCount;)
  530. d->Tags.push_back(lastTagData);
  531. }
  532. pkgTagSectionPrivate::TagData const td(Stop - Section);
  533. d->Tags.push_back(td);
  534. TrimRecord(false,End);
  535. return true;
  536. }
  537. Stop++;
  538. }
  539. return false;
  540. }
  541. /*}}}*/
  542. // TagSection::TrimRecord - Trim off any garbage before/after a record /*{{{*/
  543. // ---------------------------------------------------------------------
  544. /* There should be exactly 2 newline at the end of the record, no more. */
  545. void pkgTagSection::TrimRecord(bool BeforeRecord, const char*& End)
  546. {
  547. if (BeforeRecord == true)
  548. return;
  549. for (; Stop < End && (Stop[0] == '\n' || Stop[0] == '\r'); Stop++);
  550. }
  551. /*}}}*/
  552. // TagSection::Trim - Trim off any trailing garbage /*{{{*/
  553. // ---------------------------------------------------------------------
  554. /* There should be exactly 1 newline at the end of the buffer, no more. */
  555. void pkgTagSection::Trim()
  556. {
  557. for (; Stop > Section + 2 && (Stop[-2] == '\n' || Stop[-2] == '\r'); Stop--);
  558. }
  559. /*}}}*/
  560. // TagSection::Exists - return True if a tag exists /*{{{*/
  561. bool pkgTagSection::Exists(StringView Tag) const
  562. {
  563. unsigned int tmp;
  564. return Find(Tag, tmp);
  565. }
  566. /*}}}*/
  567. // TagSection::Find - Locate a tag /*{{{*/
  568. // ---------------------------------------------------------------------
  569. /* This searches the section for a tag that matches the given string. */
  570. bool pkgTagSection::Find(StringView TagView,unsigned int &Pos) const
  571. {
  572. const char * const Tag = TagView.data();
  573. size_t const Length = TagView.length();
  574. unsigned int Bucket = AlphaIndexes[AlphaHash(Tag, Length)];
  575. if (Bucket == 0)
  576. return false;
  577. for (; Bucket != 0; Bucket = d->Tags[Bucket - 1].NextInBucket)
  578. {
  579. if ((d->Tags[Bucket - 1].EndTag - d->Tags[Bucket - 1].StartTag) != Length)
  580. continue;
  581. char const * const St = Section + d->Tags[Bucket - 1].StartTag;
  582. if (strncasecmp(Tag,St,Length) != 0)
  583. continue;
  584. Pos = Bucket - 1;
  585. return true;
  586. }
  587. Pos = 0;
  588. return false;
  589. }
  590. bool pkgTagSection::Find(StringView Tag,const char *&Start,
  591. const char *&End) const
  592. {
  593. unsigned int Pos;
  594. if (Find(Tag, Pos) == false)
  595. return false;
  596. Start = Section + d->Tags[Pos].StartValue;
  597. // Strip off the gunk from the end
  598. End = Section + d->Tags[Pos + 1].StartTag;
  599. if (unlikely(Start > End))
  600. return _error->Error("Internal parsing error");
  601. for (; isspace_ascii(End[-1]) != 0 && End > Start; --End);
  602. return true;
  603. }
  604. /*}}}*/
  605. // TagSection::FindS - Find a string /*{{{*/
  606. StringView pkgTagSection::Find(StringView Tag) const
  607. {
  608. const char *Start;
  609. const char *End;
  610. if (Find(Tag,Start,End) == false)
  611. return StringView();
  612. return StringView(Start, End - Start);
  613. }
  614. /*}}}*/
  615. // TagSection::FindRawS - Find a string /*{{{*/
  616. StringView pkgTagSection::FindRaw(StringView Tag) const
  617. {
  618. unsigned int Pos;
  619. if (Find(Tag, Pos) == false)
  620. return "";
  621. char const *Start = (char const *) memchr(Section + d->Tags[Pos].EndTag, ':', d->Tags[Pos].StartValue - d->Tags[Pos].EndTag);
  622. ++Start;
  623. char const *End = Section + d->Tags[Pos + 1].StartTag;
  624. if (unlikely(Start > End))
  625. return "";
  626. for (; isspace_ascii(End[-1]) != 0 && End > Start; --End);
  627. return StringView(Start, End - Start);
  628. }
  629. /*}}}*/
  630. // TagSection::FindI - Find an integer /*{{{*/
  631. // ---------------------------------------------------------------------
  632. /* */
  633. signed int pkgTagSection::FindI(StringView Tag,signed long Default) const
  634. {
  635. const char *Start;
  636. const char *Stop;
  637. if (Find(Tag,Start,Stop) == false)
  638. return Default;
  639. // Copy it into a temp buffer so we can use strtol
  640. char S[300];
  641. if ((unsigned)(Stop - Start) >= sizeof(S))
  642. return Default;
  643. strncpy(S,Start,Stop-Start);
  644. S[Stop - Start] = 0;
  645. errno = 0;
  646. char *End;
  647. signed long Result = strtol(S,&End,10);
  648. if (errno == ERANGE ||
  649. Result < std::numeric_limits<int>::min() || Result > std::numeric_limits<int>::max()) {
  650. errno = ERANGE;
  651. _error->Error(_("Cannot convert %s to integer: out of range"), S);
  652. }
  653. if (S == End)
  654. return Default;
  655. return Result;
  656. }
  657. /*}}}*/
  658. // TagSection::FindULL - Find an unsigned long long integer /*{{{*/
  659. // ---------------------------------------------------------------------
  660. /* */
  661. unsigned long long pkgTagSection::FindULL(StringView Tag, unsigned long long const &Default) const
  662. {
  663. const char *Start;
  664. const char *Stop;
  665. if (Find(Tag,Start,Stop) == false)
  666. return Default;
  667. // Copy it into a temp buffer so we can use strtoull
  668. char S[100];
  669. if ((unsigned)(Stop - Start) >= sizeof(S))
  670. return Default;
  671. strncpy(S,Start,Stop-Start);
  672. S[Stop - Start] = 0;
  673. char *End;
  674. unsigned long long Result = strtoull(S,&End,10);
  675. if (S == End)
  676. return Default;
  677. return Result;
  678. }
  679. /*}}}*/
  680. // TagSection::FindB - Find boolean value /*{{{*/
  681. // ---------------------------------------------------------------------
  682. /* */
  683. bool pkgTagSection::FindB(StringView Tag, bool Default) const
  684. {
  685. const char *Start, *Stop;
  686. if (Find(Tag, Start, Stop) == false)
  687. return Default;
  688. return StringToBool(string(Start, Stop));
  689. }
  690. /*}}}*/
  691. // TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
  692. // ---------------------------------------------------------------------
  693. /* The bits marked in Flag are masked on/off in Flags */
  694. bool pkgTagSection::FindFlag(StringView Tag, uint8_t &Flags,
  695. uint8_t const Flag) const
  696. {
  697. const char *Start;
  698. const char *Stop;
  699. if (Find(Tag,Start,Stop) == false)
  700. return true;
  701. return FindFlag(Flags, Flag, Start, Stop);
  702. }
  703. bool pkgTagSection::FindFlag(uint8_t &Flags, uint8_t const Flag,
  704. char const* const Start, char const* const Stop)
  705. {
  706. switch (StringToBool(string(Start, Stop)))
  707. {
  708. case 0:
  709. Flags &= ~Flag;
  710. return true;
  711. case 1:
  712. Flags |= Flag;
  713. return true;
  714. default:
  715. _error->Warning("Unknown flag value: %s",string(Start,Stop).c_str());
  716. return true;
  717. }
  718. return true;
  719. }
  720. bool pkgTagSection::FindFlag(StringView Tag,unsigned long &Flags,
  721. unsigned long Flag) const
  722. {
  723. const char *Start;
  724. const char *Stop;
  725. if (Find(Tag,Start,Stop) == false)
  726. return true;
  727. return FindFlag(Flags, Flag, Start, Stop);
  728. }
  729. bool pkgTagSection::FindFlag(unsigned long &Flags, unsigned long Flag,
  730. char const* Start, char const* Stop)
  731. {
  732. switch (StringToBool(string(Start, Stop)))
  733. {
  734. case 0:
  735. Flags &= ~Flag;
  736. return true;
  737. case 1:
  738. Flags |= Flag;
  739. return true;
  740. default:
  741. _error->Warning("Unknown flag value: %s",string(Start,Stop).c_str());
  742. return true;
  743. }
  744. return true;
  745. }
  746. /*}}}*/
  747. void pkgTagSection::Get(const char *&Start,const char *&Stop,unsigned int I) const/*{{{*/
  748. {
  749. Start = Section + d->Tags[I].StartTag;
  750. Stop = Section + d->Tags[I+1].StartTag;
  751. }
  752. /*}}}*/
  753. APT_PURE unsigned int pkgTagSection::Count() const { /*{{{*/
  754. if (d->Tags.empty() == true)
  755. return 0;
  756. // the last element is just marking the end and isn't a real one
  757. return d->Tags.size() - 1;
  758. }
  759. /*}}}*/
  760. // TagSection::Write - Ordered (re)writing of fields /*{{{*/
  761. pkgTagSection::Tag pkgTagSection::Tag::Remove(std::string const &Name)
  762. {
  763. return Tag(REMOVE, Name, "");
  764. }
  765. pkgTagSection::Tag pkgTagSection::Tag::Rename(std::string const &OldName, std::string const &NewName)
  766. {
  767. return Tag(RENAME, OldName, NewName);
  768. }
  769. pkgTagSection::Tag pkgTagSection::Tag::Rewrite(std::string const &Name, std::string const &Data)
  770. {
  771. if (Data.empty() == true)
  772. return Tag(REMOVE, Name, "");
  773. else
  774. return Tag(REWRITE, Name, Data);
  775. }
  776. static bool WriteTag(FileFd &File, std::string Tag, StringView Value)
  777. {
  778. if (Value.empty() || isspace_ascii(Value[0]) != 0)
  779. Tag.append(":");
  780. else
  781. Tag.append(": ");
  782. Tag.append(Value.data(), Value.length());
  783. Tag.append("\n");
  784. return File.Write(Tag.c_str(), Tag.length());
  785. }
  786. static bool RewriteTags(FileFd &File, pkgTagSection const * const This, char const * const Tag,
  787. std::vector<pkgTagSection::Tag>::const_iterator &R,
  788. std::vector<pkgTagSection::Tag>::const_iterator const &REnd)
  789. {
  790. size_t const TagLen = strlen(Tag);
  791. for (; R != REnd; ++R)
  792. {
  793. std::string data;
  794. if (R->Name.length() == TagLen && strncasecmp(R->Name.c_str(), Tag, R->Name.length()) == 0)
  795. {
  796. if (R->Action != pkgTagSection::Tag::REWRITE)
  797. break;
  798. data = R->Data;
  799. }
  800. else if(R->Action == pkgTagSection::Tag::RENAME && R->Data.length() == TagLen &&
  801. strncasecmp(R->Data.c_str(), Tag, R->Data.length()) == 0)
  802. data = This->FindRaw(R->Name.c_str()).to_string();
  803. else
  804. continue;
  805. return WriteTag(File, Tag, data);
  806. }
  807. return true;
  808. }
  809. bool pkgTagSection::Write(FileFd &File, char const * const * const Order, std::vector<Tag> const &Rewrite) const
  810. {
  811. // first pass: Write everything we have an order for
  812. if (Order != NULL)
  813. {
  814. for (unsigned int I = 0; Order[I] != 0; ++I)
  815. {
  816. std::vector<Tag>::const_iterator R = Rewrite.begin();
  817. if (RewriteTags(File, this, Order[I], R, Rewrite.end()) == false)
  818. return false;
  819. if (R != Rewrite.end())
  820. continue;
  821. if (Exists(Order[I]) == false)
  822. continue;
  823. if (WriteTag(File, Order[I], FindRaw(Order[I])) == false)
  824. return false;
  825. }
  826. }
  827. // second pass: See if we have tags which aren't ordered
  828. if (d->Tags.empty() == false)
  829. {
  830. for (std::vector<pkgTagSectionPrivate::TagData>::const_iterator T = d->Tags.begin(); T != d->Tags.end() - 1; ++T)
  831. {
  832. char const * const fieldname = Section + T->StartTag;
  833. size_t fieldnamelen = T->EndTag - T->StartTag;
  834. if (Order != NULL)
  835. {
  836. unsigned int I = 0;
  837. for (; Order[I] != 0; ++I)
  838. {
  839. if (fieldnamelen == strlen(Order[I]) && strncasecmp(fieldname, Order[I], fieldnamelen) == 0)
  840. break;
  841. }
  842. if (Order[I] != 0)
  843. continue;
  844. }
  845. std::string const name(fieldname, fieldnamelen);
  846. std::vector<Tag>::const_iterator R = Rewrite.begin();
  847. if (RewriteTags(File, this, name.c_str(), R, Rewrite.end()) == false)
  848. return false;
  849. if (R != Rewrite.end())
  850. continue;
  851. if (WriteTag(File, name, FindRaw(name)) == false)
  852. return false;
  853. }
  854. }
  855. // last pass: see if there are any rewrites remaining we haven't done yet
  856. for (std::vector<Tag>::const_iterator R = Rewrite.begin(); R != Rewrite.end(); ++R)
  857. {
  858. if (R->Action == Tag::REMOVE)
  859. continue;
  860. std::string const name = ((R->Action == Tag::RENAME) ? R->Data : R->Name);
  861. if (Exists(name.c_str()))
  862. continue;
  863. if (Order != NULL)
  864. {
  865. unsigned int I = 0;
  866. for (; Order[I] != 0; ++I)
  867. {
  868. if (strncasecmp(name.c_str(), Order[I], name.length()) == 0 && name.length() == strlen(Order[I]))
  869. break;
  870. }
  871. if (Order[I] != 0)
  872. continue;
  873. }
  874. if (WriteTag(File, name, ((R->Action == Tag::RENAME) ? FindRaw(R->Name) : R->Data)) == false)
  875. return false;
  876. }
  877. return true;
  878. }
  879. /*}}}*/
  880. void pkgUserTagSection::TrimRecord(bool /*BeforeRecord*/, const char* &End)/*{{{*/
  881. {
  882. for (; Stop < End && (Stop[0] == '\n' || Stop[0] == '\r' || Stop[0] == '#'); Stop++)
  883. if (Stop[0] == '#')
  884. Stop = (const char*) memchr(Stop,'\n',End-Stop);
  885. }
  886. /*}}}*/
  887. #include "tagfile-order.c"
  888. // TFRewrite - Rewrite a control record /*{{{*/
  889. // ---------------------------------------------------------------------
  890. /* This writes the control record to stdout rewriting it as necessary. The
  891. override map item specificies the rewriting rules to follow. This also
  892. takes the time to sort the feild list. */
  893. APT_IGNORE_DEPRECATED_PUSH
  894. bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[],
  895. TFRewriteData *Rewrite)
  896. {
  897. unsigned char Visited[256]; // Bit 1 is Order, Bit 2 is Rewrite
  898. for (unsigned I = 0; I != 256; I++)
  899. Visited[I] = 0;
  900. // Set new tag up as necessary.
  901. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  902. {
  903. if (Rewrite[J].NewTag == 0)
  904. Rewrite[J].NewTag = Rewrite[J].Tag;
  905. }
  906. // Write all all of the tags, in order.
  907. if (Order != NULL)
  908. {
  909. for (unsigned int I = 0; Order[I] != 0; I++)
  910. {
  911. bool Rewritten = false;
  912. // See if this is a field that needs to be rewritten
  913. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  914. {
  915. if (strcasecmp(Rewrite[J].Tag,Order[I]) == 0)
  916. {
  917. Visited[J] |= 2;
  918. if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
  919. {
  920. if (isspace_ascii(Rewrite[J].Rewrite[0]))
  921. fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  922. else
  923. fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  924. }
  925. Rewritten = true;
  926. break;
  927. }
  928. }
  929. // See if it is in the fragment
  930. unsigned Pos;
  931. if (Tags.Find(StringView(Order[I]),Pos) == false)
  932. continue;
  933. Visited[Pos] |= 1;
  934. if (Rewritten == true)
  935. continue;
  936. /* Write out this element, taking a moment to rewrite the tag
  937. in case of changes of case. */
  938. const char *Start;
  939. const char *Stop;
  940. Tags.Get(Start,Stop,Pos);
  941. if (fputs(Order[I],Output) < 0)
  942. return _error->Errno("fputs","IO Error to output");
  943. Start += strlen(Order[I]);
  944. if (fwrite(Start,Stop - Start,1,Output) != 1)
  945. return _error->Errno("fwrite","IO Error to output");
  946. if (Stop[-1] != '\n')
  947. fprintf(Output,"\n");
  948. }
  949. }
  950. // Now write all the old tags that were missed.
  951. for (unsigned int I = 0; I != Tags.Count(); I++)
  952. {
  953. if ((Visited[I] & 1) == 1)
  954. continue;
  955. const char *Start;
  956. const char *Stop;
  957. Tags.Get(Start,Stop,I);
  958. const char *End = Start;
  959. for (; End < Stop && *End != ':'; End++);
  960. // See if this is a field that needs to be rewritten
  961. bool Rewritten = false;
  962. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  963. {
  964. if (stringcasecmp(Start,End,Rewrite[J].Tag) == 0)
  965. {
  966. Visited[J] |= 2;
  967. if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
  968. {
  969. if (isspace_ascii(Rewrite[J].Rewrite[0]))
  970. fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  971. else
  972. fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  973. }
  974. Rewritten = true;
  975. break;
  976. }
  977. }
  978. if (Rewritten == true)
  979. continue;
  980. // Write out this element
  981. if (fwrite(Start,Stop - Start,1,Output) != 1)
  982. return _error->Errno("fwrite","IO Error to output");
  983. if (Stop[-1] != '\n')
  984. fprintf(Output,"\n");
  985. }
  986. // Now write all the rewrites that were missed
  987. for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
  988. {
  989. if ((Visited[J] & 2) == 2)
  990. continue;
  991. if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
  992. {
  993. if (isspace_ascii(Rewrite[J].Rewrite[0]))
  994. fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  995. else
  996. fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
  997. }
  998. }
  999. return true;
  1000. }
  1001. APT_IGNORE_DEPRECATED_POP
  1002. /*}}}*/
  1003. pkgTagSection::~pkgTagSection() { delete d; }