335 lines
7.5 KiB
C++
335 lines
7.5 KiB
C++
/*
|
|
Copyright 2021 Grégory Soutadé
|
|
|
|
This file is part of uPDFParser.
|
|
|
|
uPDFParser is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
uPDFParser is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with uPDFParser. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef _UPDFTYPES_HPP_
|
|
#define _UPDFTYPES_HPP_
|
|
|
|
#include <map>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
|
|
static std::string strReplace(const std::string& orig, const std::string& pattern, const std::string subst)
|
|
{
|
|
std::string res = orig;
|
|
std::size_t pos;
|
|
|
|
do
|
|
{
|
|
pos = res.find(pattern);
|
|
|
|
if (pos != std::string::npos)
|
|
res.replace(pos, pattern.size(), subst);
|
|
} while (pos != std::string::npos);
|
|
|
|
return res;
|
|
}
|
|
|
|
namespace uPDFParser
|
|
{
|
|
/**
|
|
* @brief Base class for PDF object type
|
|
* From https://resources.infosecinstitute.com/topic/pdf-file-format-basic-structure/
|
|
*/
|
|
class DataType
|
|
{
|
|
public:
|
|
enum TYPE {BOOLEAN, INTEGER, REAL, NAME, STRING, HEXASTRING, REFERENCE, ARRAY, DICTIONARY, STREAM, NULLOBJECT};
|
|
|
|
DataType(TYPE _type):
|
|
_type(_type)
|
|
{}
|
|
|
|
virtual ~DataType() {}
|
|
|
|
/**
|
|
* @brief Get current data type
|
|
*/
|
|
TYPE type() { return _type; }
|
|
|
|
/**
|
|
* @brief String representation for serialization
|
|
*/
|
|
virtual std::string str() = 0;
|
|
|
|
/**
|
|
* @brief Clone current object
|
|
*/
|
|
virtual DataType* clone() = 0;
|
|
|
|
protected:
|
|
TYPE _type;
|
|
};
|
|
|
|
class Boolean : public DataType
|
|
{
|
|
public:
|
|
Boolean(bool value):
|
|
DataType(DataType::TYPE::BOOLEAN), _value(value)
|
|
{}
|
|
|
|
virtual DataType* clone() {return new Boolean(_value);}
|
|
bool value() {return _value;}
|
|
virtual std::string str() { return (_value)?" true":" false";}
|
|
|
|
private:
|
|
bool _value;
|
|
};
|
|
|
|
class Integer : public DataType
|
|
{
|
|
public:
|
|
Integer(int value, bool _signed=false):
|
|
DataType(DataType::TYPE::INTEGER), _value(value), _signed(_signed)
|
|
{}
|
|
|
|
virtual DataType* clone() {return new Integer(_value, _signed);}
|
|
int value() {return _value;}
|
|
virtual std::string str();
|
|
|
|
private:
|
|
int _value;
|
|
bool _signed;
|
|
};
|
|
|
|
class Real : public DataType
|
|
{
|
|
public:
|
|
Real(float value, bool _signed=false):
|
|
DataType(DataType::TYPE::REAL), _value(value), _signed(_signed)
|
|
{}
|
|
|
|
virtual DataType* clone() {return new Real(_value, _signed);}
|
|
float value() {return _value;}
|
|
virtual std::string str();
|
|
|
|
private:
|
|
float _value;
|
|
bool _signed;
|
|
};
|
|
|
|
class Name : public DataType
|
|
{
|
|
public:
|
|
Name(const std::string&);
|
|
|
|
virtual DataType* clone() {return new Name(_value);}
|
|
std::string value() {
|
|
const char* name = _value.c_str();
|
|
return std::string(&name[1]);
|
|
}
|
|
virtual std::string str() { return _value;}
|
|
|
|
private:
|
|
std::string _value;
|
|
};
|
|
|
|
class String : public DataType
|
|
{
|
|
public:
|
|
String(const std::string&);
|
|
|
|
virtual DataType* clone() {return new String(_value);}
|
|
std::string value() {return _value;}
|
|
|
|
// Escape '(' and ')' characters
|
|
virtual std::string str() {
|
|
char prev = '\0';
|
|
std::string res("(");
|
|
|
|
for(unsigned int i=0; i<_value.size(); i++)
|
|
{
|
|
if ((_value[i] == '(' || _value[i] == ')') &&
|
|
prev != '\\')
|
|
res += '\\';
|
|
res += _value[i];
|
|
prev = _value[i];
|
|
}
|
|
|
|
res += ")";
|
|
return res;
|
|
}
|
|
|
|
// Remove escape character '\'
|
|
virtual std::string unescapedValue() {
|
|
// Unescape '\n', \r', '\', '(' and ')'
|
|
std::string res = strReplace(_value, "\\\\", "\\");
|
|
res = strReplace(res, "\\(", "(");
|
|
res = strReplace(res, "\\)", ")");
|
|
res = strReplace(res, "\\n", "\n");
|
|
res = strReplace(res, "\\r", "\r");
|
|
|
|
return res;
|
|
}
|
|
|
|
private:
|
|
std::string _value;
|
|
};
|
|
|
|
class HexaString : public DataType
|
|
{
|
|
public:
|
|
HexaString(const std::string&);
|
|
|
|
virtual DataType* clone() {return new HexaString(_value);}
|
|
std::string value() {return _value;}
|
|
virtual std::string str() { return std::string("<") + _value + std::string(">");}
|
|
|
|
private:
|
|
std::string _value;
|
|
};
|
|
|
|
class Reference : public DataType
|
|
{
|
|
public:
|
|
Reference(int objectId, int generationNumber):
|
|
DataType(DataType::TYPE::REFERENCE), objectId(objectId), generationNumber(generationNumber)
|
|
{}
|
|
|
|
virtual DataType* clone() {return new Reference(objectId, generationNumber);}
|
|
int value() {return objectId;}
|
|
virtual std::string str() {
|
|
std::stringstream res;
|
|
res << " " << objectId << " " << generationNumber << " R";
|
|
return res.str();
|
|
}
|
|
|
|
private:
|
|
int objectId, generationNumber;
|
|
};
|
|
|
|
class Array : public DataType
|
|
{
|
|
public:
|
|
Array():
|
|
DataType(DataType::TYPE::ARRAY)
|
|
{}
|
|
|
|
void addData(DataType* data) {_value.push_back(data);}
|
|
|
|
virtual DataType* clone() {
|
|
Array* res = new Array();
|
|
std::vector<DataType*>::iterator it;
|
|
for(it=_value.begin(); it!=_value.end(); it++)
|
|
res->addData((*it)->clone());
|
|
return res;
|
|
}
|
|
std::vector<DataType*>& value() {return _value;}
|
|
virtual std::string str();
|
|
|
|
private:
|
|
std::vector<DataType*> _value;
|
|
};
|
|
|
|
class Dictionary : public DataType
|
|
{
|
|
public:
|
|
Dictionary():
|
|
DataType(DataType::TYPE::DICTIONARY)
|
|
{}
|
|
|
|
void addData(const std::string&, DataType*);
|
|
|
|
virtual DataType* clone() {
|
|
Dictionary* res = new Dictionary();
|
|
std::map<std::string, DataType*>::iterator it;
|
|
for(it=_value.begin(); it!=_value.end(); it++)
|
|
{
|
|
res->addData(it->first, it->second->clone());
|
|
}
|
|
return res;
|
|
}
|
|
std::map<std::string, DataType*>& value() {return _value;}
|
|
virtual std::string str();
|
|
|
|
bool empty() { return _value.empty(); }
|
|
|
|
bool hasKey(const std::string& key) { return _value.count(key)?true:false;}
|
|
|
|
void deleteKey(const std::string& key) {
|
|
if (!hasKey(key)) return;
|
|
delete _value[key];
|
|
_value.erase(key);
|
|
}
|
|
|
|
void replace(const std::string& key, DataType* data, bool freeData=true)
|
|
{
|
|
if (hasKey(key))
|
|
{
|
|
if (freeData)
|
|
deleteKey(key);
|
|
else
|
|
_value.erase(key);
|
|
|
|
addData(key, data);
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::map<std::string, DataType*> _value;
|
|
};
|
|
|
|
class Stream : public DataType
|
|
{
|
|
public:
|
|
Stream(Dictionary& dict, int startOffset, int endOffset, unsigned char* data=0, unsigned int dataLength=0,
|
|
bool freeData=false, int fd=0):
|
|
DataType(DataType::TYPE::STREAM), dict(dict), fd(fd),
|
|
startOffset(startOffset), endOffset(endOffset),
|
|
_data(data), _dataLength(dataLength), freeData(false)
|
|
{}
|
|
|
|
~Stream() {
|
|
if (_data && freeData) delete[] _data;
|
|
}
|
|
|
|
virtual DataType* clone() {return new Stream(dict, startOffset, endOffset,
|
|
_data, _dataLength, false, fd);}
|
|
virtual std::string str();
|
|
unsigned char* data();
|
|
unsigned int dataLength() {return _dataLength;}
|
|
void setData(unsigned char* data, unsigned int dataLength, bool freeData=false);
|
|
|
|
private:
|
|
Dictionary& dict;
|
|
int fd;
|
|
int startOffset, endOffset;
|
|
unsigned char* _data;
|
|
unsigned int _dataLength;
|
|
bool freeData;
|
|
};
|
|
|
|
class Null : public DataType
|
|
{
|
|
public:
|
|
Null():
|
|
DataType(DataType::TYPE::NULLOBJECT)
|
|
{}
|
|
|
|
virtual DataType* clone() {return new Null();}
|
|
bool value() {return 0;}
|
|
virtual std::string str() { return "null";}
|
|
|
|
private:
|
|
};
|
|
}
|
|
|
|
#endif
|