From 99c2e5aca0b8284762158b5052766a7d64bf4ffd Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 26 Jul 2006 15:57:51 +0200 Subject: * suport both MMapable files and non-mmapable files --- apt-pkg/tagfile.cc | 115 +++++++++++++++++++++++++++++++++++++++++++++-------- apt-pkg/tagfile.h | 5 ++- 2 files changed, 103 insertions(+), 17 deletions(-) (limited to 'apt-pkg') diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc index 25e2930fa..8fcbeb23b 100644 --- a/apt-pkg/tagfile.cc +++ b/apt-pkg/tagfile.cc @@ -33,21 +33,32 @@ using std::string; /* */ pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long Size) : Fd(*pFd), - Size(Size) + Size(Size), + Map(NULL), + Buffer(0) { - if (Fd.IsOpen() == false || Fd.Size() == 0) + if (Fd.IsOpen() == false) { - Buffer = 0; Start = End = Buffer = 0; + Done = true; iOffset = 0; Map = NULL; return; } - Map = new MMap (Fd, MMap::Public | MMap::ReadOnly); - Buffer = (char *) Map->Data (); - Start = Buffer; - End = Buffer + Map->Size (); + // check if we can MMap it + if(Fd.Size() == 0) + { + Buffer = new char[Size]; + Start = End = Buffer; + Done = false; + Fill(); + } else { + Map = new MMap (Fd, MMap::Public | MMap::ReadOnly); + Buffer = (char *) Map->Data (); + Start = Buffer; + End = Buffer + Map->Size (); + } iOffset = 0; } /*}}}*/ @@ -56,6 +67,7 @@ pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long Size) : /* */ pkgTagFile::~pkgTagFile() { + if(!Map) delete [] Buffer; delete Map; } /*}}}*/ @@ -64,18 +76,70 @@ pkgTagFile::~pkgTagFile() /* If the Section Scanner fails we refill the buffer and try again. */ bool pkgTagFile::Step(pkgTagSection &Tag) { - if (Start == End) + if ((Map != NULL) && (Start == End)) return false; if (Tag.Scan(Start,End - Start) == false) { - return _error->Error(_("Unable to parse package file %s (1)"), - Fd.Name().c_str()); + if (Map != NULL) + return _error->Error(_("Unable to parse package file %s (1)"), + Fd.Name().c_str()); + + if (Fill() == false) + return false; + + if (Tag.Scan(Start,End - Start) == false) + return _error->Error(_("Unable to parse package file %s (1)"), + Fd.Name().c_str()); } Start += Tag.size(); iOffset += Tag.size(); Tag.Trim(); + return true; +} + /*}}}*/ +// TagFile::Fill - Top up the buffer /*{{{*/ +// --------------------------------------------------------------------- +/* This takes the bit at the end of the buffer and puts it at the start + 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; + } + return true; } /*}}}*/ @@ -94,12 +158,31 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset) return Step(Tag); } - // Reposition and reload.. iOffset = Offset; - Start = Buffer + iOffset; + if (Map != NULL) + { + Start = Buffer + iOffset; + } + else + { + // Reposition and reload.. + Done = false; + if (Fd.Seek(Offset) == false) + return false; + End = Start = Buffer; - // Start != End is a special case to not fail on empty TagFiles - if (Start != End && Tag.Scan(Start,End - Start) == false) + 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()); return true; @@ -157,8 +240,8 @@ bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength) if ((Stop+1 >= End) && (End[-1] == '\n' || End[-1] == '\r')) { - Indexes[TagCount] = (End - 1) - Section; - return true; + Indexes[TagCount] = (End - 1) - Section; + return true; } return false; diff --git a/apt-pkg/tagfile.h b/apt-pkg/tagfile.h index 5cff2681c..dd481ba51 100644 --- a/apt-pkg/tagfile.h +++ b/apt-pkg/tagfile.h @@ -74,16 +74,19 @@ class pkgTagFile char *Buffer; char *Start; char *End; + bool Done; unsigned long iOffset; unsigned long Size; + bool Fill(); + public: bool Step(pkgTagSection &Section); inline unsigned long Offset() {return iOffset;}; bool Jump(pkgTagSection &Tag,unsigned long Offset); - pkgTagFile(FileFd *F,unsigned long Size = 32*1024); + pkgTagFile(FileFd *F,unsigned long Size = 64*1024); ~pkgTagFile(); }; -- cgit v1.2.3