]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/tagfile.cc
merged from apt--mvo
[apt.git] / apt-pkg / tagfile.cc
index fc020436ca37345e1e062be8d9d8371a60e52afd..893cb8ee7700ae2055a70517a9c6753143b397f6 100644 (file)
    ##################################################################### */
                                                                        /*}}}*/
 // 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>
@@ -35,20 +31,20 @@ pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long Size) :
      Fd(*pFd),
      Size(Size)
 {
-   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 ();
+   Buffer = new char[Size];
+   Start = End = Buffer;
+   Done = false;
    iOffset = 0;
+   Fill();
 }
                                                                        /*}}}*/
 // TagFile::~pkgTagFile - Destructor                                   /*{{{*/
@@ -56,26 +52,104 @@ pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long Size) :
 /* */
 pkgTagFile::~pkgTagFile()
 {
-   delete Map;
+   delete [] Buffer;
 }
                                                                        /*}}}*/
-// TagFile::Step - Advance to the next section                         /*{{{*/
+// TagFile::Resize - Resize the internal buffer                                /*{{{*/
 // ---------------------------------------------------------------------
-/* If the Section Scanner fails we refill the buffer and try again. */
-bool pkgTagFile::Step(pkgTagSection &Tag)
+/* Resize the internal buffer (double it in size). Fail if a maximum size
+ * size is reached.
+ */
+bool pkgTagFile::Resize()
 {
-   if (Start == End)
+   char *tmp;
+   unsigned long EndSize = End - Start;
+
+   // fail is the buffer grows too big
+   if(Size > 1024*1024+1)
       return false;
 
-   if (Tag.Scan(Start,End - Start) == 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 that fails too, double the buffer size and try again until a
+ * maximum buffer is reached.
+ */
+bool pkgTagFile::Step(pkgTagSection &Tag)
+{
+   while (Tag.Scan(Start,End - Start) == false)
    {
-      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))
+        break;
+
+      if (Resize() == 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;
 }
                                                                        /*}}}*/
@@ -96,7 +170,20 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
 
    // Reposition and reload..
    iOffset = Offset;
-   Start = Buffer + iOffset;
+   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());
@@ -108,12 +195,12 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
 // ---------------------------------------------------------------------
 /* 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;
 }
 
@@ -123,7 +210,7 @@ bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
    Stop = Section = Start;
    memset(AlphaIndexes,0,sizeof(AlphaIndexes));
 
-   if (Stop == 0 || MaxLength == 0)
+   if (Stop == 0)
       return false;
    
    TagCount = 0;
@@ -154,12 +241,6 @@ bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
       Stop++;
    }
 
-   if ((Stop+1 >= End) && (End[-1] == '\n' || End[-1] == '\r'))
-   {
-       Indexes[TagCount] = (End - 1) - Section;
-       return true;
-   }
-
    return false;
 }
                                                                        /*}}}*/
@@ -338,6 +419,7 @@ static const char *iTFRewritePackageOrder[] = {
                           "Recommends",
                           "Suggests",
                           "Conflicts",
+                          "Breaks",
                           "Conffiles",
                           "Filename",
                           "Size",