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