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 /*{{{*/
signature.asc
Description: Digital signature