Files
CoreUtils/IMFBoundary.h
Brad ArantandClaude Sonnet 5 a033cc6718 Add StreamReader and rebuild Parser/LineParser/IMFHeader/IMFBoundary on it
Introduces StreamReader to accumulate socket data delivered in arbitrary
chunks into one buffer, so a Parser can build an object (a line, a header
block, a MIME boundary) that spans any number of packets without losing
its place. Parser is redesigned around this: no longer inherits MString
(was redundant with its own buffer member), takes a StreamReader&, and
drives a resumable COMPLETE/INCOMPLETE/DATA_AVAIL state-machine protocol
via doParse(). LineParser, IMFHeader, and IMFBoundary are rewritten as
real, working resumable parsers against the shared buffer instead of the
previous non-compiling stubs (mismatched constructors/return types, a
syntax error, checkParse() never implemented).

IMFFormData is left as the stub it already was, just restored to
compiling against the new IMFHeader signature - fully wiring it up needs
IMFMultipart/IMFText migrated to StreamReader too, out of scope here.

Verified with real runtime tests (not just compilation) covering data
split mid-line, mid-CRLF, mid-header-fold, and mid-boundary-marker across
separate feed() calls, plus StreamReader::compact(). Along the way fixed
a header-value bug (space after ':' wasn't skipped) and a double
cursor-offset subtraction bug in two places caused by forgetting that
ZString::getLength() is already cursor-relative, not the raw buffer size.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 14:25:58 -07:00

47 lines
1.1 KiB
C++

#ifndef __IMFBoundary_h__
# define __IMFBoundary_h__
#include "Parser.h"
namespace coreutils {
///
/// IMFBoundary detects a MIME multipart boundary line in the shared
/// StreamReader - either an ordinary boundary ("\r\n--" + boundary +
/// "\r\n", meaning another part follows) or the closing boundary
/// ("\r\n--" + boundary + "--", meaning this was the last part).
/// Resumable: if the boundary text has been seen but there isn't yet
/// enough buffered data to tell an ordinary boundary from the closing
/// one, parse() reports INCOMPLETE without committing the cursor past
/// the ambiguous point.
///
class IMFBoundary : public Parser {
public:
IMFBoundary(StreamReader &reader, ZString boundary);
///
/// Valid once doParse() has returned Status::COMPLETE - true if this
/// was the closing boundary (no further parts follow).
///
bool isLast();
protected:
Status parse() override;
private:
enum State { PREFIX, TAIL } state = PREFIX;
ZString boundary;
bool last = false;
};
}
#endif