From 0cf833840b19e603f480dead5ca211f947503f9b Mon Sep 17 00:00:00 2001 From: Thomas Schmucker Date: Sun, 9 Mar 2025 22:26:25 +0100 Subject: Initial commit --- bin/.gitkeep | 0 include/xml.hpp | 28 +++++++++++++++++++++ makefile | 47 +++++++++++++++++++++++++++++++++++ obj/.gitkeep | 0 src/xml.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/xml_test.cpp | 58 +++++++++++++++++++++++++++++++++++++++++++ test.xml | 7 ++++++ 7 files changed, 215 insertions(+) create mode 100644 bin/.gitkeep create mode 100644 include/xml.hpp create mode 100644 makefile create mode 100644 obj/.gitkeep create mode 100644 src/xml.cpp create mode 100644 src/xml_test.cpp create mode 100644 test.xml diff --git a/bin/.gitkeep b/bin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/include/xml.hpp b/include/xml.hpp new file mode 100644 index 0000000..cc593a3 --- /dev/null +++ b/include/xml.hpp @@ -0,0 +1,28 @@ +#ifndef XML_HPP_INCLUDED +#define XML_HPP_INCLUDED + +// Standard C++ +#include +#include +#include + +class XML { + public: + void parse(std::istream& in); + + protected: + virtual void handle_start(const std::string& name, const std::vector>& attr) = 0; + virtual void handle_end(const std::string& name) = 0; + virtual void handle_cdata_start() {} + virtual void handle_cdata_end() {} + virtual void handle_data(const std::vector&) {} + + private: + static void tag_start(void* me, const char* name, const char* attr[]); + static void tag_end(void* me, const char* name); + static void cdata_start(void* me); + static void cdata_end(void* me); + static void data(void* me, const char* dat, int len); +}; + +#endif diff --git a/makefile b/makefile new file mode 100644 index 0000000..637130c --- /dev/null +++ b/makefile @@ -0,0 +1,47 @@ +EXE = bin/xml.exe + +all: $(EXE) + +EMPTY = + +CONTRIB = ../contrib + +EXPAT_DIR = $(CONTRIB)/expat-2.2.0 +EXPAT_INCLUDE_DIR = $(EXPAT_DIR)/lib +EXPAT_LIB_DIR = $(EXPAT_DIR)/win32/bin/Release +EXPAT_LIBS = libexpatMT.lib + +OBJS = \ + obj/xml.obj \ + obj/xml_test.obj \ + $(EMPTY) + +WIN32_LIBS = kernel32.lib comdlg32.lib user32.lib gdi32.lib ole32.lib wsock32.lib Ws2_32.lib comctl32.lib shell32.lib oleaut32.lib advapi32.lib uuid.lib Winspool.lib + +# === Compilereinstellungen === + +CPPFLAGS=-nologo -EHsc -Ox -MT -W4 -WX -Iinclude -I$(EXPAT_INCLUDE_DIR) -DWIN32 -D_WINDOWS -D_CRT_NOFORCE_MANIFEST -D_CRT_SECURE_NO_WARNINGS -DNDEBUG + +# === Linkereinstellungen === + +LDFLAGS=-nologo -MANIFEST:NO -LIBPATH:$(EXPAT_LIB_DIR) +LDFLAGS2=$(WIN32_LIBS) $(EXPAT_LIBS) + +$(EXE): $(OBJS) + @echo link $@ + @link.exe $(LDFLAGS) -out:$@ $(LDFLAGS2) $(OBJS) + +obj/%.obj: src/%.cpp + @echo compiling $@ + cl $(CPPFLAGS) -Tp$< -c -Fo$@ + +obj/%.obj: src/%.c + @echo compiling $@ + @cl $(CPPFLAGS) -Tc$< -c -Fo$@ + +clean: + @echo cleaning... + @del bin\*.exe + @del obj\** + @del *.pdb + diff --git a/obj/.gitkeep b/obj/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/xml.cpp b/src/xml.cpp new file mode 100644 index 0000000..44b423a --- /dev/null +++ b/src/xml.cpp @@ -0,0 +1,75 @@ +// Standard C++ +#include +#include + +// Projekt +#include "xml.hpp" + +// Expat XML Parser +#define XML_STATIC // force static linkage +#include "expat.h" + +using namespace std; + +void +XML::parse(istream& in) +{ + unique_ptr parser(XML_ParserCreate(nullptr), XML_ParserFree); + + // setup expat + XML_SetUserData(parser.get(), this); + XML_SetElementHandler(parser.get(), tag_start, tag_end); + XML_SetCdataSectionHandler(parser.get(), cdata_start, cdata_end); + XML_SetCharacterDataHandler(parser.get(), data); + + char buffer[2048]; + for ( bool done = false; !done ; ) { + in.read(buffer, sizeof buffer); + done = (in.gcount() < sizeof buffer); + + if ( XML_Parse(parser.get(), buffer, static_cast(in.gcount()), done) != XML_STATUS_OK ) { + stringstream msg; + + msg << XML_ErrorString(XML_GetErrorCode(parser.get())); + msg << " in line " << XML_GetCurrentLineNumber(parser.get()); + + throw runtime_error( msg.str() ); + } + } +} + +void +XML::tag_start(void* me, const char* name, const char* attr[]) +{ + vector> attr_temp; + + for ( size_t i = 0; attr[i]; i += 2 ) + attr_temp.push_back( make_pair(attr[i], attr[i+1]) ); + + reinterpret_cast(me)->handle_start(name, attr_temp); +} + +void +XML::tag_end(void* me, const char* name) +{ + reinterpret_cast(me)->handle_end(name); +} + +void +XML::cdata_start(void* me) +{ + reinterpret_cast(me)->handle_cdata_start(); +} + +void +XML::cdata_end(void* me) +{ + reinterpret_cast(me)->handle_cdata_end(); +} + +void +XML::data(void* me, const char* dat, int len) +{ + reinterpret_cast(me)->handle_data(vector(dat, dat+len)); +} + diff --git a/src/xml_test.cpp b/src/xml_test.cpp new file mode 100644 index 0000000..0af5b51 --- /dev/null +++ b/src/xml_test.cpp @@ -0,0 +1,58 @@ +#include +#include +using namespace std; + +#include "xml.hpp" + +class MyXML : public XML { + public: + explicit MyXML(ostream& out, size_t indent = 4) + : pout_(&out) + , depth_(0) + , indent_(indent) + { + } + + protected: + void handle_start(const string& name, const vector>& attr) + { + *pout_ << string(depth_++ * indent_, ' ') + << "<" << name; + + auto it = cbegin(attr); + auto end = cend(attr); + if ( it != end ) { + *pout_ << " " << it->first << "=\"" << it->second << "\""; + + ++it; // skip first Element + for ( ; it != end; ++it ) + *pout_ << ", " << it->first << "=\"" << it->second << "\""; + } + + *pout_ << ">" << endl; + } + + void handle_end(const string& name) + { + *pout_ << string(--depth_ * indent_, ' ') + << "" + << endl; + } + + private: + ostream* pout_; + size_t depth_; + size_t indent_; +}; + +int +main() +{ + try { + MyXML myxml(cout); + myxml.parse(cin); + } + catch ( exception& e ) { + cerr << "Fehler: " << e.what() << endl; + } +} diff --git a/test.xml b/test.xml new file mode 100644 index 0000000..24d4371 --- /dev/null +++ b/test.xml @@ -0,0 +1,7 @@ + + + + Hallo Welt!]]> + + + -- cgit v1.3