Dieser Parser ist aus einem geplanten Projekt, das ich verworfen habe. Ich hoffe jemand kann ihn noch gebrauchen.
* are permitted in any medium without royalty. This file is offered
* as-is, without any warranty.
*/
#ifndef MPFD_H
#define MPFD_H
#include <functional>
#include <exception>
#include <string>
namespace mpfd
{
class ParserException: public std::runtime_error {
public:
ParserException():runtime_error("Something went wrong during parsing"){}
ParserException(std::string msg):runtime_error(msg.c_str()){}
};
class HeaderData
{
public:
std::string name;
std::string filename;
std::string mimetype;
};
class Parser
{
private:
size_t pos;
std::string content;
std::string boundary;
std::function<void (mpfd::HeaderData, std::string)> gotpart;
protected:
bool read_boundary() {
static size_t boundlen = boundary.length();
int ret = content.compare (pos, boundlen, boundary);
if (ret == 0) {
pos += boundlen;
return true;
}
return false;
}
bool continue_reading() {
if (content.compare(pos, 2, "
") == 0) {
pos += 2;
return true;
}
if (content.compare(pos, 2, "--") == 0)
return false;
throw ParserException();
}
void read_header(std::string &name, std::string &filename, std::string &mimetype) {
while (content[pos] != ';') {
if (content[pos] == '\r' || content[pos] == '
') throw ParserException();
pos++;
}
static const std::string filenamestr = "filename=";
static const std::string namestr = "name=";
while (content.compare(pos, 2, "
") != 0) {
/* Skip if position when the current character occurs to be ';' or ' ' */
if (content[pos] == ';' || content[pos] == ' ') {
pos += 1;
} else if (content.compare(pos, filenamestr.length(), filenamestr) == 0) {
pos += filenamestr.length();
if (content[pos] == '"') {
pos += 1;
while (content[pos] != '"') {
if(content.compare(pos, 2, "
") == 0) {
throw ParserException();
}
filename += content[pos];
pos += 1;
}
pos += 1;
}
} else if (content.compare(pos, namestr.length(), namestr) == 0) {
pos += namestr.length();
if (content[pos] == '"') {
pos += 1;
while (content[pos] != '"') {
if(content.compare(pos, 2, "
") == 0) {
throw ParserException();
}
name += content[pos];
pos += 1;
}
pos += 1;
}
} else {
throw ParserException();
break;
}
}
pos += 2;
static const std::string contenttypestr = "Content-Type: ";
if (content.compare(pos, contenttypestr.length(), contenttypestr) == 0) {
pos += contenttypestr.length();
while (content[pos] != '
') {
if (content[pos] != '\r') {
mimetype += content[pos];
}
pos += 1;
}
pos += 1;
}
/* Checking for last newline */
int i;
for (i = 0; i < 2; i++) {
if (content.compare(pos, 2, "
") == 0) {
pos += 2;
}
}
}
void read_part_data(std::string &data) {
while (!read_boundary()) {
data += content[pos];
pos += 1;
}
if (data.back() == '
') {
data.erase(data.end()-1, data.end());
if (data.back() == '\r') {
data.erase(data.end()-1, data.end());
}
}
}
public:
Parser(std::function<void (mpfd::HeaderData, std::string)> gotpart) {
this->gotpart = gotpart;
}
~Parser() {}
void parse(std::string boundary, std::string content) {
pos = 0;
this->boundary = boundary;
this->content = content;
read_boundary();
while (continue_reading()) {
HeaderData header;
std::string data;
read_header(header.name, header.filename, header.mimetype);
read_part_data(data);
this->gotpart(header, data);
}
}
};
}
#endif // MPFD_H
Hier ist ein Beispiel, wie man den Parser benutzt:
#include "mpfd.h"
using namespace std;
int main()
{
string str = "--AaB03x
"
"Content-Disposition: form-data; name=\"submit-name\"
"
"Larry
"
"--AaB03x
"
"Content-Disposition: form-data; name=\"files\"; filename=\"file1.txt\"
"
"Content-Type: text/plain
"
"... contents of file1.txt ...
"
"--AaB03x--";
mpfd::Parser post_parser([](mpfd::HeaderData header, std::string content){
std::cout << "_" << header.name << "_" << header.filename << "_" << header.mimetype << std::endl;
std::cout << "_" << content << std::endl;
});
post_parser.parse("--AaB03x", str);
return 0;
}