From c5c02d7f447fa556a8e996017e3823393fa84b1d Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Fri, 16 Jul 2021 18:17:57 +0200 Subject: [PATCH] HtmlTextStream has now pt::Stream as a based class and uses pt::WTextStream as a buffer --- winixd/core/app.cpp | 58 ++- winixd/core/app.h | 8 +- winixd/core/misc.cpp | 11 + winixd/core/misc.h | 36 +- winixd/core/request.cpp | 2 +- winixd/functions/rm.cpp | 2 +- winixd/models/item.cpp | 2 +- winixd/models/itemcontent.cpp | 42 ++ winixd/models/itemcontent.h | 1 + winixd/plugins/thread/templates.cpp | 4 +- winixd/templates/filters.cpp | 103 ++-- winixd/templates/htmltextstream.cpp | 703 ++++++++++++++++++---------- winixd/templates/htmltextstream.h | 163 +++++-- winixd/templates/insert.cpp | 4 +- 14 files changed, 764 insertions(+), 375 deletions(-) diff --git a/winixd/core/app.cpp b/winixd/core/app.cpp index a713f48..909e60c 100644 --- a/winixd/core/app.cpp +++ b/winixd/core/app.cpp @@ -696,7 +696,7 @@ void App::ClearAfterRequest() try { // simple operations which should not throw an exception - json_out_stream.Clear(); + json_out_stream.clear(); templates.ClearAfterRequest(); cur.request->Clear(); cur.session->ClearAfterRequest(); @@ -767,7 +767,7 @@ void App::SaveSessionsIfNeeded() -const std::wstring * App::CreateFrameAnswer() +pt::WTextStream * App::CreateFrameAnswer() { Request & req = *cur.request; auto i = req.out_streams.streams_map.begin(); @@ -777,8 +777,7 @@ const std::wstring * App::CreateFrameAnswer() { if( (frame && i->first == *frame) || (!frame && i->first == L"content") ) { - return &i->second->Str(); - break; + return &i->second->get_buffer(); } } @@ -786,10 +785,10 @@ const std::wstring * App::CreateFrameAnswer() } -void App::CreateJSONAnswer() +pt::WTextStream * App::CreateJSONAnswer() { Request & req = *cur.request; - json_out_stream.Clear(); + json_out_stream.clear(); if( !req.return_info_only ) { @@ -806,9 +805,9 @@ void App::CreateJSONAnswer() } json_out_stream << L"\""; - JSONescape(json_out_stream, i->first); + JSONescape(i->first, json_out_stream); json_out_stream << L"\": \""; - JSONescape(json_out_stream, i->second->Str()); + JSONescapeStream(i->second->get_buffer(), json_out_stream); json_out_stream << L"\""; is_first = false; } @@ -825,6 +824,8 @@ void App::CreateJSONAnswer() log << " (Request::info only)"; log << logend; + + return &json_out_stream; } @@ -1736,9 +1737,16 @@ void App::FilterContent() if( filter_main_stream ) { - // !! IMPROVE ME may some kind of html_filtered.reserve() here? (optimization) - TemplatesFunctions::html_filter.Filter(req.out_main_stream.Str(), html_filtered); - req.out_main_stream.Str(std::move(html_filtered)); // !! IMPROVE ME we do not have Str(&&) method + std::wstring tmp_out_main_stream; + req.out_main_stream.to_str(tmp_out_main_stream, false); + TemplatesFunctions::html_filter.Filter(tmp_out_main_stream, html_filtered); // IMPROVEME let Filter take pt::WTextStream + + /* + * it would be better to just return a pointer from this method + * + */ + req.out_main_stream.clear(); + req.out_main_stream.PutText(html_filtered); log << log3 << "App: html in the main stream has been filtered" << logend; } @@ -1747,9 +1755,14 @@ void App::FilterContent() for(auto i = req.out_streams.streams_map.begin() ; i != req.out_streams.streams_map.end() ; ++i) { HtmlTextStream & stream = *i->second; - // !! IMPROVE ME may some kind of html_filtered.reserve() here? (optimization) - TemplatesFunctions::html_filter.Filter(stream.Str(), html_filtered); - stream.Str(std::move(html_filtered)); + + std::wstring tmp_stream; + stream.to_str(tmp_stream, false); + + TemplatesFunctions::html_filter.Filter(tmp_stream, html_filtered); + + stream.clear(); + stream.PutText(html_filtered); } log << log3 << "App: html in json out streams have been filtered" << logend; @@ -1878,22 +1891,25 @@ return header; void App::SendTextAnswer() { -const std::wstring * source = nullptr; +const pt::WTextStream * source = nullptr; bool compressing = false; int compress_encoding = 0; size_t output_size = 0; - Header header = GetHTTPStatusCode(); if( CanSendContent() ) { + /* + * FIXME frames are not filtered (when is_htmx_request is true) + * + * FilterContent() should be combined with CreateJSONAnswer() and CreateFrameAnswer() somehow + */ FilterContent(); if( cur.request->return_json ) { - CreateJSONAnswer(); - source = &json_out_stream.Str(); // json_out_stream was prepared by CreateJSONAnswer() + source = CreateJSONAnswer(); } else if( cur.request->is_htmx_request ) @@ -1908,12 +1924,12 @@ size_t output_size = 0; } else { - source = &cur.request->out_main_stream.Str(); + source = &cur.request->out_main_stream.get_buffer(); } - SelectCompression(source->length(), compressing, compress_encoding); + SelectCompression(source->size(), compressing, compress_encoding); - pt::wide_to_utf8(*source, output_8bit); + pt::wide_stream_to_utf8(*source, output_8bit); // !! IMPROVE ME add to log the binary stream as well if( config.log_server_answer ) diff --git a/winixd/core/app.h b/winixd/core/app.h index 6ff4bcb..5a23e03 100644 --- a/winixd/core/app.h +++ b/winixd/core/app.h @@ -147,7 +147,7 @@ private: pthread_t signal_thread; std::string socket_to_send_on_exit; std::string send_data_buf; - TextStream json_out_stream; + pt::WTextStream json_out_stream; std::string aheader_name, aheader_value; std::wstring html_filtered; std::string output_8bit; @@ -156,7 +156,7 @@ private: std::wstring http_header_name; std::wstring http_header_value; std::string http_header_8bit; - std::wstring empty_response; + pt::WTextStream empty_response; WinixModelConnector model_connector; // main thread model connector, each thread has its own connector morm::JSONConnector json_connector; @@ -200,8 +200,8 @@ private: void SaveSessionsIfNeeded(); // !! IMPROVE ME wywalic do menagera sesji?? void LogAccess(); void SendData(const BinaryPage & page, FCGX_Stream * out); - const std::wstring * CreateFrameAnswer(); - void CreateJSONAnswer(); + pt::WTextStream * CreateFrameAnswer(); + pt::WTextStream * CreateJSONAnswer(); void ReadRequest(); void SendTextAnswer(); diff --git a/winixd/core/misc.cpp b/winixd/core/misc.cpp index 32d709e..4a92dd0 100644 --- a/winixd/core/misc.cpp +++ b/winixd/core/misc.cpp @@ -1450,6 +1450,17 @@ void RemovePostFileTmp(PostFileTab & post_file_tab) } +void JSONescapeStream(const pt::WTextStream & in, pt::WTextStream & out) +{ + pt::WTextStream::const_iterator i = in.begin(); + + for( ; i != in.end() ; ++i) + { + JSONescape(*i, out); + } +} + + bool wide_to_utf8(const wchar_t * wide_string, char * utf8, size_t utf8_size) { bool res = pt::wide_to_utf8(wide_string, utf8, utf8_size); diff --git a/winixd/core/misc.h b/winixd/core/misc.h index 04bb5db..a287d8f 100644 --- a/winixd/core/misc.h +++ b/winixd/core/misc.h @@ -946,20 +946,11 @@ void SetMinMax(IntType & val, IntType min_val, IntType max_val) } - - - -template -void JSONescape(Stream & out, const StringType & str) +template +void JSONescape(wchar_t c, Stream & out) { - // !! IMPROVE ME (optimizing) - // it is better to not write one by one character - // but use write method insted - - for(size_t i=0 ; i +void JSONescape(const StringType & str, Stream & out) +{ + for(size_t i=0 ; i < str.size() ; ++i) + { + if constexpr(sizeof(char) == sizeof(typename StringType::value_type)) + { + JSONescape(static_cast(static_cast(str[i])), out); + } + else + { + JSONescape(str[i], out); } } } +void JSONescapeStream(const pt::WTextStream & in, pt::WTextStream & out); + + /* * converting from a wide string to an UTF-8 string diff --git a/winixd/core/request.cpp b/winixd/core/request.cpp index b035930..2ecbd65 100644 --- a/winixd/core/request.cpp +++ b/winixd/core/request.cpp @@ -75,7 +75,7 @@ void Request::ClearOutputStreams() { size_t len = 0; - out_main_stream.Clear(); + out_main_stream.clear(); if( config ) len = config->ezc_out_streams_size; diff --git a/winixd/functions/rm.cpp b/winixd/functions/rm.cpp index 188e2df..e1ba711 100644 --- a/winixd/functions/rm.cpp +++ b/winixd/functions/rm.cpp @@ -526,7 +526,7 @@ void Rm::CreateJSON(bool status) using TemplatesFunctions::R; pt::WTextStream buf; - JSONescape(buf, cur->request->item.url); + JSONescape(cur->request->item.url, buf); auto & out = cur->request->out_main_stream; out << R("{\"files\": [{\"") << R(buf) << R("\": "); diff --git a/winixd/models/item.cpp b/winixd/models/item.cpp index 87dc4ce..70eb6ca 100644 --- a/winixd/models/item.cpp +++ b/winixd/models/item.cpp @@ -633,7 +633,7 @@ void Item::execute(EzcEnv & env) else ezc_generator.Generate(item_run_content); - ItemContent::print_content(env.out, item_run_content.Str(), item_content.content_raw_type, config->html_filter); + ItemContent::print_content(env.out, item_run_content.get_buffer(), item_content.content_raw_type, config->html_filter); } } else diff --git a/winixd/models/itemcontent.cpp b/winixd/models/itemcontent.cpp index ea08da3..354d168 100644 --- a/winixd/models/itemcontent.cpp +++ b/winixd/models/itemcontent.cpp @@ -389,6 +389,48 @@ bool ItemContent::CanContentBeHtmlFiltered() +void ItemContent::print_content(HtmlTextStream & out, const pt::WTextStream & content, ItemContent::ContentType content_type, bool is_html_filter_on) +{ + using TemplatesFunctions::R; + + if( is_html_filter_on && !ItemContent::CanContentBeHtmlFiltered(content_type) ) + out << R(""); + + if( content_type == ItemContent::ct_text ) + { + out << content; + } + else + if( content_type == ItemContent::ct_formatted_text ) + { + std::wstring tmp_string; + content.to_str(tmp_string); + TemplatesFunctions::HtmlEscapeFormTxt(out, tmp_string); + } + else + if( content_type == ItemContent::ct_bbcode ) + { + static std::wstring out_temp; + out_temp.clear(); + out_temp.reserve(content.size()*2); + + BBCODEParser bbcode_parser; // IMPROVE ME move me to a better place + std::wstring tmp_string; + content.to_str(tmp_string); + bbcode_parser.Filter(tmp_string.c_str(), out_temp); + out << R(out_temp); + } + else + { + // ct_html, ct_other + out.get_buffer().operator<<(content); // tricky way of putting content without escaping + } + + if( is_html_filter_on && !ItemContent::CanContentBeHtmlFiltered(content_type) ) + out << R(""); +} + + void ItemContent::print_content(HtmlTextStream & out, const std::wstring & content, ItemContent::ContentType content_type, bool is_html_filter_on) { diff --git a/winixd/models/itemcontent.h b/winixd/models/itemcontent.h index e52fa60..39656b9 100644 --- a/winixd/models/itemcontent.h +++ b/winixd/models/itemcontent.h @@ -254,6 +254,7 @@ public: bool do_migration(int & current_table_version); static bool CanContentBeHtmlFiltered(ItemContent::ContentType ct); + static void print_content(HtmlTextStream & out, const pt::WTextStream & content, ItemContent::ContentType content_type, bool is_html_filter_on); static void print_content(HtmlTextStream & out, const std::wstring & content, ItemContent::ContentType content_type, bool is_html_filter_on); bool CanContentBeHtmlFiltered(); diff --git a/winixd/plugins/thread/templates.cpp b/winixd/plugins/thread/templates.cpp index 3e597ae..95a1a3a 100644 --- a/winixd/plugins/thread/templates.cpp +++ b/winixd/plugins/thread/templates.cpp @@ -353,12 +353,12 @@ void thread_sort_tab_run(Info & i) { Ezc::Pattern * p = pattern_cacher.GetPattern(*thread_info.item_sort_tab[item_sort_index]); - item_run_content.Clear(); + item_run_content.clear(); InitGenerator(ezc_generator, cur->request->models); ezc_generator.SetPattern(*p); ezc_generator.Generate(item_run_content); - ItemContent::print_content(i.out, item_run_content.Str(), thread_info.item_sort_tab[item_sort_index]->item_content.content_raw_type, config->html_filter); + ItemContent::print_content(i.out, item_run_content.get_buffer(), thread_info.item_sort_tab[item_sort_index]->item_content.content_raw_type, config->html_filter); } else { diff --git a/winixd/templates/filters.cpp b/winixd/templates/filters.cpp index c0268ad..f951237 100644 --- a/winixd/templates/filters.cpp +++ b/winixd/templates/filters.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2008-2014, Tomasz Sowa + * Copyright (c) 2008-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,38 +41,37 @@ namespace Winix namespace TemplatesFunctions { -// not thread safe -static std::string qencode_tmp; void fil_urlencode(Info & i) { - UrlEncode(i.in.Str(), i.out); + UrlEncode(i.in.get_buffer(), i.out.get_buffer(), false); } void fil_qencode(Info & i) { - QEncode(i.in.Str(), qencode_tmp); + std::wstring tmp_str; + std::string qencode_tmp; + + i.in.to_str(tmp_str); + QEncode(tmp_str, qencode_tmp); + i.out << R(qencode_tmp); } void fil_capitalize(Info & i) { - const std::wstring & str = i.in.Str(); - - for(size_t a=0 ; a\n"); else - i.out << R(str[a]); + i.out << R(c); } } @@ -184,17 +187,17 @@ void fil_new_line_to_br(Info & i) */ void fil_html_quote(Info & i) { - const std::wstring & str = i.in.Str(); - - for(size_t a=0 ; a::Clear(); + return false; } +bool HtmlTextStream::is_wchar_stream() const +{ + return true; +} + + + void HtmlTextStream::clear() { - Clear(); + escape = true; + buffer.clear(); } -void HtmlTextStream::to_str(std::wstring & str) +bool HtmlTextStream::empty() const { - str = TextStream::Str(); + return buffer.empty(); } +size_t HtmlTextStream::size() const +{ + return buffer.size(); +} + + +void HtmlTextStream::reserve(size_t len) +{ + buffer.reserve(len); +} + + +size_t HtmlTextStream::capacity() const +{ + return buffer.capacity(); +} + + +HtmlTextStream::iterator HtmlTextStream::begin() +{ + return buffer.begin(); +} + + +HtmlTextStream::iterator HtmlTextStream::end() +{ + return buffer.end(); +} + + +HtmlTextStream::const_iterator HtmlTextStream::begin() const +{ + return buffer.begin(); +} + + +HtmlTextStream::const_iterator HtmlTextStream::end() const +{ + return buffer.end(); +} + + + + +void HtmlTextStream::to_str(std::string & str, bool clear_string) const +{ + buffer.to_str(str, clear_string); +} + + +void HtmlTextStream::to_str(std::wstring & str, bool clear_string) const +{ + buffer.to_str(str, clear_string); +} + + +std::string HtmlTextStream::to_str() const +{ + return buffer.to_str(); +} + + +std::wstring HtmlTextStream::to_wstr() const +{ + return buffer.to_wstr(); +} + + +char HtmlTextStream::get_char(size_t index) const +{ + return buffer.get_char(index); +} + +wchar_t HtmlTextStream::get_wchar(size_t index) const +{ + return buffer.get_wchar(index); +} + + +const pt::WTextStream & HtmlTextStream::get_buffer() const +{ + return buffer; +} + + +pt::WTextStream & HtmlTextStream::get_buffer() +{ + return buffer; +} + + + /* without escaping */ -HtmlTextStream & HtmlTextStream::PutChar(char c) -{ - TextStream::operator<<(c); - -return *this; -} - - -HtmlTextStream & HtmlTextStream::PutChar(wchar_t c) -{ - TextStream::operator<<(c); - -return *this; -} - - HtmlTextStream & HtmlTextStream::PutText(const char * str) { - TextStream::operator<<(str); - -return *this; -} - - -HtmlTextStream & HtmlTextStream::PutText(const char * str, size_t len) -{ - TextStream::Write(str, len); - -return *this; -} - - -HtmlTextStream & HtmlTextStream::PutText(const std::string * str) -{ - TextStream::operator<<(str); + buffer.operator<<(str); return *this; } @@ -113,7 +180,7 @@ return *this; HtmlTextStream & HtmlTextStream::PutText(const std::string & str) { - TextStream::operator<<(str); + buffer.operator<<(str); return *this; } @@ -122,15 +189,7 @@ return *this; HtmlTextStream & HtmlTextStream::PutText(const wchar_t * str) { - TextStream::operator<<(str); - -return *this; -} - - -HtmlTextStream & HtmlTextStream::PutText(const std::wstring * str) -{ - TextStream::operator<<(str); + buffer.operator<<(str); return *this; } @@ -138,12 +197,64 @@ return *this; HtmlTextStream & HtmlTextStream::PutText(const std::wstring & str) { - TextStream::operator<<(str); + buffer.operator<<(str); return *this; } +HtmlTextStream & HtmlTextStream::PutText(const char * str, size_t len) +{ + buffer.write(str, len); + +return *this; +} + + +HtmlTextStream & HtmlTextStream::PutText(const wchar_t * str, size_t len) +{ + buffer.write(str, len); + +return *this; +} + + + + +HtmlTextStream & HtmlTextStream::PutChar(char c) +{ + buffer.operator<<(c); + +return *this; +} + + +HtmlTextStream & HtmlTextStream::PutChar(unsigned char c) +{ + buffer.operator<<(c); + +return *this; +} + + +HtmlTextStream & HtmlTextStream::PutChar(wchar_t c) +{ + buffer.operator<<(c); + +return *this; +} + + +HtmlTextStream & HtmlTextStream::PutChar(bool val) +{ + buffer.operator<<(val); + +return *this; +} + + + + @@ -155,33 +266,18 @@ HtmlTextStream & HtmlTextStream::operator<<(const RawText & raw) } -HtmlTextStream & HtmlTextStream::operator<<(const RawText & raw) -{ - return PutText(raw.par); -} - - - -HtmlTextStream & HtmlTextStream::operator<<(RawText raw) -{ - return PutText(raw.par); -} - - -HtmlTextStream & HtmlTextStream::operator<<(RawText raw) -{ - return PutText(raw.par); -} - - - - HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { return PutText(raw.par); } +HtmlTextStream & HtmlTextStream::operator<<(const RawText & raw) +{ + return PutText(raw.par); +} + + HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { return PutText(raw.par); @@ -189,107 +285,158 @@ HtmlTextStream & HtmlTextStream::operator<<(RawText raw) - HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { - TextStream::operator<<(raw.par); + buffer.operator<<(raw.par); + return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(RawText raw) +{ + buffer.operator<<(raw.par); return *this; } HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { - TextStream::operator<<(raw.par); + buffer.operator<<(raw.par); + return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(RawText raw) +{ + buffer.operator<<(raw.par); + return *this; +} + + + +HtmlTextStream & HtmlTextStream::operator<<(RawText raw) +{ + buffer.operator<<(raw.par); return *this; } HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { - TextStream::operator<<(raw.par); + buffer.operator<<(raw.par); return *this; } HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { - TextStream::operator<<(raw.par); + buffer.operator<<(raw.par); + return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(RawText raw) +{ + buffer.operator<<(raw.par); + return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(RawText raw) +{ + buffer.operator<<(raw.par); return *this; } HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { - TextStream::operator<<(raw.par); + buffer.operator<<(raw.par); return *this; } HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { - TextStream::operator<<(raw.par); + buffer.operator<<(raw.par); + return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(RawText raw) +{ + buffer.operator<<(raw.par); + return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(RawText raw) +{ + buffer.operator<<(raw.par); return *this; } HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { - TextStream::operator<<(raw.par); + buffer.operator<<(raw.par); + return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(RawText raw) +{ + buffer.operator<<(raw.par); return *this; } HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { - TextStream::operator<<(raw.par); + buffer.operator<<(raw.par); + return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(RawText raw) +{ + buffer.operator<<(raw.par); return *this; } HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { - TextStream::operator<<(raw.par); + buffer.operator<<(raw.par); return *this; } HtmlTextStream & HtmlTextStream::operator<<(RawText raw) { - TextStream::operator<<(raw.par); + buffer.operator<<(raw.par); return *this; } HtmlTextStream & HtmlTextStream::operator<<(const HtmlTextStream & stream) { - TextStream::operator<<(stream.Str()); + buffer.operator<<(stream.buffer); return *this; } -HtmlTextStream & HtmlTextStream::Write(const char * buf, size_t len) -{ - TextStream::Write(buf, len); - return *this; -} - -HtmlTextStream & HtmlTextStream::Write(const wchar_t * buf, size_t len) -{ - TextStream::Write(buf, len); - return *this; -} - - HtmlTextStream & HtmlTextStream::write(const char * buf, size_t len) { - TextStream::write(buf, len); + buffer.write(buf, len); return *this; } + HtmlTextStream & HtmlTextStream::write(const wchar_t * buf, size_t len) { - TextStream::write(buf, len); + buffer.write(buf, len); return *this; } @@ -300,94 +447,29 @@ HtmlTextStream & HtmlTextStream::write(const wchar_t * buf, size_t len) /* with escaping */ - - -void HtmlTextStream::Escape(bool escape_characters) -{ - escape = escape_characters; -} - - - -HtmlTextStream & HtmlTextStream::ETextPutChar(char c) -{ - return ETextPutChar(static_cast(c)); -} - - -HtmlTextStream & HtmlTextStream::ETextPutChar(wchar_t c) -{ - if( c == '<' ) - buffer += L"<"; - else - if( c == '>' ) - buffer += L">"; - else - if( c == '&' ) - buffer += L"&"; - else - if( c == '\"' ) - buffer += L"""; - else - if( c == '\'' ) - buffer += L"'"; // (it is "'" but IE8 has a problem with ') - else - if( c == 10 ) - buffer += L" "; - else - if( c == 13 ) - buffer += L" "; - else - if( c != 0 ) // !! CHECK ME may it should be changed to something like '�'; - buffer += c; - -return *this; -} - - HtmlTextStream & HtmlTextStream::EPutText(const char * str) { - pt::utf8_to_wide(str, tmp_string); + int res; + bool correct; + size_t utf8_len; - for(size_t i=0 ; i 0 ) + { + if( !correct ) + res = 0xFFFD; // U+FFFD "replacement character" - tmp_string.clear(); + ETextPutChar(static_cast(res)); + str += utf8_len; + } return *this; } - -HtmlTextStream & HtmlTextStream::EPutText(const char * str, size_t len) -{ - pt::utf8_to_wide(str, len, tmp_string); - - for(size_t i=0 ; i 0 ) + { + if( !correct ) + res = 0xFFFD; // U+FFFD "replacement character" + + ETextPutChar(static_cast(res)); + + len -= utf8_len; + str += utf8_len; + } + +return *this; +} + + HtmlTextStream & HtmlTextStream::EPutText(const wchar_t * str, size_t len) { for(size_t i=0 ; ic_str(), str->size()); + return ETextPutChar(static_cast(c)); } -HtmlTextStream & HtmlTextStream::EPutText(const std::wstring & str) +HtmlTextStream & HtmlTextStream::ETextPutChar(unsigned char c) { - return EPutText(str.c_str(), str.size()); + return ETextPutChar(static_cast(c)); } - - -HtmlTextStream & HtmlTextStream::operator<<(const char * str) +HtmlTextStream & HtmlTextStream::ETextPutChar(wchar_t c) { - if( escape ) - EPutText(str); + if( c == '<' ) + buffer << L"<"; else - PutText(str); + if( c == '>' ) + buffer << L">"; + else + if( c == '&' ) + buffer << L"&"; + else + if( c == '\"' ) + buffer << L"""; + else + if( c == '\'' ) + buffer << L"'"; // (it is "'" but IE8 has a problem with ') (' is valid in HTML5, but not HTML4) + else + if( c == 10 ) + buffer << L" "; + else + if( c == 13 ) + buffer << L" "; + else + if( c == 0 ) + buffer << L"�"; + else + buffer << c; return *this; } -HtmlTextStream & HtmlTextStream::operator<<(const std::string * str) + + +void HtmlTextStream::Escape(bool escape_characters) +{ + escape = escape_characters; +} + + + +HtmlTextStream & HtmlTextStream::operator<<(const char * str) { if( escape ) EPutText(str); @@ -456,8 +595,6 @@ return *this; } - - HtmlTextStream & HtmlTextStream::operator<<(const wchar_t * str) { if( escape ) @@ -469,17 +606,6 @@ return *this; } -HtmlTextStream & HtmlTextStream::operator<<(const std::wstring * str) -{ - if( escape ) - EPutText(str); - else - PutText(str); - -return *this; -} - - HtmlTextStream & HtmlTextStream::operator<<(const std::wstring & str) { if( escape ) @@ -491,8 +617,6 @@ return *this; } - - HtmlTextStream & HtmlTextStream::operator<<(char v) { if( escape ) @@ -504,6 +628,17 @@ return *this; } +HtmlTextStream & HtmlTextStream::operator<<(unsigned char v) +{ + if( escape ) + ETextPutChar(v); + else + PutChar(v); + +return *this; +} + + HtmlTextStream & HtmlTextStream::operator<<(wchar_t v) { if( escape ) @@ -515,14 +650,31 @@ return *this; } -HtmlTextStream & HtmlTextStream::operator<<(int v) +HtmlTextStream & HtmlTextStream::operator<<(bool v) { /* - * int, long and others don't have to be escaped - * (they consist of digits only: '0' - '9' and other characters which - * don't have to be escaped) + * bool, short, int, long, long long, float, double and long double don't have to be escaped + * they consist of digits only: '0' - '9' (and with an exponent in the case of float/double/long double) + * and don't have to be escaped + * */ - TextStream::operator<<(v); + buffer.operator<<(v); + +return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(short v) +{ + buffer.operator<<(v); + +return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(int v) +{ + buffer.operator<<(v); return *this; } @@ -530,7 +682,23 @@ return *this; HtmlTextStream & HtmlTextStream::operator<<(long v) { - TextStream::operator<<(v); + buffer.operator<<(v); + +return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(long long v) +{ + buffer.operator<<(v); + +return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(unsigned short v) +{ + buffer.operator<<(v); return *this; } @@ -538,7 +706,7 @@ return *this; HtmlTextStream & HtmlTextStream::operator<<(unsigned int v) { - TextStream::operator<<(v); + buffer.operator<<(v); return *this; } @@ -546,7 +714,23 @@ return *this; HtmlTextStream & HtmlTextStream::operator<<(unsigned long v) { - TextStream::operator<<(v); + buffer.operator<<(v); + +return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(unsigned long long v) +{ + buffer.operator<<(v); + +return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(float v) +{ + buffer.operator<<(v); return *this; } @@ -554,7 +738,15 @@ return *this; HtmlTextStream & HtmlTextStream::operator<<(double v) { - TextStream::operator<<(v); + buffer.operator<<(v); + +return *this; +} + + +HtmlTextStream & HtmlTextStream::operator<<(long double v) +{ + buffer.operator<<(v); return *this; } @@ -562,7 +754,46 @@ return *this; HtmlTextStream & HtmlTextStream::operator<<(const void * v) { - TextStream::operator<<(v); + buffer.operator<<(v); + +return *this; +} + + + +HtmlTextStream & HtmlTextStream::operator<<(const Stream & stream) +{ + if( escape ) + { + if(stream.is_char_stream()) + { + int res; + bool correct; + size_t len; + size_t index = 0; + size_t stream_len = stream.size(); + + // CHECKME + while( index < stream_len && (len = pt::utf8_to_int(stream, index, res, correct)) > 0 ) + { + if( !correct ) + res = 0xFFFD; // U+FFFD "replacement character" + + ETextPutChar(static_cast(res)); + index += len; + } + } + else + if(stream.is_wchar_stream()) + { + for(size_t i=0 ; i < stream.size() ; ++i) + ETextPutChar(stream.get_wchar(i)); + } + } + else + { + buffer.operator<<(stream); + } return *this; } @@ -573,20 +804,20 @@ HtmlTextStream & HtmlTextStream::operator<<(const pt::Space & space) { if( escape ) { - space.serialize_to_space_stream(*this, true); + space.serialize_to_json_stream(*this, true); - /* - tmp_stream.Clear(); - // !! IMPROVE ME - // we can calculate how many memory is needed beforehand - space.Serialize(tmp_stream, true, false); - operator<<(tmp_stream.Str()); - tmp_stream.Clear(); - */ + pt::WTextStream tmp_stream; + space.serialize_to_json_stream(tmp_stream, true); + + pt::WTextStream::iterator i = tmp_stream.begin(); + + for( ; i != tmp_stream.end() ; ++i) + ETextPutChar(*i); } else { - TextStream::operator<<(space); + // FIXME this will serialize to Space format !!!! + buffer.operator<<(space); } return *this; @@ -595,28 +826,24 @@ return *this; HtmlTextStream & HtmlTextStream::operator<<(const pt::Date & date) { - if( escape ) - { - date.Serialize(*this); - - /* - tmp_stream.Clear(); - // !! IMPROVE ME - // we can calculate how many memory is needed beforehand - date.Serialize(tmp_stream); - operator<<(tmp_stream.Str()); - tmp_stream.Clear(); - */ - } - else - { - TextStream::operator<<(date); - } + // dates don't need to be escaped + buffer.operator<<(date); return *this; } +HtmlTextStream & HtmlTextStream::operator<<(morm::Model & model) +{ + // CHECKME + pt::TextStream tmp_stream; + model.to_text(tmp_stream); + + return operator<<(tmp_stream); +} + + + } // namespace Winix diff --git a/winixd/templates/htmltextstream.h b/winixd/templates/htmltextstream.h index 147c241..3f3757a 100644 --- a/winixd/templates/htmltextstream.h +++ b/winixd/templates/htmltextstream.h @@ -36,7 +36,9 @@ #define headerfile_winix_templates_htmltextstream #include -#include "core/textstream.h" +#include "textstream/textstream.h" +#include "morm.h" + namespace Winix { @@ -69,25 +71,54 @@ namespace Winix > -> > & ->   " -> " - ' -> ' (it is "'" but IE8 has a problem with ') + ' -> ' (it is "'" but IE8 has a problem with ') (' is valid in HTML5, but not HTML4) 10 -> 13 -> + 0 -> � */ -class HtmlTextStream : public TextStream +class HtmlTextStream : public pt::Stream { public: + typedef wchar_t char_type; + typedef pt::WTextStream::buffer_type buffer_type; + typedef typename buffer_type::iterator iterator; + typedef typename buffer_type::const_iterator const_iterator; + HtmlTextStream(); + bool is_char_stream() const; + bool is_wchar_stream() const; + /* * clearing the buffer and setting 'escape' flag to true */ - void Clear(); - void clear(); // utf8 methods call clear(), in the future Clear() will be renamed to clear() + void clear(); + bool empty() const; + size_t size() const; + void reserve(size_t len); + size_t capacity() const; + + iterator begin(); + iterator end(); + + const_iterator begin() const; + const_iterator end() const; + + void to_str(std::string & str, bool clear_string = true) const; + void to_str(std::wstring & str, bool clear_string = true) const; + + std::string to_str() const; + std::wstring to_wstr() const; + + char get_char(size_t index) const; + wchar_t get_wchar(size_t index) const; + + const pt::WTextStream & get_buffer() const; + pt::WTextStream & get_buffer(); - void to_str(std::wstring & str); /* a helper struct to select a proper operator<< @@ -107,18 +138,20 @@ public: /* without escaping */ - HtmlTextStream & PutChar(char); - HtmlTextStream & PutChar(wchar_t); - - HtmlTextStream & PutText(const char *); - HtmlTextStream & PutText(const char *, size_t len); - HtmlTextStream & PutText(const std::string *); - HtmlTextStream & PutText(const std::string &); + HtmlTextStream & PutText(const char * str); + HtmlTextStream & PutText(const std::string & str); HtmlTextStream & PutText(const wchar_t * str); - HtmlTextStream & PutText(const wchar_t * str, size_t len); - HtmlTextStream & PutText(const std::wstring * str); HtmlTextStream & PutText(const std::wstring & str); + HtmlTextStream & PutText(const char *, size_t len); + HtmlTextStream & PutText(const wchar_t * str, size_t len); + + HtmlTextStream & PutChar(char c); + HtmlTextStream & PutChar(unsigned char c); + HtmlTextStream & PutChar(wchar_t c); + HtmlTextStream & PutChar(bool val); + + /* we need this template operator for such calling: HtmlTextStream_object << R("some string"); @@ -131,56 +164,64 @@ public: HtmlTextStream & operator<<(const RawText & raw) { return PutText(raw.par); } HtmlTextStream & operator<<(const RawText & raw); - HtmlTextStream & operator<<(const RawText & raw); - HtmlTextStream & operator<<(RawText raw); - HtmlTextStream & operator<<(RawText raw); HtmlTextStream & operator<<(RawText raw); + + HtmlTextStream & operator<<(const RawText & raw); HtmlTextStream & operator<<(RawText raw); HtmlTextStream & operator<<(RawText raw); + HtmlTextStream & operator<<(RawText raw); HtmlTextStream & operator<<(RawText raw); + HtmlTextStream & operator<<(RawText raw); + + HtmlTextStream & operator<<(RawText raw); HtmlTextStream & operator<<(RawText raw); HtmlTextStream & operator<<(RawText raw); + HtmlTextStream & operator<<(RawText raw); + + HtmlTextStream & operator<<(RawText raw); HtmlTextStream & operator<<(RawText raw); HtmlTextStream & operator<<(RawText raw); + HtmlTextStream & operator<<(RawText raw); + + HtmlTextStream & operator<<(RawText raw); HtmlTextStream & operator<<(RawText raw); + HtmlTextStream & operator<<(RawText raw); HtmlTextStream & operator<<(RawText raw); + + HtmlTextStream & operator<<(RawText raw); HtmlTextStream & operator<<(RawText raw); HtmlTextStream & operator<<(RawText raw); template HtmlTextStream & operator<<(RawText > raw); - // this method doesn't escape stream as there is no need for such behavior - stream should be already escaped HtmlTextStream & operator<<(const HtmlTextStream & stream); - // 'write' don't escapes too // with these methods you can write a zero character too - HtmlTextStream & Write(const char * buf, size_t len); - HtmlTextStream & Write(const wchar_t * buf, size_t len); - // for compatibility with standard library (Ezc uses it) HtmlTextStream & write(const char * buf, size_t len); HtmlTextStream & write(const wchar_t * buf, size_t len); + /* with escaping */ - - HtmlTextStream & ETextPutChar(char c); - HtmlTextStream & ETextPutChar(wchar_t c); - HtmlTextStream & EPutText(const char * str); - HtmlTextStream & EPutText(const char * str, size_t len); - HtmlTextStream & EPutText(const std::string * str); HtmlTextStream & EPutText(const std::string & str); HtmlTextStream & EPutText(const wchar_t * str); - HtmlTextStream & EPutText(const wchar_t * str, size_t len); - HtmlTextStream & EPutText(const std::wstring * str); HtmlTextStream & EPutText(const std::wstring & str); + HtmlTextStream & EPutText(const char * str, size_t len); + HtmlTextStream & EPutText(const wchar_t * str, size_t len); + + HtmlTextStream & ETextPutChar(char c); + HtmlTextStream & ETextPutChar(unsigned char c); + HtmlTextStream & ETextPutChar(wchar_t c); + + /* * by default all operator<< shown below use escaping * but you can turn it off by calling Escape(false) @@ -188,30 +229,40 @@ public: void Escape(bool escape_characters); HtmlTextStream & operator<<(const char * str); - HtmlTextStream & operator<<(const std::string * str); HtmlTextStream & operator<<(const std::string & str); HtmlTextStream & operator<<(const wchar_t * str); - HtmlTextStream & operator<<(const std::wstring * str); HtmlTextStream & operator<<(const std::wstring & str); HtmlTextStream & operator<<(char); + HtmlTextStream & operator<<(unsigned char); HtmlTextStream & operator<<(wchar_t); + HtmlTextStream & operator<<(bool); + HtmlTextStream & operator<<(short); HtmlTextStream & operator<<(int); HtmlTextStream & operator<<(long); + HtmlTextStream & operator<<(long long); + HtmlTextStream & operator<<(unsigned short); HtmlTextStream & operator<<(unsigned int); HtmlTextStream & operator<<(unsigned long); + HtmlTextStream & operator<<(unsigned long long); + HtmlTextStream & operator<<(float); HtmlTextStream & operator<<(double); + HtmlTextStream & operator<<(long double); HtmlTextStream & operator<<(const void *); + + HtmlTextStream & operator<<(const Stream & stream); HtmlTextStream & operator<<(const pt::Space & space); HtmlTextStream & operator<<(const pt::Date & Date); + HtmlTextStream & operator<<(morm::Model & model); + template HtmlTextStream & operator<<(const pt::TextStreamBase & arg); private: - //TextStream tmp_stream; - std::wstring tmp_string; + pt::WTextStream buffer; + //std::wstring tmp_string; bool escape; }; @@ -221,12 +272,17 @@ private: template HtmlTextStream & HtmlTextStream::operator<<(RawText > raw) { - TextStream::operator<<(raw.par); + buffer.operator<<(raw.par); return *this; } +/* + * this method is the same as HtmlTextStream & HtmlTextStream::operator<<(const Stream & stream) + * but in the future we can use iterators here + * + */ template HtmlTextStream & HtmlTextStream::operator<<(const pt::TextStreamBase & arg) { @@ -234,15 +290,38 @@ typename pt::TextStreamBase: if( escape ) { - /* - * warning: char* (utf-8) string will not be correctly handled here - */ - for(i=arg.begin() ; i != arg.end() ; ++i) - ETextPutChar(*i); + if(arg.is_char_stream()) + { + /* + * IMPROVEME it would be better to have a better api from pikotools + * instead of index we can provide an iterator + */ + int res; + bool correct; + size_t len; + size_t index = 0; + size_t stream_len = arg.size(); + + // CHECKME + while( index < stream_len && (len = pt::utf8_to_int(arg, index, res, correct)) > 0 ) + { + if( !correct ) + res = 0xFFFD; // U+FFFD "replacement character" + + ETextPutChar(static_cast(res)); + index += len; + } + } + else + if(arg.is_wchar_stream()) + { + for(i=arg.begin() ; i != arg.end() ; ++i) + ETextPutChar(*i); + } } else { - TextStream::operator<<(arg); + buffer.operator<<(arg); } return *this; diff --git a/winixd/templates/insert.cpp b/winixd/templates/insert.cpp index 9e047ca..68679a1 100644 --- a/winixd/templates/insert.cpp +++ b/winixd/templates/insert.cpp @@ -72,12 +72,12 @@ void insert_page_run(Info & i) log << log4 << "Templates: insert_page_run: using generator number: " << insert_page_cur << logend; insert_page_cur += 1; - info.run_content.Clear(); + info.run_content.clear(); InitGenerator(info.ezc_gen, cur->request->models); info.ezc_gen.SetPattern(*pat); info.ezc_gen.Generate(info.run_content); - ItemContent::print_content(i.out, info.run_content.Str(), info.item.item_content.content_raw_type, config->html_filter); + ItemContent::print_content(i.out, info.run_content.get_buffer(), info.item.item_content.content_raw_type, config->html_filter); insert_page_cur -= 1; }