// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: tagfile.cc,v 1.36 2003/04/27 05:59:14 doogie Exp $
+// $Id: tagfile.cc,v 1.37.2.2 2003/12/31 16:02:30 mdz Exp $
/* ######################################################################
Fast scanner for RFC-822 type header information
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
-#ifdef __GNUG__
-#pragma implementation "apt-pkg/tagfile.h"
-#endif
-
#include <apt-pkg/tagfile.h>
#include <apt-pkg/error.h>
#include <apt-pkg/strutl.h>
// TagFile::pkgTagFile - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
-pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long Size) : Fd(*pFd), Size(Size)
+pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long Size) :
+ Fd(*pFd),
+ Size(Size)
{
if (Fd.IsOpen() == false)
{
return;
}
- CurSize = Size;
Buffer = new char[Size];
Start = End = Buffer;
Done = false;
delete [] Buffer;
}
/*}}}*/
+// TagFile::Resize - Resize the internal buffer /*{{{*/
+// ---------------------------------------------------------------------
+/* Resize the internal buffer (double it in size). Fail if a maximum size
+ * size is reached.
+ */
+bool pkgTagFile::Resize()
+{
+ char *tmp;
+ unsigned long EndSize = End - Start;
+
+ // fail is the buffer grows too big
+ if(Size > 1024*1024+1)
+ return false;
+
+ // get new buffer and use it
+ tmp = new char[2*Size];
+ memcpy(tmp, Buffer, Size);
+ Size = Size*2;
+ delete [] Buffer;
+ Buffer = tmp;
+
+ // update the start/end pointers to the new buffer
+ Start = Buffer;
+ End = Start + EndSize;
+ return true;
+}
+ /*}}}*/
// TagFile::Step - Advance to the next section /*{{{*/
// ---------------------------------------------------------------------
-/* If the Section Scanner fails we refill the buffer and try again. */
+/* If the Section Scanner fails we refill the buffer and try again.
+ * If that fails too, double the buffer size and try again until a
+ * maximum buffer is reached.
+ */
bool pkgTagFile::Step(pkgTagSection &Tag)
{
- pkgTagSection::ScanFlags ret = Tag.Scan(Start,End - Start);
- if (ret == pkgTagSection::ScanEOF) {
- CurSize <<= 1;
+ while (Tag.Scan(Start,End - Start) == false)
+ {
if (Fill() == false)
return false;
- do {
- ret = Tag.Scan(Start,End - Start);
- if (ret == pkgTagSection::ScanEOF) {
- CurSize <<= 1;
- if (Fill() == false)
- break;
- }
- } while (ret == pkgTagSection::ScanEOF);
+
+ if(Tag.Scan(Start,End - Start))
+ break;
+
+ if (Resize() == false)
+ return _error->Error(_("Unable to parse package file %s (1)"),
+ Fd.Name().c_str());
}
- if (ret != pkgTagSection::ScanSuccess)
- return _error->Error(_("Unable to parse package file %s (1)"),
- Fd.Name().c_str());
Start += Tag.size();
iOffset += Tag.size();
if (Fill() == false)
return false;
- pkgTagSection::ScanFlags ret = Tag.Scan(Start,End - Start);
- if (ret == pkgTagSection::ScanEOF) {
- CurSize <<= 1;
- if (Fill() == false)
- return false;
- do {
- ret = Tag.Scan(Start,End - Start);
- if (ret == pkgTagSection::ScanEOF) {
- CurSize <<= 1;
- if (Fill() == false)
- break;
- }
- } while (ret == pkgTagSection::ScanEOF);
- }
- if (ret != pkgTagSection::ScanSuccess)
+ if (Tag.Scan(Start,End - Start) == true)
+ return true;
+
+ // This appends a double new line (for the real eof handling)
+ if (Fill() == false)
+ return false;
+
+ if (Tag.Scan(Start,End - Start) == false)
return _error->Error(_("Unable to parse package file %s (2)"),Fd.Name().c_str());
return true;
// ---------------------------------------------------------------------
/* This looks for the first double new line in the data stream. It also
indexes the tags in the section. This very simple hash function for the
- first 3 letters gives very good performance on the debian package files */
+ last 8 letters gives very good performance on the debian package files */
inline static unsigned long AlphaHash(const char *Text, const char *End = 0)
{
unsigned long Res = 0;
for (; Text != End && *Text != ':' && *Text != 0; Text++)
- Res = (unsigned long)(*Text) ^ (Res << 2);
+ Res = ((unsigned long)(*Text) & 0xDF) ^ (Res << 1);
return Res & 0xFF;
}
-enum pkgTagSection::ScanFlags pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
+bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
{
const char *End = Start + MaxLength;
Stop = Section = Start;
memset(AlphaIndexes,0,sizeof(AlphaIndexes));
if (Stop == 0)
- return ScanError;
-
+ return false;
+
TagCount = 0;
while (TagCount+1 < sizeof(Indexes)/sizeof(Indexes[0]) && Stop < End)
{
+ TrimRecord(true,End);
+
// Start a new index and add it to the hash
if (isspace(Stop[0]) == 0)
{
Stop = (const char *)memchr(Stop,'\n',End - Stop);
if (Stop == 0)
- return ScanEOF;
-
+ return false;
+
for (; Stop+1 < End && Stop[1] == '\r'; Stop++);
// Double newline marks the end of the record
if (Stop+1 < End && Stop[1] == '\n')
{
Indexes[TagCount] = Stop - Section;
- for (; Stop < End && (Stop[0] == '\n' || Stop[0] == '\r'); Stop++);
- return ScanSuccess;
+ TrimRecord(false,End);
+ return true;
}
Stop++;
}
- return ScanEOF;
+ return false;
+}
+ /*}}}*/
+// TagSection::TrimRecord - Trim off any garbage before/after a record /*{{{*/
+// ---------------------------------------------------------------------
+/* There should be exactly 2 newline at the end of the record, no more. */
+void pkgTagSection::TrimRecord(bool BeforeRecord, const char*& End)
+{
+ if (BeforeRecord == true)
+ return;
+ for (; Stop < End && (Stop[0] == '\n' || Stop[0] == '\r'); Stop++);
}
/*}}}*/
// TagSection::Trim - Trim off any trailing garbage /*{{{*/
return true;
}
/*}}}*/
-
// TFRewrite - Rewrite a control record /*{{{*/
// ---------------------------------------------------------------------
/* This writes the control record to stdout rewriting it as necessary. The
"Recommends",
"Suggests",
"Conflicts",
+ "Breaks",
"Conffiles",
"Filename",
"Size",
"MD5Sum",
- "SHA1Sum",
+ "SHA1",
+ "SHA256",
"MSDOS-Filename", // Obsolete
"Description",
0};