LCOV - code coverage report
Current view: top level - ugbase/common/util - base64_file_writer.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 87.1 % 116 101
Test Date: 2025-09-21 23:31:46 Functions: 92.0 % 25 23

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2013-2014:  G-CSC, Goethe University Frankfurt
       3              :  * Author: Torbjoern Klatt, Martin Scherer
       4              :  * 
       5              :  * This file is part of UG4.
       6              :  * 
       7              :  * UG4 is free software: you can redistribute it and/or modify it under the
       8              :  * terms of the GNU Lesser General Public License version 3 (as published by the
       9              :  * Free Software Foundation) with the following additional attribution
      10              :  * requirements (according to LGPL/GPL v3 §7):
      11              :  * 
      12              :  * (1) The following notice must be displayed in the Appropriate Legal Notices
      13              :  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
      14              :  * 
      15              :  * (2) The following notice must be displayed at a prominent place in the
      16              :  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
      17              :  * 
      18              :  * (3) The following bibliography is recommended for citation and must be
      19              :  * preserved in all covered files:
      20              :  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
      21              :  *   parallel geometric multigrid solver on hierarchically distributed grids.
      22              :  *   Computing and visualization in science 16, 4 (2013), 151-164"
      23              :  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
      24              :  *   flexible software system for simulating pde based models on high performance
      25              :  *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
      26              :  * 
      27              :  * This program is distributed in the hope that it will be useful,
      28              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      29              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      30              :  * GNU Lesser General Public License for more details.
      31              :  */
      32              : 
      33              : #include "common/util/base64_file_writer.h"
      34              : 
      35              : // for base64 encoding with boost
      36              : #include <boost/archive/iterators/transform_width.hpp>
      37              : #include <boost/archive/iterators/base64_from_binary.hpp>
      38              : #include <boost/archive/iterators/ostream_iterator.hpp>
      39              : //#include <boost/filesystem.hpp>
      40              : 
      41              : // debug includes!!
      42              : #include "common/profiler/profiler.h"
      43              : #include "common/error.h"
      44              : #include "common/assert.h"
      45              : 
      46              : using namespace std;
      47              : 
      48              : /**
      49              :  * \brief This is the actual encoder using Boost iterators
      50              :  * note that final padding to triplet boundary has to be performed manually!
      51              :  * see: http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/dataflow.html
      52              :  */
      53              : typedef boost::archive::iterators::base64_from_binary<
      54              :                 // convert binary values to base64 characters
      55              :                         boost::archive::iterators::transform_width<
      56              :                 // retrieve 6 bit integers from a sequence of 8 bit bytes
      57              :                         const char *, 6, 8>
      58              :                 // compose all the above operations in to a new iterator
      59              :                 > base64_text;
      60              : 
      61              : namespace ug {
      62              : 
      63              : ////////////////////////////////////////////////////////////////////////////////
      64              : // PUBLIC FUNCTIONS
      65              : 
      66            0 : Base64FileWriter::fmtflag Base64FileWriter::format() const {
      67            0 :         return m_currFormat;
      68              : }
      69              : 
      70           95 : Base64FileWriter& Base64FileWriter::operator<<(const fmtflag format)
      71              : {
      72              :         PROFILE_FUNC();
      73              : 
      74              :         // forceful flushing of encoder's internal input buffer is necessary
      75              :         // if we are switching formats.
      76           95 :         if (format != m_currFormat && m_numBytesWritten > 0) {
      77            1 :                 flushInputBuffer(true);
      78              :         }
      79           95 :         m_currFormat = format;
      80           95 :         return *this;
      81              : }
      82              : 
      83           31 : Base64FileWriter& Base64FileWriter::operator<<(int value)
      84              : {
      85           31 :         dispatch(value);
      86           31 :         return *this;
      87              : }
      88              : 
      89          199 : Base64FileWriter& Base64FileWriter::operator<<(char value) {
      90          199 :         dispatch(value);
      91          199 :         return *this;
      92              : }
      93              : 
      94            8 : Base64FileWriter& Base64FileWriter::operator<<(const char* value)
      95              : {
      96            8 :         dispatch(value);
      97            8 :         return *this;
      98              : }
      99              : 
     100            6 : Base64FileWriter& Base64FileWriter::operator<<(const string& value)
     101              : {
     102            6 :         dispatch(value);
     103            6 :         return *this;
     104              : }
     105              : 
     106            6 : Base64FileWriter& Base64FileWriter::operator<<(float value)
     107              : {
     108            6 :         dispatch(value);
     109            6 :         return *this;
     110              : }
     111              : 
     112            7 : Base64FileWriter& Base64FileWriter::operator<<(double value)
     113              : {
     114            7 :         dispatch(value);
     115            7 :         return *this;
     116              : }
     117              : 
     118           12 : Base64FileWriter& Base64FileWriter::operator<<(long value)
     119              : {
     120           12 :         dispatch(value);
     121           12 :         return *this;
     122              : }
     123              : 
     124           12 : Base64FileWriter& Base64FileWriter::operator<<(size_t value)
     125              : {
     126           12 :         dispatch(value);
     127           12 :         return *this;
     128              : }
     129              : 
     130            0 : Base64FileWriter::Base64FileWriter() :
     131            0 :         m_currFormat(base64_ascii),
     132            0 :         m_inBuffer(ios_base::binary | ios_base::out | ios_base::in),
     133            0 :         m_lastInputByteSize(0),
     134            0 :         m_numBytesWritten(0)
     135            0 : {}
     136              : 
     137           98 : Base64FileWriter::Base64FileWriter(const char* filename,
     138           98 :                 const ios_base::openmode mode) :
     139           98 :         m_currFormat(base64_ascii),
     140           98 :         m_inBuffer(ios_base::binary | ios_base::out | ios_base::in),
     141           98 :         m_lastInputByteSize(0),
     142           98 :         m_numBytesWritten(0)
     143              : {
     144              :         PROFILE_FUNC();
     145              : 
     146           98 :         open(filename, mode);
     147           98 : }
     148              : 
     149           98 : Base64FileWriter::~Base64FileWriter()
     150              : {
     151           98 :         flushInputBuffer(true);
     152           98 :         m_fStream.close();
     153           98 : }
     154              : 
     155           98 : void Base64FileWriter::open(const char *filename,
     156              :                                                                 const ios_base::openmode mode)
     157              : {
     158              :         // TODO: Create non-existing subdirectories in a platform-independent way
     159              :         // like in the following code. (Problem: no header-only boost implementation!)
     160              :         /*
     161              :         if (mode & std::ios_base::out)
     162              :         {
     163              :                 boost::filesystem::path p(filename);
     164              :                 boost::filesystem::create_directories(p.parent_path());
     165              :         }
     166              :         */
     167              : 
     168           98 :         m_fStream.open(filename, mode);
     169           98 :         if (!m_fStream.is_open()) {
     170            0 :                 UG_THROW( "Could not open output file: " << filename);
     171           98 :         } else if (!m_fStream.good()) {
     172            0 :                 UG_THROW( "Can not write to output file: " << filename);
     173              :         }
     174           98 : }
     175              : 
     176              : ////////////////////////////////////////////////////////////////////////////////
     177              : // PRIVATE FUNCTIONS
     178              : 
     179              : // this function performs conversion to plain const char* and stores it in
     180              : // m_inBuffer, either raw for binary mode or as string conversion in base64_ascii.
     181              : template <typename T>
     182          281 : void Base64FileWriter::dispatch(const T& value)
     183              : {
     184              : //      PROFILE_FUNC(); // this profile node is too small
     185          281 :         assertFileOpen();
     186              : 
     187          281 :         switch ( m_currFormat ) {
     188          187 :                 case base64_ascii:
     189              :                         // create string representation of value and store it in buffer
     190          187 :                         m_inBuffer << value;
     191              :                         // written bytes is equivalent to current write pointer pos
     192          187 :                         m_numBytesWritten = m_inBuffer.tellp();
     193          187 :                         m_lastInputByteSize = sizeof(char);
     194              :                         // check if a buffer flush is needed
     195          187 :                         flushInputBuffer();
     196          187 :                         break;
     197           91 :                 case base64_binary: {
     198              :                         // write the value in binary mode to the input buffer
     199              :                         UG_ASSERT(m_inBuffer.good(), "can not write to buffer")
     200           91 :                         m_inBuffer.write(reinterpret_cast<const char*>(&value), sizeof(T));
     201              :                         UG_ASSERT(m_inBuffer.good(), "write failed")
     202              : 
     203           91 :                         m_numBytesWritten += sizeof(T);
     204           91 :                         m_lastInputByteSize = sizeof(T);
     205              :                         // check if a buffer flush is needed
     206           91 :                         flushInputBuffer();
     207           91 :                         break;
     208              :                 }
     209            3 :                 case normal:
     210              :                         // nothing to do here, almost
     211            3 :                         m_fStream << value;
     212            2 :                         break;
     213              :         }
     214          281 : }
     215              : 
     216          281 : inline void Base64FileWriter::assertFileOpen()
     217              : {
     218          281 :         if (m_fStream.bad() || !m_fStream.is_open()) {
     219            0 :                 UG_THROW( "File stream is not open." );
     220              :         }
     221          281 : }
     222              : 
     223          475 : void Base64FileWriter::flushInputBuffer(bool force)
     224              : {
     225              : //      PROFILE_FUNC(); // this profile node is too small
     226              : 
     227              :         size_t buff_len = 0;
     228              :         // amount of elements to flush at once
     229              :         const uint elements_to_flush = 12;
     230              :         // in case of normal format, no input size is known, so this evals to zero.
     231          475 :         const uint bytes_to_flush = 3 * m_lastInputByteSize * elements_to_flush;
     232              :         // in case of forced flush we have to add padding
     233              :         uint paddChars = 0;
     234              : 
     235              :         // if force, flush all bytes in input stream
     236          475 :         if (force) {
     237          197 :                 paddChars = (3 - m_numBytesWritten % 3) % 3;
     238              :                 buff_len = m_numBytesWritten;
     239          278 :         } else if (bytes_to_flush <= m_numBytesWritten) {
     240              :                 buff_len = bytes_to_flush;
     241              :         } else {
     242              :                 // buff_len == 0
     243              :                 return;
     244              :         }
     245              : 
     246              :         m_tmpBuff.clear();
     247              :         // enlarge the input stream by # paddChars because boost reads beyond buffer
     248          203 :         m_tmpBuff.resize(buff_len + paddChars, 0x0);
     249              : 
     250          203 :         if(!m_tmpBuff.empty()){
     251              :                 char* buff = &m_tmpBuff[0];
     252              : 
     253          103 :                 if (!m_inBuffer.good()) {
     254            0 :                         UG_THROW("input buffer not good before read");
     255              :                 }
     256              : 
     257              :                 // read the buffer
     258          103 :                 m_inBuffer.read(buff, buff_len);
     259              : 
     260          103 :                 if (!m_inBuffer.good()) {
     261            0 :                         UG_THROW("failed to read from input buffer");
     262              :                 }
     263              : 
     264              :                 // encode buff in base64
     265          103 :                 copy(base64_text(buff), base64_text(buff + buff_len),
     266          103 :                                 boost::archive::iterators::ostream_iterator<char>(m_fStream));
     267              :         }
     268              : 
     269          203 :         size_t rest_len = m_numBytesWritten - buff_len;
     270              : 
     271          203 :         if (rest_len > 0) {
     272              :                 m_tmpBuff.clear();
     273            3 :                 m_tmpBuff.resize(rest_len);
     274              :                 char* rest = &m_tmpBuff[0];
     275              :                 // read the rest
     276            3 :                 m_inBuffer.read(rest, rest_len);
     277            3 :                 if (!m_inBuffer.good()) {
     278            0 :                         UG_THROW("failed to read from input buffer");
     279              :                 }
     280              : 
     281              :                 // reset the internal string
     282            3 :                 m_inBuffer.str("");
     283              :                 // set write pos to beginning
     284            3 :                 m_inBuffer.seekp(0, ios_base::beg);
     285              : 
     286              :                 // and write the rest
     287            3 :                 m_inBuffer.write(rest, rest_len);
     288            3 :                 if (!m_inBuffer.good()) {
     289            0 :                         UG_THROW("failed to write from input buffer");
     290              :                 }
     291              :         } else {
     292              :                 // reset buffer
     293          200 :                 m_inBuffer.str("");
     294          200 :                 m_inBuffer.seekp(0, ios_base::beg);
     295              :         }
     296              : 
     297              :         // set read and write position to beginning
     298          203 :         m_inBuffer.seekg(0, ios_base::beg);
     299              : 
     300          203 :         if (force) {
     301          359 :                 for(uint i = 0; i < paddChars; ++i)
     302          162 :                         m_fStream << '=';
     303              : 
     304              :                 // resetting num bytes written and bytes in block
     305          197 :                 m_numBytesWritten = 0;
     306              :         } else {
     307              :                 // update amount of bytes in input buffer
     308            6 :                 m_numBytesWritten -= buff_len;
     309              :         }
     310              : }
     311              : 
     312           98 : void Base64FileWriter::close()
     313              : {
     314              :         PROFILE_FUNC();
     315              : 
     316              :         // make sure all remaining content of the input buffer is encoded and flushed
     317           98 :         flushInputBuffer(true);
     318              : 
     319              :         // only when this is done, close the file stream
     320           98 :         m_fStream.close();
     321              :         UG_ASSERT(m_fStream.good(), "could not close output file.");
     322           98 : }
     323              : 
     324              : }       // namespace ug
        

Generated by: LCOV version 2.0-1