diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index df8d63f..f413c23 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -5,7 +5,7 @@ target_include_directories(sample_gui PUBLIC "${PROJECT_SOURCE_DIR}/src/client" ) target_link_libraries(sample_gui PUBLIC client windows console core - network database geometry audio graphics) + network database geometry audio graphics web) # Sample Console add_executable(sample_console console-main.cpp) @@ -13,7 +13,7 @@ target_include_directories(sample_console PUBLIC "${PROJECT_SOURCE_DIR}/src/console" ) target_link_libraries(sample_console PUBLIC console core network - database geometry audio) + database geometry audio web) # Xml practice add_executable(xml_practice xml-practice.cpp) @@ -21,12 +21,4 @@ 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) - -# Markdown practice -add_executable(markdown_practice markdown-practice.cpp) -target_include_directories(markdown_practice PUBLIC - "${PROJECT_SOURCE_DIR}/src/core" - "${PROJECT_SOURCE_DIR}/src/web/markdown" - ) -target_link_libraries(markdown_practice PUBLIC web core) \ No newline at end of file +target_link_libraries(xml_practice PUBLIC core web) \ No newline at end of file diff --git a/apps/console-main.cpp b/apps/console-main.cpp index d6e96db..8492cc1 100644 --- a/apps/console-main.cpp +++ b/apps/console-main.cpp @@ -1,37 +1,18 @@ -#include -#include -#include #include "CommandLineArgs.h" #include "MainApplication.h" int main(int argc, char *argv[]) { - CommandLineArgs command_line_args; - command_line_args.Process(argc, argv); + auto command_line_args = CommandLineArgs::CreateUnique(); + command_line_args->Process(argc, argv); + command_line_args->RecordLaunchPath(); - std::string program_type; - if(command_line_args.GetNumberOfArgs() > 1) - { - program_type = command_line_args.GetArg(1); - } + // Start the main app + auto main_app = MainApplication::Create(); + main_app->Initialize(std::move(command_line_args)); - // Start the main app - auto main_app = MainApplication::Create(); - main_app->Initialize(std::filesystem::current_path()); + main_app->Run(); - if(program_type == "server") - { - main_app->RunServer(); - } - else if(program_type == "audio") - { - main_app->PlayAudio(); - } - else - { - std::cerr << "Unknown program type" << std::endl; - } - - main_app->ShutDown(); - return 0; + main_app->ShutDown(); + return 0; } diff --git a/apps/gui-main.cpp b/apps/gui-main.cpp index c5490b8..aae106a 100644 --- a/apps/gui-main.cpp +++ b/apps/gui-main.cpp @@ -1,14 +1,18 @@ -#include #include #include "GuiApplication.h" #include "MainApplication.h" +#include "CommandLineArgs.h" -int main() +int main(int argc, char *argv[]) { + auto command_line_args = CommandLineArgs::CreateUnique(); + command_line_args->Process(argc, argv); + command_line_args->RecordLaunchPath(); + // Start the main app auto main_app = MainApplication::Create(); - main_app->Initialize(std::filesystem::current_path()); + main_app->Initialize(std::move(command_line_args)); // Start the gui app auto gui_app = std::make_shared(); diff --git a/apps/markdown-practice.cpp b/apps/markdown-practice.cpp deleted file mode 100644 index 4f605c3..0000000 --- a/apps/markdown-practice.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include -#include -#include "CommandLineArgs.h" -#include "MarkdownParser.h" -#include "HtmlDocument.h" -#include "HtmlWriter.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; - } - - MarkdownParser 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 md_file; - md_file.open(filepath, std::ifstream::in); - while(md_file.good()) - { - std::string line; - std::getline(md_file, line); - parser.ProcessLine(line); - } - md_file.close(); - - auto html_document = parser.GetHtml(); - HtmlWriter writer; - std::string html_string = writer.ToString(html_document); - std::ofstream out("/home/james/test.html"); - out << html_string; - out.close(); - return 0; -} diff --git a/src/console/CMakeLists.txt b/src/console/CMakeLists.txt index e222248..4c89ba9 100644 --- a/src/console/CMakeLists.txt +++ b/src/console/CMakeLists.txt @@ -3,6 +3,8 @@ list(APPEND console_LIB_INCLUDES MainApplication.cpp) add_library(console SHARED ${console_LIB_INCLUDES}) target_include_directories(console PUBLIC + "${PROJECT_SOURCE_DIR}/src/core/" + "${PROJECT_SOURCE_DIR}/src/core/file_utilities" "${PROJECT_SOURCE_DIR}/src/core/loggers" "${PROJECT_SOURCE_DIR}/src/database" "${PROJECT_SOURCE_DIR}/src/database/database_interfaces" @@ -11,4 +13,5 @@ target_include_directories(console PUBLIC "${PROJECT_SOURCE_DIR}/src/audio" "${PROJECT_SOURCE_DIR}/src/audio/midi" "${PROJECT_SOURCE_DIR}/src/audio/audio_interfaces" + "${PROJECT_SOURCE_DIR}/src/web" ) \ No newline at end of file diff --git a/src/console/MainApplication.cpp b/src/console/MainApplication.cpp index dc9a92b..b464f7b 100644 --- a/src/console/MainApplication.cpp +++ b/src/console/MainApplication.cpp @@ -1,9 +1,13 @@ #include "MainApplication.h" #include "FileLogger.h" #include "MidiReader.h" +#include "File.h" +#include "DocumentConverter.h" +#include MainApplication::MainApplication() - : mDatabaseManager() + : mDatabaseManager(), + mCommandLineArgs() { } @@ -13,20 +17,64 @@ MainApplication::~MainApplication() } -void MainApplication::Initialize(const std::filesystem::path& workDir) +void MainApplication::Initialize(CommandLineArgsUPtr commandLineArgs) { - FileLogger::GetInstance().SetWorkDirectory(workDir.string()); + mCommandLineArgs = std::move(commandLineArgs); + std::string launch_path = mCommandLineArgs->GetLaunchPath().string(); + + FileLogger::GetInstance().SetWorkDirectory(launch_path); FileLogger::GetInstance().Open(); MLOG_INFO("Launched"); mDatabaseManager = DatabaseManager::Create(); - mDatabaseManager->CreateDatabase(workDir.string() + "/database.db"); + mDatabaseManager->CreateDatabase(launch_path + "/database.db"); mNetworkManager = NetworkManager::Create(); mAudioManager = AudioManager::Create(); } +void MainApplication::Run() +{ + std::string program_type; + if(mCommandLineArgs->GetNumberOfArgs() > 1) + { + program_type = mCommandLineArgs->GetArg(1); + } + + std::string input_path; + std::string output_path; + for(unsigned idx=1; idxGetNumberOfArgs(); idx++) + { + auto arg = mCommandLineArgs->GetArg(idx); + if(arg == "-input" && mCommandLineArgs->GetNumberOfArgs() > idx+1) + { + input_path = mCommandLineArgs->GetArg(idx + 1); + } + else if(arg == "-output" && mCommandLineArgs->GetNumberOfArgs() > idx+1) + { + output_path = mCommandLineArgs->GetArg(idx + 1); + } + } + + if(program_type == "-server") + { + RunServer(); + } + else if(program_type == "-audio") + { + PlayAudio(); + } + else if(program_type == "-convert") + { + ConvertDocument(input_path, output_path); + } + else + { + MLOG_ERROR("Unknown program type: " + program_type); + } +} + void MainApplication::RunServer() { mNetworkManager->RunHttpServer(); @@ -41,6 +89,15 @@ void MainApplication::PlayAudio() mAudioManager->GetAudioInterface()->Play(device); } +void MainApplication::ConvertDocument(const std::string& inputPath, const std::string& outputPath) +{ + auto input_file = File(std::filesystem::path(inputPath)); + auto output_file = File(std::filesystem::path(outputPath)); + MLOG_INFO("Converting: " + inputPath + " to " + outputPath); + DocumentConverter converter; + converter.Convert(&input_file, &output_file); +} + void MainApplication::ShutDown() { mDatabaseManager->OnShutDown(); diff --git a/src/console/MainApplication.h b/src/console/MainApplication.h index 275caa8..780e6c7 100644 --- a/src/console/MainApplication.h +++ b/src/console/MainApplication.h @@ -7,11 +7,13 @@ #include "FileLogger.h" #include "DatabaseManager.h" #include "NetworkManager.h" +#include "CommandLineArgs.h" class MainApplication { private: + CommandLineArgsUPtr mCommandLineArgs; DatabaseManagerPtr mDatabaseManager; NetworkManagerPtr mNetworkManager; AudioManagerPtr mAudioManager; @@ -22,15 +24,20 @@ public: ~MainApplication(); - void Initialize(const std::filesystem::path& workDir); + void Initialize(CommandLineArgsUPtr commandLineArgs); - void RunServer(); - - void PlayAudio(); + void Run(); void ShutDown(); static std::shared_ptr Create(); + +private: + void RunServer(); + + void PlayAudio(); + + void ConvertDocument(const std::string& inputPath, const std::string& outputPath); }; using MainApplicationPtr = std::shared_ptr; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4f09cf3..a852845 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -4,6 +4,8 @@ list(APPEND core_LIB_INCLUDES CommandLineArgs.cpp loggers/FileLogger.cpp file_utilities/BinaryFile.cpp + file_utilities/File.cpp + file_utilities/FileFormats.cpp StringUtils.cpp http/HttpResponse.cpp) @@ -12,4 +14,6 @@ add_library(core SHARED ${core_LIB_INCLUDES}) target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}/file_utilities" + "${CMAKE_CURRENT_SOURCE_DIR}/loggers" ) \ No newline at end of file diff --git a/src/core/CommandLineArgs.cpp b/src/core/CommandLineArgs.cpp index 11a5bd2..336b971 100644 --- a/src/core/CommandLineArgs.cpp +++ b/src/core/CommandLineArgs.cpp @@ -1,29 +1,45 @@ #include "CommandLineArgs.h" CommandLineArgs::CommandLineArgs() - : mArugments() + : mArugments(), + mLaunchPath() { } +std::unique_ptr CommandLineArgs::CreateUnique() +{ + return std::make_unique(); +} + +std::filesystem::path CommandLineArgs::GetLaunchPath() +{ + return mLaunchPath; +} + +void CommandLineArgs::RecordLaunchPath() +{ + mLaunchPath = std::filesystem::current_path(); +} + void CommandLineArgs::Process(int argc, char *argv[]) { - for(int idx=0; idx #include #include +#include class CommandLineArgs { - std::vector mArugments; + std::vector mArugments; + std::filesystem::path mLaunchPath; public: - CommandLineArgs(); + CommandLineArgs(); - void Process(int argc, char *argv[]); + static std::unique_ptr CreateUnique(); - std::size_t GetNumberOfArgs() const; + void RecordLaunchPath(); - std::string GetArg(std::size_t index) const; + std::filesystem::path GetLaunchPath(); + + void Process(int argc, char *argv[]); + + std::size_t GetNumberOfArgs() const; + + std::string GetArg(std::size_t index) const; }; + +using CommandLineArgsUPtr = std::unique_ptr; diff --git a/src/core/StringUtils.cpp b/src/core/StringUtils.cpp index cc91ce5..9729f2e 100644 --- a/src/core/StringUtils.cpp +++ b/src/core/StringUtils.cpp @@ -1,5 +1,6 @@ #include "StringUtils.h" #include +#include bool StringUtils::IsAlphaNumeric(char c) { @@ -12,3 +13,11 @@ bool StringUtils::IsSpace(char c) std::locale loc; return std::isspace(c, loc); } + +std::string StringUtils::ToLower(const std::string& s) +{ + std::string ret; + std::transform(s.begin(), s.end(), ret.begin(), + [](unsigned char c){ return std::tolower(c); }); + return ret; +} diff --git a/src/core/StringUtils.h b/src/core/StringUtils.h index 8a973a6..6601076 100644 --- a/src/core/StringUtils.h +++ b/src/core/StringUtils.h @@ -16,4 +16,5 @@ public: static bool IsAlphaNumeric(char c); static bool IsSpace(char c); + static std::string ToLower(const std::string& s); }; diff --git a/src/core/file_utilities/File.cpp b/src/core/file_utilities/File.cpp new file mode 100644 index 0000000..940da13 --- /dev/null +++ b/src/core/file_utilities/File.cpp @@ -0,0 +1,68 @@ +#include "File.h" +#include "FileLogger.h" + +File::File(std::filesystem::path path) + : mFullPath(path), + mInHandle(), + mOutHandle(), + mAccessMode(AccessMode::Read) +{ + +} + +std::string File::GetExtension() const +{ + return mFullPath.extension(); +} + +void File::SetAccessMode(AccessMode mode) +{ + mAccessMode = mode; +} + +std::ifstream* File::GetInHandle() const +{ + return mInHandle.get(); +} + +std::ofstream* File::GetOutHandle() const +{ + return mOutHandle.get(); +} + +void File::Open() +{ + if(mAccessMode == AccessMode::Read) + { + mInHandle = std::make_unique(); + mInHandle->open(mFullPath, std::ifstream::in); + } + else + { + mOutHandle = std::make_unique(); + mOutHandle->open(mFullPath, std::ofstream::out); + } +} + +void File::Close() +{ + if(mOutHandle) + { + mOutHandle->close(); + } + if(mInHandle) + { + mInHandle->close(); + } +} + +FileFormat::Format File::InferFormat() const +{ + const auto extension = GetExtension(); + return FileFormat::InferFormat(extension); +} + +bool File::PathExists() const +{ + return std::filesystem::exists(mFullPath); +} diff --git a/src/core/file_utilities/File.h b/src/core/file_utilities/File.h new file mode 100644 index 0000000..aad1223 --- /dev/null +++ b/src/core/file_utilities/File.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include +#include "FileFormats.h" +#include +#include + +class File +{ +public: + enum class AccessMode{ + Read, + Write + }; + +private: + + std::filesystem::path mFullPath; + std::unique_ptr mInHandle; + std::unique_ptr mOutHandle; + AccessMode mAccessMode; + +public: + + File(std::filesystem::path fullPath); + + std::string GetExtension() const; + + FileFormat::Format InferFormat() const; + + std::ifstream* GetInHandle() const; + + std::ofstream* GetOutHandle() const; + + bool PathExists() const; + + void SetAccessMode(AccessMode mode); + + void Open(); + + void Close(); + +}; diff --git a/src/core/file_utilities/FileFormats.cpp b/src/core/file_utilities/FileFormats.cpp new file mode 100644 index 0000000..e75ca09 --- /dev/null +++ b/src/core/file_utilities/FileFormats.cpp @@ -0,0 +1,9 @@ +#include "FileFormats.h" + +FileFormat::ExtensionMap FileFormat::mExtensions = [] +{ + ExtensionMap ret; + ret[Format::Markdown] = ".md"; + ret[Format::Html] = ".html"; + return ret; +}(); diff --git a/src/core/file_utilities/FileFormats.h b/src/core/file_utilities/FileFormats.h new file mode 100644 index 0000000..a1941b2 --- /dev/null +++ b/src/core/file_utilities/FileFormats.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include "StringUtils.h" + +class FileFormat{ + +public: + enum class Encoding{ + Ascii, + UTF8, + Binary + }; + + enum class Format{ + Html, + Xml, + Markdown, + Pdf, + Json, + Png, + Wav, + Midi, + Unknown + }; + + using ExtensionMap = std::map; + +private: + static ExtensionMap mExtensions; + +public: + + bool IsFormat(const std::string& extension, Format format) + { + return StringUtils::ToLower(extension) == mExtensions[format]; + } + + static Format InferFormat(const std::string& query) + { + for(const auto& extension : mExtensions) + { + if(extension.second == query) + { + return extension.first; + } + } + return Format::Unknown; + } + + std::string GetExtension(Format format) + { + return mExtensions[format]; + } +}; + diff --git a/src/web/CMakeLists.txt b/src/web/CMakeLists.txt index a6b1a50..11c718a 100644 --- a/src/web/CMakeLists.txt +++ b/src/web/CMakeLists.txt @@ -6,14 +6,18 @@ list(APPEND web_LIB_INCLUDES xml/XmlProlog.cpp markdown/MarkdownParser.cpp html/HtmlWriter.cpp - html/HtmlDocument.cpp) + html/HtmlDocument.cpp + DocumentConverter.cpp) # add the executable add_library(web SHARED ${web_LIB_INCLUDES}) target_include_directories(web PUBLIC "${PROJECT_SOURCE_DIR}/src/core/" + "${PROJECT_SOURCE_DIR}/src/core/loggers" + "${PROJECT_SOURCE_DIR}/src/core/file_utilities" "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/xml" "${CMAKE_CURRENT_SOURCE_DIR}/html" + "${CMAKE_CURRENT_SOURCE_DIR}/markdown" ) \ No newline at end of file diff --git a/src/web/DocumentConverter.cpp b/src/web/DocumentConverter.cpp new file mode 100644 index 0000000..114e268 --- /dev/null +++ b/src/web/DocumentConverter.cpp @@ -0,0 +1,76 @@ +#include "DocumentConverter.h" +#include "MarkdownParser.h" +#include "HtmlWriter.h" +#include "FileLogger.h" +#include + +DocumentConverter::DocumentConverter() +{ + +} + +void DocumentConverter::Convert(File* input, File* output) +{ + if(!input || !output) + { + return; + } + + const auto input_format = input->InferFormat(); + switch (input_format) + { + case FileFormat::Format::Markdown: + { + ConvertMarkdown(input, output); + break; + } + default: + { + break; + } + } +} + +void DocumentConverter::ConvertMarkdown(File* input, File* output) +{ + const auto output_format = output->InferFormat(); + switch (output_format) + { + case FileFormat::Format::Html: + { + MarkdownToHtml(input, output); + break; + } + default: + { + break; + } + } +} + +void DocumentConverter::MarkdownToHtml(File* input, File* output) +{ + MLOG_INFO("Converting Markdown to Html"); + input->SetAccessMode(File::AccessMode::Read); + input->Open(); + + MarkdownParser parser; + + auto handle = input->GetInHandle(); + while(handle->good()) + { + std::string line; + std::getline(*handle, line); + parser.ProcessLine(line); + }; + input->Close(); + + auto html_document = parser.GetHtml(); + HtmlWriter writer; + std::string html_string = writer.ToString(html_document); + + output->SetAccessMode(File::AccessMode::Write); + output->Open(); + *(output->GetOutHandle()) << html_string; + output->Close(); +} diff --git a/src/web/DocumentConverter.h b/src/web/DocumentConverter.h new file mode 100644 index 0000000..c987b2f --- /dev/null +++ b/src/web/DocumentConverter.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include "File.h" + +class DocumentConverter +{ +public: + DocumentConverter(); + + void Convert(File* input, File* output); + + void ConvertMarkdown(File* input, File* output); + + void MarkdownToHtml(File* input, File* output); +}; diff --git a/src/web/html/HtmlElement.cpp b/src/web/html/HtmlElement.cpp index 35c274b..2c766c0 100644 --- a/src/web/html/HtmlElement.cpp +++ b/src/web/html/HtmlElement.cpp @@ -1,11 +1,12 @@ #include "HtmlElement.h" -HtmlElement::HtmlElement() +HtmlElement::HtmlElement(const std::string& tagName) + : XmlElement(tagName) { } -static std::shared_ptr HtmlElement::Create() +static std::unique_ptr HtmlElement::CreateUnique(const std::string& tagName) { - return std::make_shared(); + return std::make_unique(tagName); } diff --git a/src/web/html/HtmlElement.h b/src/web/html/HtmlElement.h index 0344406..3ca13a9 100644 --- a/src/web/html/HtmlElement.h +++ b/src/web/html/HtmlElement.h @@ -4,9 +4,9 @@ class HtmlElement : public XmlElement { - HtmlElement(); + HtmlElement(const std::string& tagName); - static std::shared_ptr Create(); + static std::unique_ptr CreateUnique(const std::string& tagName); }; -using HtmlElementPtr = std::shared_ptr; +using HtmlElementUPtr = std::unique_ptr; diff --git a/src/web/xml/XmlAttribute.cpp b/src/web/xml/XmlAttribute.cpp index 4e0e734..19f662b 100644 --- a/src/web/xml/XmlAttribute.cpp +++ b/src/web/xml/XmlAttribute.cpp @@ -2,28 +2,28 @@ XmlAttribute::XmlAttribute(const std::string& name) - : mName(name), - mValue() + : mName(name), + mValue() { } -std::shared_ptr XmlAttribute::Create(const std::string& name) +XmlAttributeUPtr XmlAttribute::Create(const std::string& name) { - return std::make_shared(name); + return std::make_unique(name); } void XmlAttribute::SetValue(const std::string& value) { - mValue = value; + mValue = value; } std::string XmlAttribute::GetName() const { - return mName; + return mName; } std::string XmlAttribute::GetValue() const { - return mValue; + return mValue; } diff --git a/src/web/xml/XmlAttribute.h b/src/web/xml/XmlAttribute.h index 8dd700b..551f7c7 100644 --- a/src/web/xml/XmlAttribute.h +++ b/src/web/xml/XmlAttribute.h @@ -5,21 +5,22 @@ class XmlAttribute { - - std::string mName; - std::string mValue; +private: + std::string mName; + std::string mValue; public: - XmlAttribute(const std::string& name); + XmlAttribute(const std::string& name); - static std::shared_ptr Create(const std::string& name); + static std::unique_ptr Create(const std::string& name); - void SetValue(const std::string& value); + void SetValue(const std::string& value); - std::string GetName() const; + std::string GetName() const; - std::string GetValue() const; + std::string GetValue() const; }; using XmlAttributePtr = std::shared_ptr; +using XmlAttributeUPtr = std::unique_ptr; diff --git a/src/web/xml/XmlDocument.cpp b/src/web/xml/XmlDocument.cpp index 2b16e4d..2150db4 100644 --- a/src/web/xml/XmlDocument.cpp +++ b/src/web/xml/XmlDocument.cpp @@ -1,34 +1,33 @@ #include "XmlDocument.h" - XmlDocument::XmlDocument() - :mProlog(XmlProlog::Create("xml")) + :mProlog(XmlProlog::Create("xml")) { } -std::shared_ptr XmlDocument::Create() +XmlDocumentUPtr XmlDocument::Create() { - return std::make_shared(); + return std::make_unique(); } -void XmlDocument::SetProlog(XmlPrologPtr prolog) +void XmlDocument::SetProlog(XmlPrologUPtr prolog) { - mProlog = prolog; + mProlog = std::move(prolog); } -XmlPrologPtr XmlDocument::GetProlog() const +XmlProlog* XmlDocument::GetProlog() const { - return mProlog; + return mProlog.get(); } -void XmlDocument::SetRoot(XmlElementPtr root) +void XmlDocument::SetRoot(XmlElementUPtr root) { - mRoot = root; + mRoot = std::move(root); } -XmlElementPtr XmlDocument::GetRoot() const +XmlElement* XmlDocument::GetRoot() const { - return mRoot; + return mRoot.get(); } diff --git a/src/web/xml/XmlDocument.h b/src/web/xml/XmlDocument.h index 41e55b0..530f054 100644 --- a/src/web/xml/XmlDocument.h +++ b/src/web/xml/XmlDocument.h @@ -6,21 +6,20 @@ class XmlDocument { - XmlPrologPtr mProlog; - XmlElementPtr mRoot; + XmlPrologUPtr mProlog; + XmlElementUPtr mRoot; public: - XmlDocument(); + XmlDocument(); - static std::shared_ptr Create(); - - void SetProlog(XmlPrologPtr prolog); - XmlPrologPtr GetProlog() const; - - void SetRoot(XmlElementPtr root); - XmlElementPtr GetRoot() const; + static std::unique_ptr Create(); + XmlProlog* GetProlog() const; + XmlElement* GetRoot() const; + void SetProlog(XmlPrologUPtr prolog); + void SetRoot(XmlElementUPtr root); }; using XmlDocumentPtr = std::shared_ptr; +using XmlDocumentUPtr = std::unique_ptr; diff --git a/src/web/xml/XmlElement.cpp b/src/web/xml/XmlElement.cpp index fc62e32..ee27546 100644 --- a/src/web/xml/XmlElement.cpp +++ b/src/web/xml/XmlElement.cpp @@ -2,60 +2,69 @@ XmlElement::XmlElement(const std::string& tagName) - : mTagName(tagName), - mChildren() + : mTagName(tagName), + mChildren() { } -std::shared_ptr XmlElement::Create(const std::string& tagName) +XmlElementUPtr XmlElement::Create(const std::string& tagName) { - return std::make_shared(tagName); + return std::make_unique(tagName); } -void XmlElement::AddChild(std::shared_ptr child) +void XmlElement::SetTagName(const std::string& tagName) { - mChildren.push_back(child); + mTagName = tagName; +} + +void XmlElement::AddChild(XmlElementUPtr child) +{ + mChildren.push_back(std::move(child)); +} + +void XmlElement::AddAttribute(XmlAttributeUPtr attribute) +{ + mAttributes.push_back(std::move(attribute)); } std::string XmlElement::GetTagName() const { - return mTagName; + return mTagName; } std::string XmlElement::GetText() const { - return mText; + return mText; } void XmlElement::SetText(const std::string& text) { - mText = text; + mText = text; } -void XmlElement::AddAttribute(XmlAttributePtr attribute) +XmlAttribute* XmlElement::GetAttribute(const std::string& attributeName) const { - mAttributes.push_back(attribute); + for(const auto& attribute : mAttributes) + { + if(attribute->GetName() == attributeName) + { + return attribute.get(); + } + } + return nullptr; } -XmlAttributePtr XmlElement::GetAttribute(const std::string& attributeName) const +XmlAttribute* XmlElement::GetAttribute(std::size_t index) const { - for(const auto& attribute : mAttributes) - { - if(attribute->GetName() == attributeName) - { - return attribute; - } - } - return nullptr; + if(index < mAttributes.size()) + { + return mAttributes[index].get(); + } + return nullptr; } std::size_t XmlElement::GetNumAttributes() const { - return mAttributes.size(); -} - -std::vector XmlElement::GetAttributes() -{ - return mAttributes; + return mAttributes.size(); } diff --git a/src/web/xml/XmlElement.h b/src/web/xml/XmlElement.h index 5dfa64d..0de7b1d 100644 --- a/src/web/xml/XmlElement.h +++ b/src/web/xml/XmlElement.h @@ -7,26 +7,29 @@ class XmlElement { protected: - std::string mTagName; - std::vector mAttributes; - std::vector > mChildren; - std::string mText; + std::string mTagName; + std::vector mAttributes; + std::vector > mChildren; + std::string mText; public: - XmlElement(const std::string& tagName); - virtual ~XmlElement() = default; + XmlElement(const std::string& tagName); + virtual ~XmlElement() = default; - static std::shared_ptr Create(const std::string& tagName); + static std::unique_ptr Create(const std::string& tagName); - void AddChild(std::shared_ptr child); - std::string GetTagName() const; - std::string GetText() const; - void SetText(const std::string& text); + void AddAttribute(XmlAttributeUPtr attribute); + void AddChild(std::unique_ptr child); - void AddAttribute(XmlAttributePtr attribute); - XmlAttributePtr GetAttribute(const std::string& attribute) const; - std::size_t GetNumAttributes() const; - std::vector GetAttributes(); + std::string GetTagName() const; + std::string GetText() const; + XmlAttribute* GetAttribute(const std::string& attribute) const; + XmlAttribute* GetAttribute(std::size_t index) const; + std::size_t GetNumAttributes() const; + + void SetText(const std::string& text); + void SetTagName(const std::string& tagName); }; using XmlElementPtr = std::shared_ptr; +using XmlElementUPtr = std::unique_ptr; diff --git a/src/web/xml/XmlParser.cpp b/src/web/xml/XmlParser.cpp index 81831f3..fc5c847 100644 --- a/src/web/xml/XmlParser.cpp +++ b/src/web/xml/XmlParser.cpp @@ -6,375 +6,376 @@ using LS = XmlParser::LineState; using DS = XmlParser::DocumentState; XmlParser::XmlParser() - : mDocument(XmlDocument::Create()), - mDocumentState(XmlParser::DocumentState::Await_Prolog), - mLineState(XmlParser::LineState::Await_Tag_Open) + : mDocument(XmlDocument::Create()), + mDocumentState(XmlParser::DocumentState::Await_Prolog), + mLineState(XmlParser::LineState::Await_Tag_Open), + mParentElement(nullptr), + mWorkingElement(nullptr) { } void XmlParser::ProcessLine(const std::string& input) { - for(std::size_t idx; idxGetTagName() == mWorkingTagName) - { - mDocumentState = DS::Await_Element; - mLineState = LS::Await_Tag_Open; - if(mParentElement) - { - mWorkingElement = mParentElement; - } - } - } + if(mDocumentState == DS::Build_Prolog) + { + onFinishProlog(); + } + else if(mDocumentState == DS::Build_Element) + { + if(mLineState == LS::Await_Tag_Name_End) + { + OnTagNameEnd(); + } + onElementTagEnd(); + } + else if(mDocumentState == DS::Close_Element) + { + if(mWorkingElement->GetTagName() == mWorkingTagName) + { + mDocumentState = DS::Await_Element; + mLineState = LS::Await_Tag_Open; + if(mParentElement) + { + mWorkingElement = mParentElement; + } + } + } } void XmlParser::OnTextStart(char c) { - mWorkingText = c; - mLineState = LS::Await_Text_End; + mWorkingText = c; + mLineState = LS::Await_Text_End; } void XmlParser::OnTextEnd() { - mWorkingElement->SetText(mWorkingText); + mWorkingElement->SetText(mWorkingText); } void XmlParser::onElementTagEnd() { - mDocumentState = DS::Await_Element; - mLineState = LS::Await_Tag_Open; + mDocumentState = DS::Await_Element; + mLineState = LS::Await_Tag_Open; } void XmlParser::OnTagNameStart(char c) { - mWorkingTagName = c; - mLineState = LS::Await_Tag_Name_End; - if(mDocumentState != DS::Build_Prolog && mDocumentState != DS::Close_Element) - { - mDocumentState = DS::Build_Element; - } + mWorkingTagName = c; + mLineState = LS::Await_Tag_Name_End; + if(mDocumentState != DS::Build_Prolog && mDocumentState != DS::Close_Element) + { + mDocumentState = DS::Build_Element; + } } void XmlParser::OnTagNameEnd() { - if(mDocumentState == DS::Build_Prolog) - { - mWorkingProlog = XmlProlog::Create(mWorkingTagName); - mLineState = LS::Await_Attribute_Name; - } - else if(mDocumentState == DS::Build_Element) - { - auto new_element = XmlElement::Create(mWorkingTagName); - mParentElement = mWorkingElement; - mWorkingElement = new_element; + if(mDocumentState == DS::Build_Prolog) + { + mDocument->GetProlog()->SetTagName(mWorkingTagName); + mLineState = LS::Await_Attribute_Name; + } + else if(mDocumentState == DS::Build_Element) + { + auto new_element = XmlElement::Create(mWorkingTagName); - if(!mDocument->GetRoot()) - { - mDocument->SetRoot(mWorkingElement); - } - mLineState = LS::Await_Attribute_Name; - } + mParentElement = mWorkingElement; + mWorkingElement = new_element.get(); + + if(!mDocument->GetRoot()) + { + mDocument->SetRoot(std::move(new_element)); + } + mLineState = LS::Await_Attribute_Name; + } } void XmlParser::OnAttributeNameStart(char c) { - mWorkingAttributeName = c; - mLineState = LS::Await_Attribute_Name_End; + mWorkingAttributeName = c; + mLineState = LS::Await_Attribute_Name_End; } void XmlParser::OnAttributeNameEnd() { - mWorkingAttribute = XmlAttribute::Create(mWorkingAttributeName); - if(mDocumentState == DS::Build_Prolog) - { - mWorkingProlog->AddAttribute(mWorkingAttribute); - } - else if(mDocumentState == DS::Build_Element) - { - mWorkingElement->AddAttribute(mWorkingAttribute); - } - mLineState = LS::Await_Attribute_Value; + auto attribute = XmlAttribute::Create(mWorkingAttributeName); + if(mDocumentState == DS::Build_Prolog) + { + mDocument->GetProlog()->AddAttribute(std::move(attribute)); + } + else if(mDocumentState == DS::Build_Element) + { + mWorkingElement->AddAttribute(std::move(attribute)); + } + mLineState = LS::Await_Attribute_Value; } void XmlParser::OnAttributeValueStart() { - mWorkingAttributeValue = ""; - mLineState = LS::Await_Attribute_Value_End; + mWorkingAttributeValue = ""; + mLineState = LS::Await_Attribute_Value_End; } void XmlParser::OnAttributeValueEnd() { - mWorkingAttribute->SetValue(mWorkingAttributeValue); - mLineState = LS::Await_Attribute_Name; + mWorkingElement->GetAttribute(mWorkingAttributeName)->SetValue(mWorkingAttributeValue); + mLineState = LS::Await_Attribute_Name; } void XmlParser::OnStartProlog() { - mDocumentState = DS::Build_Prolog; - mLineState = LS::Await_Tag_Name_End; + mDocumentState = DS::Build_Prolog; + mLineState = LS::Await_Tag_Name_End; } void XmlParser::onFinishProlog() { - mWorkingProlog->Update(); - mDocument->SetProlog(mWorkingProlog); - mWorkingProlog = nullptr; - mDocumentState = DS::Await_Element; - mLineState = LS::Await_Tag_Open; + mDocument->GetProlog()->Update(); + mDocumentState = DS::Await_Element; + mLineState = LS::Await_Tag_Open; } XmlDocumentPtr XmlParser::GetDocument() const { - return mDocument; + return mDocument; } diff --git a/src/web/xml/XmlParser.h b/src/web/xml/XmlParser.h index 05bd1e0..289de2e 100644 --- a/src/web/xml/XmlParser.h +++ b/src/web/xml/XmlParser.h @@ -6,97 +6,95 @@ class XmlParser { public: - enum class DocumentState - { - Await_Prolog, - Build_Prolog, - Await_Element, - Build_Element, - Close_Element - }; + enum class DocumentState + { + Await_Prolog, + Build_Prolog, + Await_Element, + Build_Element, + Close_Element + }; - enum class LineState - { - Await_Tag_Open, - Await_Tag_Follower, - Await_Tag_Name, - Await_Tag_Name_End, - Await_Attribute_Name, - Await_Attribute_Name_End, - Await_Attribute_Value, - Await_Attribute_Value_End, - Await_Text_End - }; + enum class LineState + { + Await_Tag_Open, + Await_Tag_Follower, + Await_Tag_Name, + Await_Tag_Name_End, + Await_Attribute_Name, + Await_Attribute_Name_End, + Await_Attribute_Value, + Await_Attribute_Value_End, + Await_Text_End + }; private: - DocumentState mDocumentState; - LineState mLineState; - XmlDocumentPtr mDocument; - XmlPrologPtr mWorkingProlog; - XmlElementPtr mParentElement; - XmlElementPtr mWorkingElement; - XmlAttributePtr mWorkingAttribute; - std::string mWorkingAttributeName; - std::string mWorkingTagName; - std::string mWorkingAttributeValue; - std::string mWorkingText; + DocumentState mDocumentState; + LineState mLineState; + XmlDocumentPtr mDocument; + XmlElement* mParentElement; + XmlElement* mWorkingElement; + std::string mWorkingAttributeName; + std::string mWorkingTagName; + std::string mWorkingAttributeValue; + std::string mWorkingText; public: - XmlParser(); + XmlParser(); - void ProcessLine(const std::string& input); + void ProcessLine(const std::string& input); - XmlDocumentPtr GetDocument() const; + XmlDocumentPtr GetDocument() const; private: - void OnLeftBracket(); + void OnLeftBracket(); - void OnRightBracket(); + void OnRightBracket(); - void OnQuestionMark(); + void OnQuestionMark(); - void OnForwardSlash(); + void OnForwardSlash(); - void OnChar(char c); + void OnChar(char c); - void OnSpace(char c); + void OnSpace(char c); - void OnAlphaNumeric(char c); + void OnAlphaNumeric(char c); - void OnNonAlphaNumeric(char c); + void OnNonAlphaNumeric(char c); - void OnEquals(); + void OnEquals(); - void OnDoubleQuote(); + void OnDoubleQuote(); - void OnTagOpen(); + void OnTagOpen(); - void OnTagNameStart(char c); + void OnTagNameStart(char c); - void OnTagNameEnd(); + void OnTagNameEnd(); - void OnTagClose(); + void OnTagClose(); - void OnTextStart(char c); + void OnTextStart(char c); - void OnTextEnd(); + void OnTextEnd(); - void OnAttributeNameStart(char c); + void OnAttributeNameStart(char c); - void OnAttributeNameEnd(); + void OnAttributeNameEnd(); - void OnAttributeValueStart(); + void OnAttributeValueStart(); - void OnAttributeValueEnd(); + void OnAttributeValueEnd(); - void OnPrologId(); + void OnPrologId(); - void OnStartProlog(); + void OnStartProlog(); - void onFinishProlog(); + void onFinishProlog(); - void onElementTagEnd(); + void onElementTagEnd(); }; diff --git a/src/web/xml/XmlProlog.cpp b/src/web/xml/XmlProlog.cpp index 3199403..e66db0b 100644 --- a/src/web/xml/XmlProlog.cpp +++ b/src/web/xml/XmlProlog.cpp @@ -2,53 +2,53 @@ XmlProlog::XmlProlog(const std::string& tagName) - : XmlElement(tagName), - mVersion(XmlProlog::Version::V1_0), - mEncoding(XmlProlog::Encoding::UTF8) + : XmlElement(tagName), + mVersion(XmlProlog::Version::V1_0), + mEncoding(XmlProlog::Encoding::UTF8) { } -std::shared_ptr XmlProlog::Create(const std::string& tagName) +XmlPrologUPtr XmlProlog::Create(const std::string& tagName) { - return std::make_shared(tagName); + return std::make_unique(tagName); } XmlProlog::Encoding XmlProlog::GetEncoding() const { - return mEncoding; + return mEncoding; } XmlProlog::Version XmlProlog::GetVersion() const { - return mVersion; + return mVersion; } void XmlProlog::SetEncoding(const std::string& encoding) { - if(encoding == "UTF-8") - { - mEncoding == XmlProlog::Encoding::UTF8; - } + if(encoding == "UTF-8") + { + mEncoding == XmlProlog::Encoding::UTF8; + } } void XmlProlog::SetVersion(const std::string& version) { - if(version == "1.0") - { - mVersion == XmlProlog::Version::V1_0; - } + if(version == "1.0") + { + mVersion == XmlProlog::Version::V1_0; + } } void XmlProlog::Update() { - if(const auto version = GetAttribute("version")) - { - SetVersion(version->GetValue()); - } + if(const auto version = GetAttribute("version")) + { + SetVersion(version->GetValue()); + } - if(const auto encoding = GetAttribute("encoding")) - { - SetEncoding(encoding->GetValue()); - } + if(const auto encoding = GetAttribute("encoding")) + { + SetEncoding(encoding->GetValue()); + } } diff --git a/src/web/xml/XmlProlog.h b/src/web/xml/XmlProlog.h index 6e636cb..c9c6a0a 100644 --- a/src/web/xml/XmlProlog.h +++ b/src/web/xml/XmlProlog.h @@ -7,30 +7,31 @@ class XmlProlog : public XmlElement { public: - enum class Version{ - V1_0 - }; + enum class Version{ + V1_0 + }; - enum class Encoding{ - UTF8 - }; + enum class Encoding{ + UTF8 + }; private: - Version mVersion; - Encoding mEncoding; - std::string mTagName; + Version mVersion; + Encoding mEncoding; public: - XmlProlog(const std::string& tagName); + XmlProlog(const std::string& tagName); - static std::shared_ptr Create(const std::string& tagName); - void Update(); - Encoding GetEncoding() const; - Version GetVersion() const; + static std::unique_ptr Create(const std::string& tagName); - void SetEncoding(const std::string& encoding); - void SetVersion(const std::string& version); + Encoding GetEncoding() const; + Version GetVersion() const; + + void SetEncoding(const std::string& encoding); + void SetVersion(const std::string& version); + void Update(); }; using XmlPrologPtr = std::shared_ptr; +using XmlPrologUPtr = std::unique_ptr;