On Mon, May 16, 2005 at 04:20:28PM +0200, Christian Aichinger wrote:
> The patch is available in apt--export--0--patch-1.

Hi,
the archive is offline now, so I'm sending the patch here. It still
applies to apt in unstable.

Cheers,
Christian Aichinger
--- orig/apt-pkg/tagfile.cc
+++ mod/apt-pkg/tagfile.cc
@@ -80,48 +80,154 @@
    return true;
 }
                                                                        /*}}}*/
-// TagFile::Fill - Top up the buffer                                   /*{{{*/
+// BuildCompleteBuffer - Build the real Buffer from its parts          /*{{{*/
 // ---------------------------------------------------------------------
-/* This takes the bit at the end of the buffer and puts it at the start
-   then fills the rest from the file */
+// (Utility function for TagFile::Fill()
+/* Copies all the data from [Start, End[, Buffers and Buf into a newly
+   allocated memory region that is returned in Result and ResultLen.
+   2 Bytes are guaranteed to be available at the end for a possible \n\n
+   */
+void BuildCompleteBuffer(
+         char* StartBuf, unsigned long StartLen,
+         const vector<char*> &Buffers, unsigned long BuffersLen,
+         char* EndBuf, unsigned long EndLen,
+         char** Result, unsigned long* ResultLen)
+{
+   unsigned long Needed = StartLen + Buffers.size()*BuffersLen + EndLen + 2;
+   char *Res = new char[Needed];
+   char *i = Res;
+
+
+   memcpy(i, StartBuf, StartLen);
+   i += StartLen;
+
+   for (vector<char*>::const_iterator BufIter = Buffers.begin();
+                                       BufIter != Buffers.end(); BufIter++) {
+      memcpy(i, *BufIter, BuffersLen);
+      i += BuffersLen;
+   }
+
+   memcpy(i, EndBuf, EndLen);
+   i += EndLen;
+
+   *Result = Res;
+   *ResultLen = i - Res;
+}
+                                                                       /*}}}*/
+// SearchDoubleNewline - Search for a \n[\r]*\n sequence               /*{{{*/
+// ---------------------------------------------------------------------
+// (Utility function for TagFile::Fill()
+/* Searches for a double-newline in [Start, End[ and returns true if it's found
+*/
+static bool SearchDoubleNewline(const void *Start, const void *End_)
+{
+   const char *NewLine = static_cast<const char *>(Start);
+   const char *End = static_cast<const char *>(End_);
+
+   while (1) {
+       NewLine = static_cast<const char *>(memchr(NewLine, '\n', End - 
NewLine));
+       if (!NewLine)
+           return false;
+
+       do { NewLine++; }
+       while ((NewLine < End) && (*NewLine == '\r'));
+
+       if (NewLine >= End)
+         return false;
+
+       if (*NewLine == '\n')
+         return true;
+   }
+}
+                                                                       /*}}}*/
+// AppendDoubleNewline - Appends a double-newline if necessary         /*{{{*/
+// ---------------------------------------------------------------------
+// (Utility function for TagFile::Fill()
+/* Looks if the buffer already ends in a double-Newline, and adds one if
+   necessary */
+static unsigned long AppendDoubleNewline(char *Start, char* End)
+{
+   // Append a double new line if one does not exist
+   unsigned int LineCount = 0;
+   for (const char *p = End - 1; (*p == '\n' || *p == '\r') && 
+                                (LineCount < 2) && (p > Start); p--) {
+      if (*p == '\n')
+        LineCount++;
+   }
+   for (; LineCount < 2; LineCount++)
+      *End++ = '\n';
+
+   return End-Start;
+}
+                                                                       /*}}}*/
+// DeleteElements - Calls delete [] on all elements in the vector      /*{{{*/
+// ---------------------------------------------------------------------
+// delete[]s all elements in a Buffers vector passed to it.
+static inline void DeleteElements(vector<char*> Buffers) {
+   for (vector<char *>::iterator BufIter = Buffers.begin();
+       BufIter != Buffers.end();
+       BufIter++)
+      delete [] *BufIter;
+}
+                                                                       /*}}}*/
+// TagFile::Fill - Prepare Buffer for pkgTagSection.Scan()             /*{{{*/
+// ---------------------------------------------------------------------
+/* This function makes sure that a blank line is in the buffer, making it
+   useable for pkgTagSection.Scan(). If necessary data is read from the file. 
+   */
 bool pkgTagFile::Fill()
 {
-   unsigned long EndSize = End - Start;
+   if (SearchDoubleNewline(Start, End))
+      // we've found a double newline in the current buffer region, so we don't
+      // need to do anything.
+      return true;
+
+   if (Done)
+      // We're done, but SearchDoubleNewline didn't find a double NL in the
+      // current buffer space. So either something is going terribly wrong,
+      // or we're called at the EOF when all the data has been parsed
+      // already. Either way, there's nothing we can do.
+      return false;
+
+   vector<char*> Buffers;
    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)
+
+   // Load chunks from the file until we hit EOF or find a double-NL
+   while (true) {
+      char *NewBuf = new char[Size];
+
+      if (Fd.Read(NewBuf, Size, &Actual) == false) {
+        delete [] NewBuf;
+        DeleteElements(Buffers);
         return false;
-      if (Actual != Size - (End - Buffer))
+      }
+      if (Actual != Size)
         Done = true;
-      End += Actual;
-   }
-   
-   if (Done == true)
-   {
-      if (EndSize <= 3 && Actual == 0)
-        return false;
-      if (Size - (End - Buffer) < 4)
+
+      if (Done || SearchDoubleNewline(NewBuf, NewBuf+Actual)) {
+        char *Result;
+        unsigned long ResultLen;
+        // Create a new buffer, and copy all the accumulated data into it.
+        BuildCompleteBuffer(Start, End-Start, Buffers, Size, NewBuf, Actual,
+              &Result, &ResultLen);
+
+        if (Done)
+           ResultLen = AppendDoubleNewline(Result, Result+ResultLen);
+
+        // Get rid of all the stuff we don't need anymore
+        delete [] Buffer;
+        delete [] NewBuf;
+        DeleteElements(Buffers);
+
+        Buffer = Result;
+        Start = Result;
+        End = Result+ResultLen;
+
         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;
+      }
+
+      Buffers.push_back(NewBuf);
    }
-   
-   return true;
 }
                                                                        /*}}}*/
 // TagFile::Jump - Jump to a pre-recorded location in the file         /*{{{*/

Attachment: signature.asc
Description: Digital signature

Reply via email to