#include "IMFHeader.h" #include "Exception.h" namespace coreutils { IMFHeader::IMFHeader(StreamReader &reader) : Parser(reader) {} Parser::Status IMFHeader::parse() { MString &buffer = reader.getBuffer(); switch (state) { case NAME: { if (buffer.eod()) return Status::INCOMPLETE; if (buffer.getChar() == '\r') { // ZString::getLength() is already cursor-relative. if (buffer.getLength() < 2) return Status::INCOMPLETE; if (!buffer.ifNext(ZString("\r\n"))) throw coreutils::Exception("IMFHeader: expected CRLF at end of header block."); return Status::COMPLETE; } name << buffer.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-0123456789"); if (buffer.eod()) return Status::INCOMPLETE; if (!buffer.ifNext(ZString(":"))) throw coreutils::Exception("IMFHeader: expected ':' in header name."); state = SKIP_SPACE; return Status::DATA_AVAIL; } case SKIP_SPACE: while (!buffer.eod() && buffer.getChar() == ' ') buffer.nextChar(); if (buffer.eod()) return Status::INCOMPLETE; state = FIELD; return Status::DATA_AVAIL; case FIELD: field << buffer.getTokenExclude("\r\n"); // Need 2 bytes buffered to reliably test for "\r\n" - eod() (a // 1-byte check) would wrongly treat a lone trailing \r as // malformed instead of "wait for the \n". Same bug class already // fixed once in IMFBoundary's TAIL state. if (buffer.getLength() < 2) return Status::INCOMPLETE; if (!buffer.ifNext(ZString("\r\n"))) throw coreutils::Exception("IMFHeader: expected CRLF at end of header field."); state = FOLD_CHECK; return Status::DATA_AVAIL; case FOLD_CHECK: if (buffer.eod()) return Status::INCOMPLETE; if (buffer.getChar() == ' ' || buffer.getChar() == '\t') { buffer.nextChar(); field << " "; state = SKIP_SPACE; return Status::DATA_AVAIL; } commitField(); state = NAME; return Status::DATA_AVAIL; } throw coreutils::Exception("IMFHeader: unreachable state."); } void IMFHeader::commitField() { headers[name] = field; name = MString(); field = MString(); } std::map &IMFHeader::getHeaders() { return headers; } }