// ---------------------------------------------------------------------
/* */
pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long Size) :
- Fd(*pFd),
- Size(Size)
+ Fd(*pFd)
{
- if (Fd.IsOpen() == false)
+ if (Fd.IsOpen() == false || Fd.Size() == 0)
{
+ _error->Discard();
+ Map = NULL;
Buffer = 0;
Start = End = Buffer = 0;
Done = true;
return;
}
- Buffer = new char[Size];
+ Map = new MMap(*pFd, MMap::ReadOnly);
+ Buffer = reinterpret_cast<char *>(Map->Data());
Start = End = Buffer;
Done = false;
iOffset = 0;
/* */
pkgTagFile::~pkgTagFile()
{
- delete [] Buffer;
+ delete Map;
}
/*}}}*/
-// 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.
*/
bool pkgTagFile::Step(pkgTagSection &Tag)
{
- while (Tag.Scan(Start,End - Start) == false)
+ if (Tag.Scan(Start,End - Start) == false)
{
- if (Fill() == false)
- return false;
-
- if(Tag.Scan(Start,End - Start))
- break;
-
- if (Resize() == false)
+ if (Start == End)
+ return false;
+ else
return _error->Error(_("Unable to parse package file %s (1)"),
Fd.Name().c_str());
}
then fills the rest from the file */
bool pkgTagFile::Fill()
{
- unsigned long EndSize = End - Start;
- unsigned long Actual = 0;
-
- memmove(Buffer,Start,EndSize);
- Start = Buffer;
- End = Buffer + EndSize;
-
- if (Done == false)
- {
- // See if only a bit of the file is left
- if (Fd.Read(End,Size - (End - Buffer),&Actual) == false)
- return false;
- if (Actual != Size - (End - Buffer))
- Done = true;
- End += Actual;
- }
-
- if (Done == true)
- {
- if (EndSize <= 3 && Actual == 0)
- return false;
- if (Size - (End - Buffer) < 4)
- return true;
-
- // Append a double new line if one does not exist
- unsigned int LineCount = 0;
- for (const char *E = End - 1; E - End < 6 && (*E == '\n' || *E == '\r'); E--)
- if (*E == '\n')
- LineCount++;
- for (; LineCount < 2; LineCount++)
- *End++ = '\n';
-
- return true;
- }
-
+ unsigned int Size(Map->Size());
+ End = Buffer + Size;
+ if (iOffset >= Size)
+ return false;
+ Start = Buffer + iOffset;
return true;
}
/*}}}*/
// Reposition and reload..
iOffset = Offset;
Done = false;
- if (Fd.Seek(Offset) == false)
- return false;
End = Start = Buffer;
if (Fill() == false)
return false;
- 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());
if (Stop == 0)
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)
{
Indexes[TagCount++] = Stop - Section;
- AlphaIndexes[AlphaHash(Stop,End)] = TagCount;
+ unsigned long hash(AlphaHash(Stop, End));
+ while (AlphaIndexes[hash] != 0)
+ hash = (hash + 1) % (sizeof(AlphaIndexes) / sizeof(AlphaIndexes[0]));
+ AlphaIndexes[hash] = TagCount;
}
Stop = (const char *)memchr(Stop,'\n',End - Stop);
- if (Stop == 0)
- return false;
-
+ if (Stop == 0) {
+ Stop = End;
+ goto end;
+ }
+
for (; Stop+1 < End && Stop[1] == '\r'; Stop++);
// Double newline marks the end of the record
- if (Stop+1 < End && Stop[1] == '\n')
- {
+ if (Stop+1 == End || Stop[1] == '\n')
+ end: {
Indexes[TagCount] = Stop - Section;
- for (; Stop < End && (Stop[0] == '\n' || Stop[0] == '\r'); Stop++);
+ TrimRecord(false,End);
return true;
}
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 /*{{{*/
// ---------------------------------------------------------------------
/* There should be exactly 1 newline at the end of the buffer, no more. */
bool pkgTagSection::Find(const char *Tag,unsigned &Pos) const
{
unsigned int Length = strlen(Tag);
- unsigned int I = AlphaIndexes[AlphaHash(Tag)];
- if (I == 0)
- return false;
- I--;
+ unsigned int J = AlphaHash(Tag);
- for (unsigned int Counter = 0; Counter != TagCount; Counter++,
- I = (I+1)%TagCount)
+ for (unsigned int Counter = 0; Counter != TagCount; Counter++,
+ J = (J+1)%(sizeof(AlphaIndexes)/sizeof(AlphaIndexes[0])))
{
+ unsigned int I = AlphaIndexes[J];
+ if (I == 0)
+ return false;
+ I--;
+
const char *St;
St = Section + Indexes[I];
if (strncasecmp(Tag,St,Length) != 0)
const char *&End) const
{
unsigned int Length = strlen(Tag);
- unsigned int I = AlphaIndexes[AlphaHash(Tag)];
- if (I == 0)
- return false;
- I--;
+ unsigned int J = AlphaHash(Tag);
- for (unsigned int Counter = 0; Counter != TagCount; Counter++,
- I = (I+1)%TagCount)
+ for (unsigned int Counter = 0; Counter != TagCount; Counter++,
+ J = (J+1)%(sizeof(AlphaIndexes)/sizeof(AlphaIndexes[0])))
{
+ unsigned int I = AlphaIndexes[J];
+ if (I == 0)
+ return false;
+ I--;
+
const char *St;
St = Section + Indexes[I];
if (strncasecmp(Tag,St,Length) != 0)
return true;
}
/*}}}*/
-
// TFRewrite - Rewrite a control record /*{{{*/
// ---------------------------------------------------------------------
/* This writes the control record to stdout rewriting it as necessary. The