Add PDF writer.
This commit is contained in:
parent
c05b7b6315
commit
9c116b1efd
72 changed files with 1819 additions and 114 deletions
|
@ -26,14 +26,5 @@ target_include_directories(sample_console PUBLIC
|
||||||
target_link_libraries(sample_console PUBLIC console core network
|
target_link_libraries(sample_console PUBLIC console core network
|
||||||
database geometry audio web)
|
database geometry audio web)
|
||||||
|
|
||||||
# Xml practice
|
|
||||||
add_executable(xml_practice xml-practice.cpp)
|
|
||||||
target_include_directories(xml_practice PUBLIC
|
|
||||||
"${PROJECT_SOURCE_DIR}/src/core"
|
|
||||||
"${PROJECT_SOURCE_DIR}/src/web/xml"
|
|
||||||
)
|
|
||||||
target_link_libraries(xml_practice PUBLIC core web)
|
|
||||||
|
|
||||||
set_property(TARGET sample_console PROPERTY FOLDER apps)
|
set_property(TARGET sample_console PROPERTY FOLDER apps)
|
||||||
set_property(TARGET sample_gui PROPERTY FOLDER apps)
|
set_property(TARGET sample_gui PROPERTY FOLDER apps)
|
||||||
set_property(TARGET xml_practice PROPERTY FOLDER apps)
|
|
|
@ -1,38 +0,0 @@
|
||||||
#include <filesystem>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include "CommandLineArgs.h"
|
|
||||||
#include "XmlParser.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
CommandLineArgs command_line_args;
|
|
||||||
command_line_args.Process(argc, argv);
|
|
||||||
|
|
||||||
if(command_line_args.GetNumberOfArgs() < 2)
|
|
||||||
{
|
|
||||||
std::cerr << "Expected a filepath argument" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
XmlParser parser;
|
|
||||||
const auto filepath = command_line_args.GetArg(1);
|
|
||||||
|
|
||||||
if(!std::filesystem::exists(filepath))
|
|
||||||
{
|
|
||||||
std::cerr << "Couldn't find file: " << filepath << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ifstream xml_file;
|
|
||||||
xml_file.open(filepath, std::ifstream::in);
|
|
||||||
while(xml_file.good())
|
|
||||||
{
|
|
||||||
std::string line;
|
|
||||||
std::getline(xml_file, line);
|
|
||||||
parser.ProcessLine(line);
|
|
||||||
}
|
|
||||||
xml_file.close();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -3,9 +3,12 @@ add_subdirectory(database)
|
||||||
add_subdirectory(network)
|
add_subdirectory(network)
|
||||||
add_subdirectory(geometry)
|
add_subdirectory(geometry)
|
||||||
add_subdirectory(audio)
|
add_subdirectory(audio)
|
||||||
|
add_subdirectory(image)
|
||||||
add_subdirectory(console)
|
add_subdirectory(console)
|
||||||
add_subdirectory(client)
|
add_subdirectory(client)
|
||||||
add_subdirectory(graphics)
|
add_subdirectory(graphics)
|
||||||
|
add_subdirectory(publishing)
|
||||||
|
add_subdirectory(video)
|
||||||
add_subdirectory(windows)
|
add_subdirectory(windows)
|
||||||
add_subdirectory(web)
|
add_subdirectory(web)
|
||||||
add_subdirectory(ui_elements)
|
add_subdirectory(ui_elements)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
list(APPEND core_HEADERS
|
list(APPEND core_HEADERS
|
||||||
AbstractApp.h
|
AbstractApp.h
|
||||||
|
Dictionary.h
|
||||||
Event.h
|
Event.h
|
||||||
Color.h
|
Color.h
|
||||||
CommandLineArgs.h
|
CommandLineArgs.h
|
||||||
|
@ -12,6 +13,7 @@ list(APPEND core_HEADERS
|
||||||
|
|
||||||
list(APPEND core_LIB_INCLUDES
|
list(APPEND core_LIB_INCLUDES
|
||||||
Event.cpp
|
Event.cpp
|
||||||
|
Dictionary.cpp
|
||||||
Color.cpp
|
Color.cpp
|
||||||
CommandLineArgs.cpp
|
CommandLineArgs.cpp
|
||||||
loggers/FileLogger.cpp
|
loggers/FileLogger.cpp
|
||||||
|
|
56
src/core/Dictionary.cpp
Normal file
56
src/core/Dictionary.cpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#include "Dictionary.h"
|
||||||
|
|
||||||
|
bool Dictionary::HasKey(const std::string& key) const
|
||||||
|
{
|
||||||
|
return HasStringKey(key) || HasDictKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dictionary::HasStringKey(const std::string& key) const
|
||||||
|
{
|
||||||
|
return mStringData.count(key) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dictionary::HasDictKey(const std::string& key) const
|
||||||
|
{
|
||||||
|
return mDictData.count(key) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> Dictionary::GetStringKeys() const
|
||||||
|
{
|
||||||
|
std::vector<std::string> keys;
|
||||||
|
for (const auto& item : mStringData)
|
||||||
|
{
|
||||||
|
keys.push_back(item.first);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> Dictionary::GetDictKeys() const
|
||||||
|
{
|
||||||
|
std::vector<std::string> keys;
|
||||||
|
for (const auto& item : mDictData)
|
||||||
|
{
|
||||||
|
keys.push_back(item.first);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary* Dictionary::GetDict(const std::string& key) const
|
||||||
|
{
|
||||||
|
return mDictData.at(key).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Dictionary::GetItem(const std::string& key) const
|
||||||
|
{
|
||||||
|
return mStringData.at(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dictionary::AddStringItem(const std::string& key, const std::string& item)
|
||||||
|
{
|
||||||
|
mStringData[key] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dictionary::AddDictItem(const std::string& key, std::unique_ptr<Dictionary> dict)
|
||||||
|
{
|
||||||
|
mDictData[key] = std::move(dict);
|
||||||
|
}
|
35
src/core/Dictionary.h
Normal file
35
src/core/Dictionary.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class Dictionary
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Dictionary() = default;
|
||||||
|
virtual ~Dictionary() = default;
|
||||||
|
|
||||||
|
bool HasKey(const std::string& key) const;
|
||||||
|
|
||||||
|
bool HasStringKey(const std::string& key) const;
|
||||||
|
|
||||||
|
bool HasDictKey(const std::string& key) const;
|
||||||
|
|
||||||
|
Dictionary* GetDict(const std::string& key) const;
|
||||||
|
|
||||||
|
std::vector<std::string> GetDictKeys() const;
|
||||||
|
|
||||||
|
std::vector<std::string> GetStringKeys() const;
|
||||||
|
|
||||||
|
std::string GetItem(const std::string& key) const;
|
||||||
|
|
||||||
|
void AddStringItem(const std::string& key, const std::string& item);
|
||||||
|
|
||||||
|
void AddDictItem(const std::string& key, std::unique_ptr<Dictionary> dict);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
std::map<std::string, std::string> mStringData;
|
||||||
|
std::map<std::string, std::unique_ptr<Dictionary> > mDictData;
|
||||||
|
};
|
|
@ -1,6 +1,8 @@
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Windows.h"
|
#include "Windows.h"
|
||||||
|
@ -45,3 +47,10 @@ std::string StringUtils::convert(const std::wstring& input)
|
||||||
throw std::logic_error("Not implemented");
|
throw std::logic_error("Not implemented");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string StringUtils::ToPaddedString(unsigned numBytes, unsigned entry)
|
||||||
|
{
|
||||||
|
std::stringstream sstr;
|
||||||
|
sstr << std::setfill('0') << std::setw(numBytes) << entry;
|
||||||
|
return sstr.str();
|
||||||
|
}
|
||||||
|
|
|
@ -18,4 +18,5 @@ public:
|
||||||
static bool IsSpace(char c);
|
static bool IsSpace(char c);
|
||||||
static std::string ToLower(const std::string& s);
|
static std::string ToLower(const std::string& s);
|
||||||
static std::string convert(const std::wstring& input);
|
static std::string convert(const std::wstring& input);
|
||||||
|
static std::string ToPaddedString(unsigned numBytes, unsigned entry);
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,6 +27,11 @@ void DatabaseManager::CreateDatabase(const std::string& path)
|
||||||
mDatabaseInterface->Open(mDatabase);
|
mDatabaseInterface->Open(mDatabase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DatabaseManager::Run(const std::string& statement)
|
||||||
|
{
|
||||||
|
mDatabaseInterface->Run(statement);
|
||||||
|
}
|
||||||
|
|
||||||
void DatabaseManager::OnShutDown()
|
void DatabaseManager::OnShutDown()
|
||||||
{
|
{
|
||||||
if(mDatabaseInterface)
|
if(mDatabaseInterface)
|
||||||
|
|
|
@ -7,10 +7,6 @@
|
||||||
|
|
||||||
class DatabaseManager
|
class DatabaseManager
|
||||||
{
|
{
|
||||||
|
|
||||||
DatabasePtr mDatabase;
|
|
||||||
SqliteInterfacePtr mDatabaseInterface;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DatabaseManager();
|
DatabaseManager();
|
||||||
|
@ -21,7 +17,13 @@ public:
|
||||||
|
|
||||||
void CreateDatabase(const std::string& path);
|
void CreateDatabase(const std::string& path);
|
||||||
|
|
||||||
|
void Run(const std::string& statement);
|
||||||
|
|
||||||
void OnShutDown();
|
void OnShutDown();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DatabasePtr mDatabase;
|
||||||
|
SqliteInterfacePtr mDatabaseInterface;
|
||||||
};
|
};
|
||||||
|
|
||||||
using DatabaseManagerPtr = std::unique_ptr<DatabaseManager>;
|
using DatabaseManagerPtr = std::unique_ptr<DatabaseManager>;
|
||||||
|
|
21
src/image/CMakeLists.txt
Normal file
21
src/image/CMakeLists.txt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
list(APPEND image_HEADERS
|
||||||
|
Image.h
|
||||||
|
PngWriter.h
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND image_LIB_INCLUDES
|
||||||
|
Image.cpp
|
||||||
|
PngWriter.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(image SHARED ${image_LIB_INCLUDES} ${image_HEADERS})
|
||||||
|
|
||||||
|
target_include_directories(image PUBLIC
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
)
|
||||||
|
set_target_properties( image PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||||
|
|
||||||
|
find_package(PNG REQUIRED)
|
||||||
|
target_link_libraries( image PUBLIC PNG::PNG)
|
||||||
|
|
||||||
|
set_property(TARGET image PROPERTY FOLDER src)
|
69
src/image/Image.cpp
Normal file
69
src/image/Image.cpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#include "Image.h"
|
||||||
|
|
||||||
|
Image::Image(unsigned width, unsigned height)
|
||||||
|
: mWidth(width),
|
||||||
|
mHeight(height)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Image> Image::Create(unsigned width, unsigned height)
|
||||||
|
{
|
||||||
|
return std::make_unique<Image>(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Image::GetBytesPerRow() const
|
||||||
|
{
|
||||||
|
const auto bitsPerEntry = mBitDepth <= 8 ? 1 : 2;
|
||||||
|
return mWidth * mNumChannels *bitsPerEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Image::GetWidth() const
|
||||||
|
{
|
||||||
|
return mWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Image::GetHeight() const
|
||||||
|
{
|
||||||
|
return mHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Image::GetBitDepth() const
|
||||||
|
{
|
||||||
|
return mBitDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char Image::GetByte(unsigned idx, unsigned jdx) const
|
||||||
|
{
|
||||||
|
return mData[jdx*GetBytesPerRow() + idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Image::GetNumChannels() const
|
||||||
|
{
|
||||||
|
return mNumChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::SetData(const std::vector<unsigned char>& data)
|
||||||
|
{
|
||||||
|
mData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::SetWidth(unsigned width)
|
||||||
|
{
|
||||||
|
mWidth = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::SetHeight(unsigned height)
|
||||||
|
{
|
||||||
|
mHeight = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::SetBitDepth(unsigned bitDepth)
|
||||||
|
{
|
||||||
|
mBitDepth = bitDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::SetNumChannels(unsigned numChannels)
|
||||||
|
{
|
||||||
|
mNumChannels = numChannels;
|
||||||
|
}
|
35
src/image/Image.h
Normal file
35
src/image/Image.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
class Image
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Image(unsigned width, unsigned height);
|
||||||
|
static std::unique_ptr<Image> Create(unsigned width, unsigned height);
|
||||||
|
|
||||||
|
unsigned GetBytesPerRow() const;
|
||||||
|
unsigned GetWidth() const;
|
||||||
|
unsigned GetHeight() const;
|
||||||
|
unsigned GetBitDepth() const;
|
||||||
|
unsigned GetNumChannels() const;
|
||||||
|
unsigned char GetByte(unsigned idx, unsigned jdx) const;
|
||||||
|
|
||||||
|
void SetData(const std::vector<unsigned char>& data);
|
||||||
|
void SetWidth(unsigned width);
|
||||||
|
void SetHeight(unsigned height);
|
||||||
|
void SetBitDepth(unsigned bitDepth);
|
||||||
|
void SetNumChannels(unsigned numChannels);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned mWidth{1};
|
||||||
|
unsigned mHeight{1};
|
||||||
|
unsigned mBitDepth{8};
|
||||||
|
unsigned mNumChannels{1};
|
||||||
|
std::vector<unsigned char> mData;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ImagePtr = std::unique_ptr<Image>;
|
74
src/image/PngWriter.cpp
Normal file
74
src/image/PngWriter.cpp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#include "PngWriter.h"
|
||||||
|
|
||||||
|
#include "Image.h"
|
||||||
|
|
||||||
|
#include <png.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
std::unique_ptr<PngWriter> PngWriter::Create()
|
||||||
|
{
|
||||||
|
return std::make_unique<PngWriter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PngWriter::SetPath(const std::string& path)
|
||||||
|
{
|
||||||
|
mPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PngWriter::Write(const std::unique_ptr<Image>& image) const
|
||||||
|
{
|
||||||
|
auto fp = fopen(mPath.c_str(), "wb");
|
||||||
|
|
||||||
|
auto png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||||
|
auto info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png_ptr)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
png_init_io(png_ptr, fp);
|
||||||
|
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png_ptr)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto color_type = PNG_COLOR_TYPE_RGB;
|
||||||
|
png_set_IHDR(png_ptr, info_ptr, image->GetWidth(), image->GetHeight(),
|
||||||
|
image->GetBitDepth(), color_type, PNG_INTERLACE_NONE,
|
||||||
|
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||||
|
|
||||||
|
png_write_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png_ptr)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * image->GetHeight());
|
||||||
|
auto row_size = image->GetBytesPerRow();
|
||||||
|
for(unsigned jdx=0;jdx<image->GetHeight();jdx++)
|
||||||
|
{
|
||||||
|
row_pointers[jdx]=(png_byte*)malloc(sizeof(png_byte)*row_size);
|
||||||
|
for(unsigned idx=0;idx<row_size;idx++)
|
||||||
|
{
|
||||||
|
row_pointers[jdx][idx] = image->GetByte(idx, jdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
png_write_image(png_ptr, row_pointers);
|
||||||
|
if (setjmp(png_jmpbuf(png_ptr)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_write_end(png_ptr, nullptr);
|
||||||
|
|
||||||
|
for (unsigned y=0; y<image->GetHeight(); y++)
|
||||||
|
{
|
||||||
|
free(row_pointers[y]);
|
||||||
|
}
|
||||||
|
free(row_pointers);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return;
|
||||||
|
}
|
22
src/image/PngWriter.h
Normal file
22
src/image/PngWriter.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Image;
|
||||||
|
|
||||||
|
class PngWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::unique_ptr<PngWriter> Create();
|
||||||
|
|
||||||
|
void SetPath(const std::string& path);
|
||||||
|
|
||||||
|
void Write(const std::unique_ptr<Image>& image) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::string mPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
using PngWriterPtr = std::unique_ptr<PngWriter>;
|
|
@ -8,9 +8,6 @@
|
||||||
|
|
||||||
class NetworkManager
|
class NetworkManager
|
||||||
{
|
{
|
||||||
std::vector<SocketPtr> mActiveSockets;
|
|
||||||
ISocketInterfaceUPtr mSocketInterface;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NetworkManager();
|
NetworkManager();
|
||||||
|
@ -24,6 +21,10 @@ public:
|
||||||
void RunHttpServer();
|
void RunHttpServer();
|
||||||
|
|
||||||
void ShutDown();
|
void ShutDown();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<SocketPtr> mActiveSockets;
|
||||||
|
ISocketInterfaceUPtr mSocketInterface;
|
||||||
};
|
};
|
||||||
|
|
||||||
using NetworkManagerUPtr = std::unique_ptr<NetworkManager>;
|
using NetworkManagerUPtr = std::unique_ptr<NetworkManager>;
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
SocketHandle mHandle;
|
SocketHandle mHandle;
|
||||||
unsigned mPort;
|
unsigned mPort{0};
|
||||||
std::string mMessage;
|
std::string mMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
36
src/publishing/CMakeLists.txt
Normal file
36
src/publishing/CMakeLists.txt
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
list(APPEND publishing_HEADERS
|
||||||
|
pdf/PdfDocument.h
|
||||||
|
pdf/PdfDocumentCatalog.h
|
||||||
|
pdf/PdfDictionary.h
|
||||||
|
pdf/PdfObject.h
|
||||||
|
pdf/PdfOutline.h
|
||||||
|
pdf/PdfPageTree.h
|
||||||
|
pdf/PdfPage.h
|
||||||
|
pdf/PdfStream.h
|
||||||
|
pdf/PdfXRefTable.h
|
||||||
|
pdf/PdfWriter.h
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND publishing_LIB_INCLUDES
|
||||||
|
pdf/PdfDocument.cpp
|
||||||
|
pdf/PdfDocumentCatalog.cpp
|
||||||
|
pdf/PdfDictionary.cpp
|
||||||
|
pdf/PdfObject.cpp
|
||||||
|
pdf/PdfOutline.cpp
|
||||||
|
pdf/PdfPageTree.cpp
|
||||||
|
pdf/PdfPage.cpp
|
||||||
|
pdf/PdfStream.cpp
|
||||||
|
pdf/PdfXRefTable.cpp
|
||||||
|
pdf/PdfWriter.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(publishing SHARED ${publishing_LIB_INCLUDES} ${publishing_INCLUDES} ${publishing_HEADERS})
|
||||||
|
|
||||||
|
target_include_directories(publishing PUBLIC
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/pdf"
|
||||||
|
)
|
||||||
|
set_target_properties( publishing PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||||
|
target_link_libraries( publishing PUBLIC core)
|
||||||
|
|
||||||
|
set_property(TARGET publishing PROPERTY FOLDER src)
|
45
src/publishing/pdf/PdfDictionary.cpp
Normal file
45
src/publishing/pdf/PdfDictionary.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include "PdfDictionary.h"
|
||||||
|
|
||||||
|
std::string PdfDictionary::ToString() const
|
||||||
|
{
|
||||||
|
const auto keys = GetStringKeys();
|
||||||
|
if (keys.empty())
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string content = " <<";
|
||||||
|
bool first = true;
|
||||||
|
auto ending = keys.size() == 1 ? "" : "\n";
|
||||||
|
for (const auto& key : keys)
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
content += " /" + key + " " + GetItem(key) + ending;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content += " /" + key + " " + GetItem(key) + ending;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto dictKeys = GetDictKeys();
|
||||||
|
ending = dictKeys.size() == 1 ? "" : "\n";
|
||||||
|
for (const auto& key : GetDictKeys())
|
||||||
|
{
|
||||||
|
auto pdfDict = dynamic_cast<PdfDictionary*>(GetDict(key));
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
content += " /" + key + " " + pdfDict->ToString() + ending;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content += " /" + key + " " + pdfDict->ToString() + ending;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content += " >>\n";
|
||||||
|
return content;
|
||||||
|
}
|
10
src/publishing/pdf/PdfDictionary.h
Normal file
10
src/publishing/pdf/PdfDictionary.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Dictionary.h"
|
||||||
|
|
||||||
|
class PdfDictionary : public Dictionary
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
std::string ToString() const;
|
||||||
|
};
|
73
src/publishing/pdf/PdfDocument.cpp
Normal file
73
src/publishing/pdf/PdfDocument.cpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#include "PdfDocument.h"
|
||||||
|
|
||||||
|
#include "PdfObject.h"
|
||||||
|
#include "PdfDocumentCatalog.h"
|
||||||
|
#include "PdfPageTree.h"
|
||||||
|
#include "PdfPage.h"
|
||||||
|
#include "PdfOutline.h"
|
||||||
|
#include "PdfXRefTable.h"
|
||||||
|
|
||||||
|
PdfDocument::PdfDocument()
|
||||||
|
{
|
||||||
|
mXRefTable = std::make_unique<PdfXRefTable>();
|
||||||
|
mCatalog = std::make_unique<PdfDocumentCatalog>();
|
||||||
|
}
|
||||||
|
|
||||||
|
PdfDocument::~PdfDocument()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfDocument::ToString()
|
||||||
|
{
|
||||||
|
IndexObjects();
|
||||||
|
auto content = GetHeaderString();
|
||||||
|
content += GetBodyString();
|
||||||
|
|
||||||
|
content += GetXRefString();
|
||||||
|
|
||||||
|
content += GetTrailerString();
|
||||||
|
|
||||||
|
content += "%%EOF\n";
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfDocument::GetHeaderString()
|
||||||
|
{
|
||||||
|
auto content = "%PDF-" + mVersion + "\n";
|
||||||
|
mXRefOffset = content.size();
|
||||||
|
mXRefTable->AddRecord(content.size(), 65535, true);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfDocument::GetBodyString()
|
||||||
|
{
|
||||||
|
const auto content = mCatalog->ToString(mXRefTable.get());
|
||||||
|
mXRefOffset += content.size();
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfDocument::GetXRefString()
|
||||||
|
{
|
||||||
|
return mXRefTable->ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfDocument::GetTrailerString()
|
||||||
|
{
|
||||||
|
const auto numObjects = mXRefTable->GetNumEntries();
|
||||||
|
mTrailer.AddStringItem("Size", std::to_string(numObjects));
|
||||||
|
mTrailer.AddStringItem("Root", mCatalog->GetRefString());
|
||||||
|
|
||||||
|
std::string content = "trailer\n";
|
||||||
|
content += mTrailer.ToString();
|
||||||
|
|
||||||
|
content += "startxref\n";
|
||||||
|
content += std::to_string(mXRefOffset) + "\n";
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PdfDocument::IndexObjects()
|
||||||
|
{
|
||||||
|
mCatalog->IndexObjects(0);
|
||||||
|
}
|
||||||
|
|
44
src/publishing/pdf/PdfDocument.h
Normal file
44
src/publishing/pdf/PdfDocument.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "PdfDictionary.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class PdfDocumentCatalog;
|
||||||
|
using PdfDocumentCatalogPtr = std::unique_ptr<PdfDocumentCatalog>;
|
||||||
|
|
||||||
|
class PdfXRefTable;
|
||||||
|
using PdfXRefTablePtr = std::unique_ptr<PdfXRefTable>;
|
||||||
|
|
||||||
|
class PdfDocument
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
PdfDocument();
|
||||||
|
~PdfDocument();
|
||||||
|
|
||||||
|
std::string ToString();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string GetHeaderString();
|
||||||
|
|
||||||
|
std::string GetTrailerString();
|
||||||
|
|
||||||
|
std::string GetBodyString();
|
||||||
|
|
||||||
|
std::string GetXRefString();
|
||||||
|
|
||||||
|
void IndexObjects();
|
||||||
|
|
||||||
|
private:
|
||||||
|
PdfDictionary mTrailer;
|
||||||
|
std::string mVersion {"1.7"};
|
||||||
|
PdfXRefTablePtr mXRefTable;
|
||||||
|
unsigned mXRefOffset{0};
|
||||||
|
PdfDocumentCatalogPtr mCatalog;
|
||||||
|
};
|
||||||
|
|
||||||
|
using PdfDocumentPtr = std::unique_ptr<PdfDocument>;
|
44
src/publishing/pdf/PdfDocumentCatalog.cpp
Normal file
44
src/publishing/pdf/PdfDocumentCatalog.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include "PdfDocumentCatalog.h"
|
||||||
|
|
||||||
|
#include "PdfOutline.h"
|
||||||
|
#include "PdfPageTree.h"
|
||||||
|
#include "PdfPage.h"
|
||||||
|
#include "PdfXRefTable.h"
|
||||||
|
|
||||||
|
PdfDocumentCatalog::PdfDocumentCatalog()
|
||||||
|
: PdfObject()
|
||||||
|
{
|
||||||
|
mOutlines = std::make_unique<PdfOutlineCollection>();
|
||||||
|
mPages = std::make_unique<PdfPageTree>();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned PdfDocumentCatalog::IndexObjects(unsigned count)
|
||||||
|
{
|
||||||
|
auto newCount = count + 1;
|
||||||
|
mObjectNumber = newCount;
|
||||||
|
auto objectCount = mOutlines->IndexObjects(mObjectNumber);
|
||||||
|
objectCount = mPages->IndexObjects(objectCount);
|
||||||
|
return objectCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfDocumentCatalog::ToString(PdfXRefTable* xRefTable)
|
||||||
|
{
|
||||||
|
UpdateDictionary();
|
||||||
|
auto content = GetStringPrefix();
|
||||||
|
content += mDictionary.ToString();
|
||||||
|
content += GetStringSuffix();
|
||||||
|
xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);
|
||||||
|
|
||||||
|
content += mOutlines->ToString(xRefTable);
|
||||||
|
|
||||||
|
content += mPages->ToString(xRefTable);
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PdfDocumentCatalog::UpdateDictionary()
|
||||||
|
{
|
||||||
|
mDictionary.AddStringItem("Type", "/Catalog");
|
||||||
|
mDictionary.AddStringItem("Outlines", mOutlines->GetRefString());
|
||||||
|
mDictionary.AddStringItem("Pages", mPages->GetRefString());
|
||||||
|
}
|
23
src/publishing/pdf/PdfDocumentCatalog.h
Normal file
23
src/publishing/pdf/PdfDocumentCatalog.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "PdfObject.h"
|
||||||
|
|
||||||
|
class PdfPageTree;
|
||||||
|
class PdfOutlineCollection;
|
||||||
|
|
||||||
|
class PdfDocumentCatalog : public PdfObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
PdfDocumentCatalog();
|
||||||
|
|
||||||
|
unsigned IndexObjects(unsigned count) override;
|
||||||
|
|
||||||
|
std::string ToString(PdfXRefTable* xRefTable) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void UpdateDictionary() override;
|
||||||
|
|
||||||
|
std::unique_ptr<PdfOutlineCollection> mOutlines;
|
||||||
|
std::unique_ptr<PdfPageTree> mPages;
|
||||||
|
};
|
58
src/publishing/pdf/PdfObject.cpp
Normal file
58
src/publishing/pdf/PdfObject.cpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include "PdfObject.h"
|
||||||
|
|
||||||
|
#include "PdfDictionary.h"
|
||||||
|
#include "PdfXRefTable.h"
|
||||||
|
|
||||||
|
std::string PdfObject::ToString(PdfXRefTable* xRefTable)
|
||||||
|
{
|
||||||
|
UpdateDictionary();
|
||||||
|
|
||||||
|
auto content = GetStringPrefix();
|
||||||
|
content += mDictionary.ToString();
|
||||||
|
content += GetStringSuffix();
|
||||||
|
|
||||||
|
xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PdfObject::UpdateDictionary()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfObject::GetStringSuffix() const
|
||||||
|
{
|
||||||
|
return "endobj\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned PdfObject::IndexObjects(unsigned count)
|
||||||
|
{
|
||||||
|
const auto newCount = count + 1;
|
||||||
|
mObjectNumber = newCount;
|
||||||
|
return newCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PdfObject::SetObjectNumber(unsigned num)
|
||||||
|
{
|
||||||
|
mObjectNumber = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PdfObject::SetGenerationNumber(unsigned num)
|
||||||
|
{
|
||||||
|
mGenerationNumber = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfObject::GetStringPrefix() const
|
||||||
|
{
|
||||||
|
return std::to_string(mObjectNumber) + " " + std::to_string(mGenerationNumber) + " obj\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfObject::GetRefString() const
|
||||||
|
{
|
||||||
|
return std::to_string(mObjectNumber) + " " + std::to_string(mGenerationNumber) + " R";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PdfObject::IsFree() const
|
||||||
|
{
|
||||||
|
return mIsFree;
|
||||||
|
}
|
40
src/publishing/pdf/PdfObject.h
Normal file
40
src/publishing/pdf/PdfObject.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "PdfDictionary.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class PdfXRefTable;
|
||||||
|
|
||||||
|
class PdfObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~PdfObject() = default;
|
||||||
|
|
||||||
|
std::string GetStringPrefix() const;
|
||||||
|
|
||||||
|
std::string GetStringSuffix() const;
|
||||||
|
|
||||||
|
std::string GetRefString() const;
|
||||||
|
|
||||||
|
virtual unsigned IndexObjects(unsigned count);
|
||||||
|
|
||||||
|
bool IsFree() const;
|
||||||
|
|
||||||
|
virtual std::string ToString(PdfXRefTable* xRefTable);
|
||||||
|
|
||||||
|
void SetObjectNumber(unsigned num);
|
||||||
|
|
||||||
|
void SetGenerationNumber(unsigned num);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void UpdateDictionary();
|
||||||
|
|
||||||
|
unsigned mObjectNumber{0};
|
||||||
|
unsigned mGenerationNumber{0};
|
||||||
|
PdfDictionary mDictionary;
|
||||||
|
bool mIsFree {false};
|
||||||
|
};
|
||||||
|
using PdfObjectPtr = std::unique_ptr<PdfObject>;
|
40
src/publishing/pdf/PdfOutline.cpp
Normal file
40
src/publishing/pdf/PdfOutline.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include "PdfOutline.h"
|
||||||
|
|
||||||
|
#include "PdfXRefTable.h"
|
||||||
|
|
||||||
|
std::string PdfOutline::ToString(PdfXRefTable* xRefTable)
|
||||||
|
{
|
||||||
|
mDictionary.AddStringItem("Type", "/Outline");
|
||||||
|
auto content = GetStringPrefix();
|
||||||
|
content += mDictionary.ToString();
|
||||||
|
content += GetStringSuffix();
|
||||||
|
xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned PdfOutlineCollection::IndexObjects(unsigned count)
|
||||||
|
{
|
||||||
|
auto newCount = count + 1;
|
||||||
|
mObjectNumber = newCount;
|
||||||
|
for (const auto& outline : mOutlines)
|
||||||
|
{
|
||||||
|
newCount = outline->IndexObjects(newCount);
|
||||||
|
}
|
||||||
|
return newCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfOutlineCollection::ToString(PdfXRefTable* xRefTable)
|
||||||
|
{
|
||||||
|
UpdateDictionary();
|
||||||
|
std::string content = GetStringPrefix();
|
||||||
|
content += mDictionary.ToString();
|
||||||
|
content += GetStringSuffix();
|
||||||
|
xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PdfOutlineCollection::UpdateDictionary()
|
||||||
|
{
|
||||||
|
mDictionary.AddStringItem("Type", "/Outlines");
|
||||||
|
mDictionary.AddStringItem("Count", std::to_string(mOutlines.size()));
|
||||||
|
}
|
26
src/publishing/pdf/PdfOutline.h
Normal file
26
src/publishing/pdf/PdfOutline.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "PdfObject.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class PdfOutline : public PdfObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string ToString(PdfXRefTable* xRefTable) override;
|
||||||
|
};
|
||||||
|
using PdfOutlinePtr = std::unique_ptr<PdfOutline>;
|
||||||
|
|
||||||
|
class PdfOutlineCollection : public PdfObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
unsigned IndexObjects(unsigned count) override;
|
||||||
|
|
||||||
|
std::string ToString(PdfXRefTable* xRefTable) override;
|
||||||
|
|
||||||
|
void UpdateDictionary();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<PdfOutlinePtr> mOutlines;
|
||||||
|
};
|
0
src/publishing/pdf/PdfPage.cpp
Normal file
0
src/publishing/pdf/PdfPage.cpp
Normal file
121
src/publishing/pdf/PdfPage.h
Normal file
121
src/publishing/pdf/PdfPage.h
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "PdfObject.h"
|
||||||
|
#include "PdfStream.h"
|
||||||
|
#include "PdfXRefTable.h"
|
||||||
|
|
||||||
|
class PdfPageTree;
|
||||||
|
|
||||||
|
class PdfProcSet : public PdfObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string ToString(PdfXRefTable* xRefTable) override
|
||||||
|
{
|
||||||
|
UpdateDictionary();
|
||||||
|
auto content = GetStringPrefix();
|
||||||
|
content += mDictionary.ToString();
|
||||||
|
content += "[/PDF]\n";
|
||||||
|
content += GetStringSuffix();
|
||||||
|
xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PdfFont : public PdfObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string ToString(PdfXRefTable* xRefTable) override
|
||||||
|
{
|
||||||
|
UpdateDictionary();
|
||||||
|
auto content = GetStringPrefix();
|
||||||
|
content += mDictionary.ToString();
|
||||||
|
content += GetStringSuffix();
|
||||||
|
xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDictionary()
|
||||||
|
{
|
||||||
|
mDictionary.AddStringItem("Type", "/Font");
|
||||||
|
mDictionary.AddStringItem("Subtype", "/Type1");
|
||||||
|
mDictionary.AddStringItem("Name", "/F1");
|
||||||
|
mDictionary.AddStringItem("BaseFont", "/Helvetica");
|
||||||
|
mDictionary.AddStringItem("Encoding", "/MacRomanEncoding");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PdfPage : public PdfObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PdfPage(PdfPageTree* parent)
|
||||||
|
: mParent(parent)
|
||||||
|
{
|
||||||
|
mContent = std::make_unique<PdfStream>();
|
||||||
|
|
||||||
|
std::string pageContent = "BT\n";
|
||||||
|
pageContent += "/F1 24 Tf\n";
|
||||||
|
pageContent += "100 100 Td\n";
|
||||||
|
pageContent += "(Hello World) Tj\n";
|
||||||
|
pageContent += "ET";
|
||||||
|
|
||||||
|
mContent->SetContent(pageContent);
|
||||||
|
mProcSet = std::make_unique<PdfProcSet>();
|
||||||
|
|
||||||
|
mDefaultFont = std::make_unique<PdfFont>();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned IndexObjects(unsigned count)
|
||||||
|
{
|
||||||
|
auto newCount = count + 1;
|
||||||
|
mObjectNumber = newCount;
|
||||||
|
newCount = mContent->IndexObjects(newCount);
|
||||||
|
newCount = mProcSet->IndexObjects(newCount);
|
||||||
|
newCount = mDefaultFont->IndexObjects(newCount);
|
||||||
|
return newCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToString(PdfXRefTable* xRefTable) override
|
||||||
|
{
|
||||||
|
UpdateDictionary();
|
||||||
|
auto content = GetStringPrefix();
|
||||||
|
content += mDictionary.ToString();
|
||||||
|
content += GetStringSuffix();
|
||||||
|
xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);
|
||||||
|
|
||||||
|
content += mContent->ToString(xRefTable);
|
||||||
|
|
||||||
|
content += mProcSet->ToString(xRefTable);
|
||||||
|
|
||||||
|
content += mDefaultFont->ToString(xRefTable);
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDictionary()
|
||||||
|
{
|
||||||
|
std::string mediaBox = "[0 0 " + std::to_string(mWidth) + " " + std::to_string(mHeight) + "]";
|
||||||
|
mDictionary.AddStringItem("Type", "/Page");
|
||||||
|
mDictionary.AddStringItem("MediaBox", mediaBox);
|
||||||
|
mDictionary.AddStringItem("Parent", mParent->GetRefString());
|
||||||
|
mDictionary.AddStringItem("Contents", mContent->GetRefString());
|
||||||
|
|
||||||
|
auto resourcesDict = std::make_unique<PdfDictionary>();
|
||||||
|
resourcesDict->AddStringItem("ProcSet", mProcSet->GetRefString());
|
||||||
|
|
||||||
|
auto fontDict = std::make_unique<PdfDictionary>();
|
||||||
|
fontDict->AddStringItem("F1", mDefaultFont->GetRefString());
|
||||||
|
resourcesDict->AddDictItem("Font", std::move(fontDict));
|
||||||
|
|
||||||
|
mDictionary.AddDictItem("Resources", std::move(resourcesDict));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned mWidth{612};
|
||||||
|
unsigned mHeight{792};
|
||||||
|
std::unique_ptr<PdfStream> mContent;
|
||||||
|
std::unique_ptr<PdfFont> mDefaultFont;
|
||||||
|
PdfObjectPtr mProcSet;
|
||||||
|
PdfPageTree* mParent;
|
||||||
|
|
||||||
|
};
|
37
src/publishing/pdf/PdfPageTree.cpp
Normal file
37
src/publishing/pdf/PdfPageTree.cpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#include "PdfPageTree.h"
|
||||||
|
|
||||||
|
#include "PdfXRefTable.h"
|
||||||
|
#include "PdfPage.h"
|
||||||
|
|
||||||
|
PdfPageTree::PdfPageTree()
|
||||||
|
{
|
||||||
|
mRootPage = std::make_unique<PdfPage>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned PdfPageTree::IndexObjects(unsigned count)
|
||||||
|
{
|
||||||
|
auto newCount = count + 1;
|
||||||
|
mObjectNumber = newCount;
|
||||||
|
newCount = mRootPage->IndexObjects(newCount);
|
||||||
|
return newCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfPageTree::ToString(PdfXRefTable* xRefTable)
|
||||||
|
{
|
||||||
|
UpdateDictionary();
|
||||||
|
std::string content = GetStringPrefix();
|
||||||
|
content += mDictionary.ToString();
|
||||||
|
content += GetStringSuffix();
|
||||||
|
xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);
|
||||||
|
|
||||||
|
content += mRootPage->ToString(xRefTable);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PdfPageTree::UpdateDictionary()
|
||||||
|
{
|
||||||
|
mDictionary.AddStringItem("Type", "/Pages");
|
||||||
|
std::string kids = "[" + mRootPage->GetRefString() + "]";
|
||||||
|
mDictionary.AddStringItem("Kids", kids);
|
||||||
|
mDictionary.AddStringItem("Count", "1");
|
||||||
|
}
|
23
src/publishing/pdf/PdfPageTree.h
Normal file
23
src/publishing/pdf/PdfPageTree.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "PdfObject.h"
|
||||||
|
|
||||||
|
class PdfPage;
|
||||||
|
using PdfPagePtr = std::unique_ptr<PdfPage>;
|
||||||
|
|
||||||
|
class PdfPageTree : public PdfObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
PdfPageTree();
|
||||||
|
|
||||||
|
unsigned IndexObjects(unsigned count) override;
|
||||||
|
|
||||||
|
std::string ToString(PdfXRefTable* xRefTable) override;
|
||||||
|
|
||||||
|
void UpdateDictionary() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
PdfPagePtr mRootPage;
|
||||||
|
};
|
36
src/publishing/pdf/PdfStream.cpp
Normal file
36
src/publishing/pdf/PdfStream.cpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#include "PdfStream.h"
|
||||||
|
|
||||||
|
#include "PdfDictionary.h"
|
||||||
|
#include "PdfXRefTable.h"
|
||||||
|
|
||||||
|
PdfStream::PdfStream()
|
||||||
|
{
|
||||||
|
mDictionary.AddStringItem("Length", "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PdfStream::SetContent(const std::string& content)
|
||||||
|
{
|
||||||
|
mContent = content;
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PdfStream::Update()
|
||||||
|
{
|
||||||
|
auto length = mContent.size();
|
||||||
|
mDictionary.AddStringItem("Length", std::to_string(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfStream::ToString(PdfXRefTable* xRefTable)
|
||||||
|
{
|
||||||
|
std::string content = GetStringPrefix();
|
||||||
|
|
||||||
|
content += mDictionary.ToString();
|
||||||
|
|
||||||
|
content += "stream\n";
|
||||||
|
content += mContent;
|
||||||
|
content += "\nendstream\n";
|
||||||
|
content += "endobj\n\n";
|
||||||
|
|
||||||
|
xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);
|
||||||
|
return content;
|
||||||
|
}
|
19
src/publishing/pdf/PdfStream.h
Normal file
19
src/publishing/pdf/PdfStream.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "PdfObject.h"
|
||||||
|
|
||||||
|
class PdfStream : public PdfObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
PdfStream();
|
||||||
|
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
void SetContent(const std::string& content);
|
||||||
|
|
||||||
|
std::string ToString(PdfXRefTable* xRefTable) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mContent;
|
||||||
|
};
|
12
src/publishing/pdf/PdfWriter.cpp
Normal file
12
src/publishing/pdf/PdfWriter.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "PdfWriter.h"
|
||||||
|
|
||||||
|
#include "PdfDocument.h"
|
||||||
|
|
||||||
|
std::string PdfWriter::ToString(const std::unique_ptr<PdfDocument>& document) const
|
||||||
|
{
|
||||||
|
std::string content;
|
||||||
|
|
||||||
|
content += document->ToString();
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
13
src/publishing/pdf/PdfWriter.h
Normal file
13
src/publishing/pdf/PdfWriter.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class PdfDocument;
|
||||||
|
|
||||||
|
class PdfWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
std::string ToString(const std::unique_ptr<PdfDocument>& document) const;
|
||||||
|
};
|
68
src/publishing/pdf/PdfXRefTable.cpp
Normal file
68
src/publishing/pdf/PdfXRefTable.cpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#include "PdfXRefTable.h"
|
||||||
|
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
PdfXRefTable::PdfXRefTable()
|
||||||
|
{
|
||||||
|
mSections.push_back(TableSubSection());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PdfXRefTable::ToString()
|
||||||
|
{
|
||||||
|
std::string content;
|
||||||
|
for (const auto& section : mSections)
|
||||||
|
{
|
||||||
|
content += "xref\n" + std::to_string(section.mStartIndex) + " " + std::to_string(section.mRecords.size());
|
||||||
|
content += "\n";
|
||||||
|
for (const auto& record : section.mRecords)
|
||||||
|
{
|
||||||
|
auto offsetString = StringUtils::ToPaddedString(10, record.mOffsetBytes);
|
||||||
|
auto generationString = StringUtils::ToPaddedString(5, record.mGenerationNumber);
|
||||||
|
auto freeString = record.mIsFree ? "f" : "n";
|
||||||
|
|
||||||
|
content += offsetString + " " + generationString + " " + freeString + "\n";
|
||||||
|
}
|
||||||
|
content += "\n";
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned PdfXRefTable::GetNextOffset()
|
||||||
|
{
|
||||||
|
auto lastNumRecords = mSections[mSections.size() - 1].mRecords.size();
|
||||||
|
if (lastNumRecords > 0)
|
||||||
|
{
|
||||||
|
return mSections[mSections.size() - 1].mRecords[lastNumRecords -1].mOffsetBytes + mLastAddedBytes;
|
||||||
|
}
|
||||||
|
else if (mSections.size() > 1)
|
||||||
|
{
|
||||||
|
lastNumRecords = mSections[mSections.size() - 2].mRecords.size();
|
||||||
|
return mSections[mSections.size() - 2].mRecords[lastNumRecords -1].mOffsetBytes + mLastAddedBytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PdfXRefTable::AddRecord(unsigned numBytes, unsigned generation, unsigned isFree)
|
||||||
|
{
|
||||||
|
XRefRecord record;
|
||||||
|
|
||||||
|
record.mOffsetBytes = GetNextOffset();
|
||||||
|
record.mGenerationNumber = generation;
|
||||||
|
record.mIsFree = isFree;
|
||||||
|
mSections[mSections.size()-1].mRecords.push_back(record);
|
||||||
|
mLastAddedBytes = numBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned PdfXRefTable::GetNumEntries()
|
||||||
|
{
|
||||||
|
unsigned count = 0;
|
||||||
|
for (const auto& section : mSections)
|
||||||
|
{
|
||||||
|
count += section.mRecords.size();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
37
src/publishing/pdf/PdfXRefTable.h
Normal file
37
src/publishing/pdf/PdfXRefTable.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct XRefRecord
|
||||||
|
{
|
||||||
|
unsigned mOffsetBytes{0};
|
||||||
|
unsigned mGenerationNumber{0};
|
||||||
|
bool mIsFree{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TableSubSection
|
||||||
|
{
|
||||||
|
unsigned mStartIndex{0};
|
||||||
|
std::vector<XRefRecord> mRecords;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PdfXRefTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
PdfXRefTable();
|
||||||
|
|
||||||
|
std::string ToString();
|
||||||
|
|
||||||
|
unsigned GetNextOffset();
|
||||||
|
|
||||||
|
void AddRecord(unsigned numBytes, unsigned generation, unsigned isFree);
|
||||||
|
|
||||||
|
unsigned GetNumEntries();
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned mLastAddedBytes{0};
|
||||||
|
std::vector<TableSubSection> mSections;
|
||||||
|
};
|
30
src/video/CMakeLists.txt
Normal file
30
src/video/CMakeLists.txt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
list(APPEND video_HEADERS
|
||||||
|
Video.h
|
||||||
|
FfmpegInterface.h
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND video_LIB_INCLUDES
|
||||||
|
Video.cpp
|
||||||
|
FfmegInterface.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(video SHARED ${video_LIB_INCLUDES} ${video_HEADERS})
|
||||||
|
|
||||||
|
target_include_directories(video PUBLIC
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
)
|
||||||
|
set_target_properties( video PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||||
|
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
|
||||||
|
libavdevice
|
||||||
|
libavfilter
|
||||||
|
libavformat
|
||||||
|
libavcodec
|
||||||
|
libswresample
|
||||||
|
libswscale
|
||||||
|
libavutil
|
||||||
|
)
|
||||||
|
target_link_libraries( video PUBLIC image PkgConfig::LIBAV)
|
||||||
|
|
||||||
|
set_property(TARGET image PROPERTY FOLDER src)
|
118
src/video/FfmegInterface.cpp
Normal file
118
src/video/FfmegInterface.cpp
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
#include "FfmpegInterface.h"
|
||||||
|
|
||||||
|
#include "Image.h"
|
||||||
|
#include "Video.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/dict.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <libavutil/imgutils.h>
|
||||||
|
#include <libswscale/swscale.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Image> > FfmpegInterface::decodeToImages(const std::unique_ptr<Video>& video, unsigned maxImages)
|
||||||
|
{
|
||||||
|
std::vector<std::unique_ptr<Image> > images;
|
||||||
|
|
||||||
|
AVFormatContext* fmt_ctx{nullptr};
|
||||||
|
|
||||||
|
auto ret = avformat_open_input(&fmt_ctx, video->GetPath().c_str(), nullptr, nullptr);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
//AVDictionaryEntry* tag{nullptr};
|
||||||
|
//while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
|
||||||
|
//{
|
||||||
|
// std::cout << "key: " << tag->key << " value: " << tag->value << std::endl;
|
||||||
|
//}
|
||||||
|
|
||||||
|
ret = avformat_find_stream_info(fmt_ctx, nullptr);
|
||||||
|
|
||||||
|
AVCodec* decoder;
|
||||||
|
const auto bestStreamIdx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
|
||||||
|
|
||||||
|
//std::cout << "Best stream idx = " << std::to_string(bestStreamIdx) << std::endl;
|
||||||
|
//std::cout << "Codec is: " << decoder->name << " |" << decoder->long_name << std::endl;
|
||||||
|
|
||||||
|
AVCodecContext* decoder_context = avcodec_alloc_context3(decoder);
|
||||||
|
|
||||||
|
avcodec_parameters_to_context(decoder_context, fmt_ctx->streams[bestStreamIdx]->codecpar);
|
||||||
|
av_opt_set_int(decoder_context, "refcounted_frames", 1, 0);
|
||||||
|
|
||||||
|
avcodec_open2(decoder_context, decoder, nullptr);
|
||||||
|
|
||||||
|
AVPacket packet;
|
||||||
|
AVFrame* frame = av_frame_alloc();
|
||||||
|
AVFrame* scaled_frame = av_frame_alloc();
|
||||||
|
|
||||||
|
int w = decoder_context->width;
|
||||||
|
int h = decoder_context->height;
|
||||||
|
|
||||||
|
scaled_frame->width = w;
|
||||||
|
scaled_frame->height = h;
|
||||||
|
scaled_frame->format = AV_PIX_FMT_RGB24;
|
||||||
|
|
||||||
|
av_image_alloc(scaled_frame->data, scaled_frame->linesize, w, h, AV_PIX_FMT_RGB24, 32);
|
||||||
|
|
||||||
|
|
||||||
|
auto img_convert_ctx = sws_getContext(w, h,
|
||||||
|
decoder_context->pix_fmt,
|
||||||
|
w, h, AV_PIX_FMT_RGB24, SWS_BICUBIC,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
for (unsigned idx=0; idx<100; idx++)
|
||||||
|
{
|
||||||
|
auto frame_ret = av_read_frame(fmt_ctx, &packet);
|
||||||
|
if (frame_ret)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet.stream_index == bestStreamIdx)
|
||||||
|
{
|
||||||
|
avcodec_send_packet(decoder_context, &packet);
|
||||||
|
ret = 0;
|
||||||
|
while(ret >= 0)
|
||||||
|
{
|
||||||
|
ret = avcodec_receive_frame(decoder_context, frame);
|
||||||
|
|
||||||
|
if (ret >= 0)
|
||||||
|
{
|
||||||
|
frame->pts = frame->best_effort_timestamp;
|
||||||
|
|
||||||
|
sws_scale(img_convert_ctx, frame->data,
|
||||||
|
frame->linesize, 0,
|
||||||
|
decoder_context->height,
|
||||||
|
scaled_frame->data, scaled_frame->linesize);
|
||||||
|
|
||||||
|
auto image = Image::Create(frame->width, frame->height);
|
||||||
|
image->SetNumChannels(3);
|
||||||
|
|
||||||
|
auto bufferSize = av_image_get_buffer_size(AV_PIX_FMT_RGB24, frame->width, frame->height, 32);
|
||||||
|
std::vector<unsigned char> data(bufferSize, 0);
|
||||||
|
|
||||||
|
auto copyRet = av_image_copy_to_buffer(data.data(), bufferSize,
|
||||||
|
scaled_frame->data, scaled_frame->linesize,
|
||||||
|
AV_PIX_FMT_RGB24, frame->width, frame->height, 32);
|
||||||
|
|
||||||
|
image->SetData(data);
|
||||||
|
images.push_back(std::move(image));
|
||||||
|
}
|
||||||
|
av_frame_unref(frame);
|
||||||
|
//av_frame_unref(scaled_frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
av_packet_unref(&packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
avcodec_free_context(&decoder_context);
|
||||||
|
avformat_close_input(&fmt_ctx);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
|
||||||
|
return images;
|
||||||
|
}
|
15
src/video/FfmpegInterface.h
Normal file
15
src/video/FfmpegInterface.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Image;
|
||||||
|
class Video;
|
||||||
|
|
||||||
|
class FfmpegInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Image> > decodeToImages(const std::unique_ptr<Video>& video, unsigned maxImages=0);
|
||||||
|
|
||||||
|
};
|
16
src/video/Video.cpp
Normal file
16
src/video/Video.cpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include "Video.h"
|
||||||
|
|
||||||
|
std::unique_ptr<Video> Video::Create()
|
||||||
|
{
|
||||||
|
return std::make_unique<Video>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Video::SetPath(const std::string& path)
|
||||||
|
{
|
||||||
|
mPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Video::GetPath() const
|
||||||
|
{
|
||||||
|
return mPath;
|
||||||
|
}
|
18
src/video/Video.h
Normal file
18
src/video/Video.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Video
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::unique_ptr<Video> Create();
|
||||||
|
void SetPath(const std::string& path);
|
||||||
|
std::string GetPath() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::string mPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
using VideoPtr = std::unique_ptr<Video>;
|
|
@ -8,6 +8,9 @@ list(APPEND web_LIB_INCLUDES
|
||||||
markdown/MarkdownParser.cpp
|
markdown/MarkdownParser.cpp
|
||||||
html/HtmlWriter.cpp
|
html/HtmlWriter.cpp
|
||||||
html/HtmlDocument.cpp
|
html/HtmlDocument.cpp
|
||||||
|
html/HtmlElement.cpp
|
||||||
|
html/elements/HtmlHeadElement.cpp
|
||||||
|
html/elements/HtmlBodyElement.cpp
|
||||||
DocumentConverter.cpp)
|
DocumentConverter.cpp)
|
||||||
|
|
||||||
# add the executable
|
# add the executable
|
||||||
|
@ -21,6 +24,7 @@ target_include_directories(web PUBLIC
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/xml"
|
"${CMAKE_CURRENT_SOURCE_DIR}/xml"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/xml/xml-elements"
|
"${CMAKE_CURRENT_SOURCE_DIR}/xml/xml-elements"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/html"
|
"${CMAKE_CURRENT_SOURCE_DIR}/html"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/html/elements"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/markdown"
|
"${CMAKE_CURRENT_SOURCE_DIR}/markdown"
|
||||||
)
|
)
|
||||||
set_property(TARGET web PROPERTY FOLDER src)
|
set_property(TARGET web PROPERTY FOLDER src)
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
#include "HtmlDocument.h"
|
#include "HtmlDocument.h"
|
||||||
|
|
||||||
|
#include "HtmlHeadElement.h"
|
||||||
|
#include "HtmlBodyElement.h"
|
||||||
|
|
||||||
HtmlDocument::HtmlDocument()
|
HtmlDocument::HtmlDocument()
|
||||||
: XmlDocument()
|
: XmlDocument()
|
||||||
{
|
{
|
||||||
|
auto root = XmlElement::Create("html");
|
||||||
|
SetRoot(std::move(root));
|
||||||
|
|
||||||
|
auto header = std::make_unique<HtmlHeadElement>();
|
||||||
|
GetRoot()->AddChild(std::move(header));
|
||||||
|
|
||||||
|
auto body = std::make_unique<HtmlBodyElement>();
|
||||||
|
GetRoot()->AddChild(std::move(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<HtmlDocument> HtmlDocument::Create()
|
std::shared_ptr<HtmlDocument> HtmlDocument::Create()
|
||||||
|
|
|
@ -9,6 +9,7 @@ public:
|
||||||
HtmlDocument();
|
HtmlDocument();
|
||||||
|
|
||||||
static std::shared_ptr<HtmlDocument> Create();
|
static std::shared_ptr<HtmlDocument> Create();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using HtmlDocumentPtr = std::shared_ptr<HtmlDocument>;
|
using HtmlDocumentPtr = std::shared_ptr<HtmlDocument>;
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "HtmlDocument.h";
|
||||||
|
|
||||||
|
class HtmlDomManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
HtmlDomManager();
|
||||||
|
|
||||||
|
HtmlDocument* GetDocument();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HtmlDocumentPtr mDocument;
|
||||||
|
};
|
|
@ -6,7 +6,7 @@ HtmlElement::HtmlElement(const std::string& tagName)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<HtmlElement> HtmlElement::CreateUnique(const std::string& tagName)
|
std::unique_ptr<HtmlElement> HtmlElement::CreateUnique(const std::string& tagName)
|
||||||
{
|
{
|
||||||
return std::make_unique<HtmlElement>(tagName);
|
return std::make_unique<HtmlElement>(tagName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "../xml/xml-elements/XmlElement.h"
|
#include "XmlElement.h"
|
||||||
|
|
||||||
class HtmlElement : public XmlElement
|
class HtmlElement : public XmlElement
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
HtmlElement(const std::string& tagName);
|
HtmlElement(const std::string& tagName);
|
||||||
|
|
||||||
static std::unique_ptr<HtmlElement> CreateUnique(const std::string& tagName);
|
static std::unique_ptr<HtmlElement> CreateUnique(const std::string& tagName);
|
||||||
|
|
|
@ -5,7 +5,58 @@ HtmlWriter::HtmlWriter()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string HtmlWriter::ToString(XmlElement* element, unsigned depth)
|
||||||
|
{
|
||||||
|
const auto prefix = std::string(2*depth, ' ');
|
||||||
|
|
||||||
|
auto content = prefix + "<" + element->GetTagName();
|
||||||
|
for (std::size_t idx=0; idx< element->GetNumAttributes(); idx++)
|
||||||
|
{
|
||||||
|
auto attribute = element->GetAttribute(idx);
|
||||||
|
content += " " + attribute->GetName() + "=\"" + attribute->GetValue() + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto num_children = element->GetNumChildren();
|
||||||
|
if (num_children == 0 && element->GetText().empty())
|
||||||
|
{
|
||||||
|
content += "/>\n";
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content += ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!element->GetText().empty())
|
||||||
|
{
|
||||||
|
content += element->GetText();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_children>0)
|
||||||
|
{
|
||||||
|
content += "\n";
|
||||||
|
}
|
||||||
|
for (std::size_t idx=0; idx< element->GetNumChildren(); idx++)
|
||||||
|
{
|
||||||
|
auto child = element->GetChild(idx);
|
||||||
|
content += ToString(child, depth+1);
|
||||||
|
}
|
||||||
|
if (num_children>0)
|
||||||
|
{
|
||||||
|
content += prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
content += "</" + element->GetTagName() + ">\n";
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
std::string HtmlWriter::ToString(HtmlDocumentPtr document)
|
std::string HtmlWriter::ToString(HtmlDocumentPtr document)
|
||||||
{
|
{
|
||||||
return "<html>Uh oh!!!!</html>";
|
std::string content = "<!DOCTYPE html>\n";
|
||||||
|
|
||||||
|
if (auto root = document->GetRoot())
|
||||||
|
{
|
||||||
|
content += ToString(root);
|
||||||
|
}
|
||||||
|
return content;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,7 @@ public:
|
||||||
HtmlWriter();
|
HtmlWriter();
|
||||||
|
|
||||||
std::string ToString(HtmlDocumentPtr document);
|
std::string ToString(HtmlDocumentPtr document);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string ToString(XmlElement* element, unsigned depth=0);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "HtmlElement.h"
|
||||||
|
|
||||||
|
class HtmlBodyElement : public HtmlElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HtmlBodyElement() : HtmlElement("body")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "HtmlElement.h"
|
||||||
|
|
||||||
|
class HtmlHeadElement : public HtmlElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HtmlHeadElement() : HtmlElement("head")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,16 +1,29 @@
|
||||||
#include "MarkdownParser.h"
|
#include "MarkdownParser.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
MarkdownParser::MarkdownParser()
|
MarkdownParser::MarkdownParser()
|
||||||
: mHtmlDocument(HtmlDocument::Create())
|
: mHtmlDocument(HtmlDocument::Create())
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkdownParser::ProcessLine(const std::string)
|
void MarkdownParser::ProcessLine(const std::string& line)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MarkdownParser::Run(const std::string& content)
|
||||||
|
{
|
||||||
|
std::stringstream ss(content);
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(ss, line, '\n'))
|
||||||
|
{
|
||||||
|
ProcessLine(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HtmlDocumentPtr MarkdownParser::GetHtml()
|
HtmlDocumentPtr MarkdownParser::GetHtml()
|
||||||
{
|
{
|
||||||
return mHtmlDocument;
|
return mHtmlDocument;
|
||||||
|
|
|
@ -4,13 +4,27 @@
|
||||||
|
|
||||||
class MarkdownParser
|
class MarkdownParser
|
||||||
{
|
{
|
||||||
|
enum class DocumentState
|
||||||
|
{
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class LineState
|
||||||
|
{
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DocumentState mDocumentState {DocumentState::None};
|
||||||
HtmlDocumentPtr mHtmlDocument;
|
HtmlDocumentPtr mHtmlDocument;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MarkdownParser();
|
MarkdownParser();
|
||||||
|
|
||||||
void ProcessLine(const std::string);
|
|
||||||
|
|
||||||
HtmlDocumentPtr GetHtml();
|
HtmlDocumentPtr GetHtml();
|
||||||
|
|
||||||
|
void ProcessLine(const std::string& line);
|
||||||
|
|
||||||
|
void Run(const std::string& content);
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,8 +9,7 @@ XmlParser::XmlParser()
|
||||||
: mDocument(XmlDocument::Create()),
|
: mDocument(XmlDocument::Create()),
|
||||||
mDocumentState(XmlParser::DocumentState::Await_Prolog),
|
mDocumentState(XmlParser::DocumentState::Await_Prolog),
|
||||||
mLineState(XmlParser::LineState::Await_Tag_Open),
|
mLineState(XmlParser::LineState::Await_Tag_Open),
|
||||||
mParentElement(nullptr),
|
mWorkingElements()
|
||||||
mWorkingElement(nullptr)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -268,15 +267,12 @@ void XmlParser::OnTagClose()
|
||||||
onElementTagEnd();
|
onElementTagEnd();
|
||||||
}
|
}
|
||||||
else if(mDocumentState == DS::Close_Element)
|
else if(mDocumentState == DS::Close_Element)
|
||||||
{
|
|
||||||
if(mWorkingElement->GetTagName() == mWorkingTagName)
|
|
||||||
{
|
{
|
||||||
mDocumentState = DS::Await_Element;
|
mDocumentState = DS::Await_Element;
|
||||||
mLineState = LS::Await_Tag_Open;
|
mLineState = LS::Await_Tag_Open;
|
||||||
if(mParentElement)
|
if (!mWorkingElements.empty())
|
||||||
{
|
{
|
||||||
mWorkingElement = mParentElement;
|
mWorkingElements.pop();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,7 +285,7 @@ void XmlParser::OnTextStart(char c)
|
||||||
|
|
||||||
void XmlParser::OnTextEnd()
|
void XmlParser::OnTextEnd()
|
||||||
{
|
{
|
||||||
mWorkingElement->SetText(mWorkingText);
|
mWorkingElements.top()->SetText(mWorkingText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XmlParser::onElementTagEnd()
|
void XmlParser::onElementTagEnd()
|
||||||
|
@ -318,14 +314,17 @@ void XmlParser::OnTagNameEnd()
|
||||||
else if(mDocumentState == DS::Build_Element)
|
else if(mDocumentState == DS::Build_Element)
|
||||||
{
|
{
|
||||||
auto new_element = XmlElement::Create(mWorkingTagName);
|
auto new_element = XmlElement::Create(mWorkingTagName);
|
||||||
|
auto working_element = new_element.get();
|
||||||
mParentElement = mWorkingElement;
|
|
||||||
mWorkingElement = new_element.get();
|
|
||||||
|
|
||||||
if (!mDocument->GetRoot())
|
if (!mDocument->GetRoot())
|
||||||
{
|
{
|
||||||
mDocument->SetRoot(std::move(new_element));
|
mDocument->SetRoot(std::move(new_element));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mWorkingElements.top()->AddChild(std::move(new_element));
|
||||||
|
}
|
||||||
|
mWorkingElements.push(working_element);
|
||||||
mLineState = LS::Await_Attribute_Name;
|
mLineState = LS::Await_Attribute_Name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,7 +344,7 @@ void XmlParser::OnAttributeNameEnd()
|
||||||
}
|
}
|
||||||
else if(mDocumentState == DS::Build_Element)
|
else if(mDocumentState == DS::Build_Element)
|
||||||
{
|
{
|
||||||
mWorkingElement->AddAttribute(std::move(attribute));
|
mWorkingElements.top()->AddAttribute(std::move(attribute));
|
||||||
}
|
}
|
||||||
mLineState = LS::Await_Attribute_Value;
|
mLineState = LS::Await_Attribute_Value;
|
||||||
}
|
}
|
||||||
|
@ -358,7 +357,14 @@ void XmlParser::OnAttributeValueStart()
|
||||||
|
|
||||||
void XmlParser::OnAttributeValueEnd()
|
void XmlParser::OnAttributeValueEnd()
|
||||||
{
|
{
|
||||||
mWorkingElement->GetAttribute(mWorkingAttributeName)->SetValue(mWorkingAttributeValue);
|
if(mDocumentState == DS::Build_Prolog)
|
||||||
|
{
|
||||||
|
mDocument->GetProlog()->GetAttribute(mWorkingAttributeName)->SetValue(mWorkingAttributeValue);
|
||||||
|
}
|
||||||
|
else if(mDocumentState == DS::Build_Element)
|
||||||
|
{
|
||||||
|
mWorkingElements.top()->GetAttribute(mWorkingAttributeName)->SetValue(mWorkingAttributeValue);
|
||||||
|
}
|
||||||
mLineState = LS::Await_Attribute_Name;
|
mLineState = LS::Await_Attribute_Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <stack>
|
||||||
#include "XmlDocument.h"
|
#include "XmlDocument.h"
|
||||||
|
|
||||||
class XmlParser
|
class XmlParser
|
||||||
|
@ -33,8 +34,7 @@ private:
|
||||||
DocumentState mDocumentState;
|
DocumentState mDocumentState;
|
||||||
LineState mLineState;
|
LineState mLineState;
|
||||||
XmlDocumentPtr mDocument;
|
XmlDocumentPtr mDocument;
|
||||||
XmlElement* mParentElement;
|
std::stack<XmlElement*> mWorkingElements;
|
||||||
XmlElement* mWorkingElement;
|
|
||||||
std::string mWorkingAttributeName;
|
std::string mWorkingAttributeName;
|
||||||
std::string mWorkingTagName;
|
std::string mWorkingTagName;
|
||||||
std::string mWorkingAttributeValue;
|
std::string mWorkingAttributeValue;
|
||||||
|
|
|
@ -1,6 +1,68 @@
|
||||||
#include "XmlWriter.h"
|
#include "XmlWriter.h"
|
||||||
|
|
||||||
void XmlWriter::Write(File* file, XmlDocument* document)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
std::string XmlWriter::ToString(XmlElement* element, unsigned depth)
|
||||||
|
{
|
||||||
|
const auto prefix = std::string(2*depth, ' ');
|
||||||
|
|
||||||
|
auto content = prefix + "<" + element->GetTagName();
|
||||||
|
for (std::size_t idx=0; idx< element->GetNumAttributes(); idx++)
|
||||||
|
{
|
||||||
|
auto attribute = element->GetAttribute(idx);
|
||||||
|
content += " " + attribute->GetName() + "=\"" + attribute->GetValue() + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto num_children = element->GetNumChildren();
|
||||||
|
if (num_children == 0 && element->GetText().empty())
|
||||||
|
{
|
||||||
|
content += "/>\n";
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content += ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!element->GetText().empty())
|
||||||
|
{
|
||||||
|
content += element->GetText();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_children>0)
|
||||||
|
{
|
||||||
|
content += "\n";
|
||||||
|
}
|
||||||
|
for (std::size_t idx=0; idx< element->GetNumChildren(); idx++)
|
||||||
|
{
|
||||||
|
auto child = element->GetChild(idx);
|
||||||
|
content += ToString(child, depth+1);
|
||||||
|
}
|
||||||
|
if (num_children>0)
|
||||||
|
{
|
||||||
|
content += prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
content += "</" + element->GetTagName() + ">\n";
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string XmlWriter::ToString(XmlDocument* document)
|
||||||
|
{
|
||||||
|
std::string content;
|
||||||
|
if (auto prolog = document->GetProlog())
|
||||||
|
{
|
||||||
|
content += "<?xml";
|
||||||
|
for (std::size_t idx=0; idx< prolog->GetNumAttributes(); idx++)
|
||||||
|
{
|
||||||
|
auto attribute = prolog->GetAttribute(idx);
|
||||||
|
content += " " + attribute->GetName() + "=\"" + attribute->GetValue() + "\"";
|
||||||
|
}
|
||||||
|
content += "?>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto root = document->GetRoot())
|
||||||
|
{
|
||||||
|
content += ToString(root);
|
||||||
|
}
|
||||||
|
return content;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "File.h"
|
|
||||||
#include "XmlDocument.h"
|
#include "XmlDocument.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
class XmlWriter
|
class XmlWriter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
XmlWriter() = default;
|
XmlWriter() = default;
|
||||||
|
|
||||||
void Write(File* file, XmlDocument* document);
|
std::string ToString(XmlDocument* document);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string ToString(XmlElement* element, unsigned depth=0);
|
||||||
};
|
};
|
||||||
|
|
|
@ -68,3 +68,13 @@ std::size_t XmlElement::GetNumAttributes() const
|
||||||
{
|
{
|
||||||
return mAttributes.size();
|
return mAttributes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t XmlElement::GetNumChildren() const
|
||||||
|
{
|
||||||
|
return mChildren.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlElement* XmlElement::GetChild(std::size_t index) const
|
||||||
|
{
|
||||||
|
return mChildren[index].get();
|
||||||
|
}
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "XmlAttribute.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "xml-elements/XmlAttribute.h"
|
|
||||||
|
|
||||||
class XmlElement
|
class XmlElement
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
std::string mTagName;
|
|
||||||
std::vector<XmlAttributeUPtr> mAttributes;
|
|
||||||
std::vector<std::unique_ptr<XmlElement> > mChildren;
|
|
||||||
std::string mText;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
XmlElement(const std::string& tagName);
|
XmlElement(const std::string& tagName);
|
||||||
virtual ~XmlElement() = default;
|
virtual ~XmlElement() = default;
|
||||||
|
@ -28,8 +23,17 @@ public:
|
||||||
XmlAttribute* GetAttribute(std::size_t index) const;
|
XmlAttribute* GetAttribute(std::size_t index) const;
|
||||||
std::size_t GetNumAttributes() const;
|
std::size_t GetNumAttributes() const;
|
||||||
|
|
||||||
|
std::size_t GetNumChildren() const;
|
||||||
|
XmlElement* GetChild(std::size_t index) const;
|
||||||
|
|
||||||
void SetText(const std::string& text);
|
void SetText(const std::string& text);
|
||||||
void SetTagName(const std::string& tagName);
|
void SetTagName(const std::string& tagName);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string mTagName;
|
||||||
|
std::vector<XmlAttributeUPtr> mAttributes;
|
||||||
|
std::vector<std::unique_ptr<XmlElement> > mChildren;
|
||||||
|
std::string mText;
|
||||||
};
|
};
|
||||||
|
|
||||||
using XmlElementPtr = std::shared_ptr<XmlElement>;
|
using XmlElementPtr = std::shared_ptr<XmlElement>;
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "xml-elements/XmlElement.h"
|
#include "XmlElement.h"
|
||||||
|
|
||||||
class XmlProlog : public XmlElement
|
class XmlProlog : public XmlElement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum class Version{
|
enum class Version{
|
||||||
V1_0
|
V1_0
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,16 +10,35 @@ target_include_directories(test_utils PUBLIC
|
||||||
list(APPEND TestFiles
|
list(APPEND TestFiles
|
||||||
audio/TestAudioWriter.cpp
|
audio/TestAudioWriter.cpp
|
||||||
audio/TestMidiReader.cpp
|
audio/TestMidiReader.cpp
|
||||||
graphics/TestOpenGlRendering.cpp)
|
database/TestDatabase.cpp
|
||||||
|
graphics/TestOpenGlRendering.cpp
|
||||||
|
ipc/TestDbus.cpp
|
||||||
|
image/TestPngWriter.cpp
|
||||||
|
publishing/TestPdfWriter.cpp
|
||||||
|
video/TestVideoDecoder.cpp
|
||||||
|
web/TestMarkdownParser.cpp
|
||||||
|
web/TestXmlParser.cpp)
|
||||||
|
|
||||||
list(APPEND TestNames
|
list(APPEND TestNames
|
||||||
TestAudioWriter
|
TestAudioWriter
|
||||||
TestMidiReader
|
TestMidiReader
|
||||||
TestOpenGlRendering)
|
TestDatabase
|
||||||
|
TestOpenGlRendering
|
||||||
|
TestDbus
|
||||||
|
TestPngWriter
|
||||||
|
TestPdfWriter
|
||||||
|
TestVideoDecoder
|
||||||
|
TestMarkdownParser
|
||||||
|
TestXmlParser)
|
||||||
|
|
||||||
|
find_package(PkgConfig)
|
||||||
|
pkg_check_modules(DBUS REQUIRED dbus-1)
|
||||||
|
include_directories(${DBUS_INCLUDE_DIRS})
|
||||||
|
link_directories(${DBUS_LIBRARY_DIRS})
|
||||||
|
|
||||||
foreach(TestFile TestName IN ZIP_LISTS TestFiles TestNames)
|
foreach(TestFile TestName IN ZIP_LISTS TestFiles TestNames)
|
||||||
add_executable(${TestName} ${TestFile})
|
add_executable(${TestName} ${TestFile})
|
||||||
target_link_libraries(${TestName} PUBLIC core network database geometry audio graphics web client test_utils)
|
target_link_libraries(${TestName} PUBLIC core network image publishing video database geometry audio graphics web client test_utils ${DBUS_LIBRARIES})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
class TestWriteWav : public TestCase
|
class TestWriteWav : public TestCase
|
||||||
|
@ -32,9 +34,11 @@ class TestAudioRender : public TestCase
|
||||||
public:
|
public:
|
||||||
bool Run() override
|
bool Run() override
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
WasapiInterface audio_interface;
|
WasapiInterface audio_interface;
|
||||||
auto device = AudioDevice::Create();
|
auto device = AudioDevice::Create();
|
||||||
audio_interface.Play(device);
|
audio_interface.Play(device);
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -42,8 +46,9 @@ public:
|
||||||
//int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
|
//int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||||
|
#endif
|
||||||
std::cout << "into entry point" << std::endl;
|
std::cout << "into entry point" << std::endl;
|
||||||
TestCaseRunner runner;
|
TestCaseRunner runner;
|
||||||
//runner.AddTestCase("TestWriteNav", std::make_unique<TestWriteWav>());
|
//runner.AddTestCase("TestWriteNav", std::make_unique<TestWriteWav>());
|
||||||
|
@ -51,6 +56,7 @@ int main()
|
||||||
|
|
||||||
const auto testsPassed = runner.Run();
|
const auto testsPassed = runner.Run();
|
||||||
return testsPassed ? 0 : -1;
|
return testsPassed ? 0 : -1;
|
||||||
|
#ifdef _WIN32
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
20
test/data/sample_markdown.md
Normal file
20
test/data/sample_markdown.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# I'm a level one header
|
||||||
|
I'm some text under level one
|
||||||
|
|
||||||
|
## I'm a level two header
|
||||||
|
I'm some text under level two
|
||||||
|
|
||||||
|
```
|
||||||
|
I'm a code block
|
||||||
|
```
|
||||||
|
|
||||||
|
I'm a line under the code block, with some `inline code`.
|
||||||
|
|
||||||
|
### I'm a level three header
|
||||||
|
I'm a bullet point list:
|
||||||
|
|
||||||
|
* First point
|
||||||
|
* Second point
|
||||||
|
* Third point
|
||||||
|
|
||||||
|
With a [hyperlink](www.imahyperlink.com) embedded.
|
12
test/database/TestDatabase.cpp
Normal file
12
test/database/TestDatabase.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "DatabaseManager.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
DatabaseManager db_manager;
|
||||||
|
db_manager.CreateDatabase("test.db");
|
||||||
|
|
||||||
|
std::string statement = "CREATE TABLE corporation;";
|
||||||
|
db_manager.Run(statement);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
31
test/image/TestPngWriter.cpp
Normal file
31
test/image/TestPngWriter.cpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#include "Image.h"
|
||||||
|
#include "PngWriter.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
unsigned width = 200;
|
||||||
|
unsigned height = 200;
|
||||||
|
unsigned numChannels = 3;
|
||||||
|
auto image = Image::Create(width, height);
|
||||||
|
image->SetNumChannels(numChannels);
|
||||||
|
|
||||||
|
std::vector<unsigned char> data(image->GetBytesPerRow()*height, 0);
|
||||||
|
for(unsigned jdx=0;jdx<height;jdx++)
|
||||||
|
{
|
||||||
|
const auto heightOffset = jdx*image->GetBytesPerRow();
|
||||||
|
for(unsigned idx=0;idx<width*numChannels;idx+=numChannels)
|
||||||
|
{
|
||||||
|
const auto index = heightOffset + idx;
|
||||||
|
data[index] = (idx%2 == 0) ? 255*jdx/(height+1) : 0;
|
||||||
|
data[index+1] = 0;
|
||||||
|
data[index+2] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
image->SetData(data);
|
||||||
|
|
||||||
|
PngWriter writer;
|
||||||
|
writer.SetPath("test.png");
|
||||||
|
writer.Write(image);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
8
test/ipc/TestDbus.cpp
Normal file
8
test/ipc/TestDbus.cpp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#include <dbus/dbus.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
DBusError err;
|
||||||
|
DBusConnection* conn;
|
||||||
|
return 0;
|
||||||
|
}
|
18
test/publishing/TestPdfWriter.cpp
Normal file
18
test/publishing/TestPdfWriter.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "PdfDocument.h"
|
||||||
|
#include "PdfWriter.h"
|
||||||
|
#include "PdfObject.h"
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
auto document = std::make_unique<PdfDocument>();
|
||||||
|
|
||||||
|
PdfWriter writer;
|
||||||
|
const auto output = writer.ToString(document);
|
||||||
|
|
||||||
|
File pdf_file("TestPdfWriter.pdf");
|
||||||
|
pdf_file.SetAccessMode(File::AccessMode::Write);
|
||||||
|
pdf_file.Open();
|
||||||
|
pdf_file.WriteText(output);
|
||||||
|
return 0;
|
||||||
|
}
|
25
test/video/TestVideoDecoder.cpp
Normal file
25
test/video/TestVideoDecoder.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include "Video.h"
|
||||||
|
#include "Image.h"
|
||||||
|
#include "FfmpegInterface.h"
|
||||||
|
#include "PngWriter.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
auto video = Video::Create();
|
||||||
|
video->SetPath("/home/jmsgrogan/test.mp4");
|
||||||
|
|
||||||
|
FfmpegInterface decoder;
|
||||||
|
auto images = decoder.decodeToImages(video, 4);
|
||||||
|
std::cout << "Got " << std::to_string(images.size()) << std::endl;
|
||||||
|
|
||||||
|
PngWriter writer;
|
||||||
|
for(unsigned idx=0; idx<20; idx++)
|
||||||
|
{
|
||||||
|
auto filename = "test_out" + std::to_string(idx) + ".png";
|
||||||
|
writer.SetPath(filename);
|
||||||
|
writer.Write(images[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
25
test/web/TestMarkdownParser.cpp
Normal file
25
test/web/TestMarkdownParser.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include "MarkdownParser.h"
|
||||||
|
#include "File.h"
|
||||||
|
#include "HtmlWriter.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
File md_file("/home/jmsgrogan/code/MediaTool/test/data/sample_markdown.md");
|
||||||
|
md_file.Open();
|
||||||
|
const auto md_content = md_file.ReadText();
|
||||||
|
|
||||||
|
MarkdownParser parser;
|
||||||
|
parser.Run(md_content);
|
||||||
|
|
||||||
|
auto html = parser.GetHtml();
|
||||||
|
|
||||||
|
HtmlWriter writer;
|
||||||
|
const auto html_string = writer.ToString(html);
|
||||||
|
|
||||||
|
File html_file("TestMarkdownParserOut.html");
|
||||||
|
html_file.SetAccessMode(File::AccessMode::Write);
|
||||||
|
html_file.Open();
|
||||||
|
html_file.WriteText(html_string);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
31
test/web/TestXmlParser.cpp
Normal file
31
test/web/TestXmlParser.cpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "XmlParser.h"
|
||||||
|
#include "XmlWriter.h"
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
XmlParser parser;
|
||||||
|
|
||||||
|
std::ifstream xml_file;
|
||||||
|
xml_file.open("/home/jmsgrogan/test.xml", std::ifstream::in);
|
||||||
|
while(xml_file.good())
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
std::getline(xml_file, line);
|
||||||
|
parser.ProcessLine(line);
|
||||||
|
}
|
||||||
|
xml_file.close();
|
||||||
|
|
||||||
|
auto outFile = std::make_unique<File>("test_out.xml");
|
||||||
|
outFile->SetAccessMode(File::AccessMode::Write);
|
||||||
|
outFile->Open();
|
||||||
|
|
||||||
|
XmlWriter writer;
|
||||||
|
auto content = writer.ToString(parser.GetDocument().get());
|
||||||
|
outFile->WriteText(content);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue