LCOV - code coverage report
Current view: top level - ezlibs - ezFigFont.hpp (source / functions) Coverage Total Hit
Test: Coverage (llvm-cov → lcov → genhtml) Lines: 91.8 % 134 123
Test Date: 2025-09-16 22:55:37 Functions: 90.0 % 10 9
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 84.8 % 46 39

             Branch data     Line data    Source code
       1                 :             : #pragma once
       2                 :             : 
       3                 :             : /*
       4                 :             : MIT License
       5                 :             : 
       6                 :             : Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
       7                 :             : 
       8                 :             : Permission is hereby granted, free of charge, to any person obtaining a copy
       9                 :             : of this software and associated documentation files (the "Software"), to deal
      10                 :             : in the Software without restriction, including without limitation the rights
      11                 :             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12                 :             : copies of the Software, and to permit persons to whom the Software is
      13                 :             : furnished to do so, subject to the following conditions:
      14                 :             : 
      15                 :             : The above copyright notice and this permission notice shall be included in all
      16                 :             : copies or substantial portions of the Software.
      17                 :             : 
      18                 :             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19                 :             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20                 :             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21                 :             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22                 :             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23                 :             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      24                 :             : SOFTWARE.
      25                 :             : */
      26                 :             : 
      27                 :             : // ezFigFont is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
      28                 :             : 
      29                 :             : #include <array>
      30                 :             : #include <string>
      31                 :             : #include <vector>
      32                 :             : #include <cstdint>
      33                 :             : #include <sstream>
      34                 :             : #include <fstream>
      35                 :             : #include <iostream>
      36                 :             : #include <unordered_map>
      37                 :             : 
      38                 :             : #include "ezLog.hpp"
      39                 :             : 
      40                 :             : #ifndef EZ_FIG_FONT
      41                 :             : #define EZ_FIG_FONT
      42                 :             : #endif  // EZ_FIG_FONT
      43                 :             : 
      44                 :             : namespace ez {
      45                 :             : 
      46                 :             : class FigFont {
      47                 :             : private:
      48                 :             :         bool m_isValid{false};
      49                 :             :     struct Header {
      50                 :             :         uint8_t endChar{};
      51                 :             :         uint8_t hardblank{};  // Filling char
      52                 :             :         int32_t height{};  // char height
      53                 :             :         int32_t baseline{};  // base line from top
      54                 :             :         int32_t maxLength{};  // max width of achar
      55                 :             :         int32_t oldLayout{}; // Old Layout
      56                 :             :         int32_t commentLines{};  // Comments line count just after header line
      57                 :             :         int32_t printDirection{};  // printing direction
      58                 :             :         int32_t fullLayout{};  // Full Layout
      59                 :             :         int32_t codetagCount{};  // codeTagCount (optional)
      60                 :             :         std::vector<std::string> commentBlock;
      61                 :             :     } m_header;
      62                 :             :     struct Glyph {
      63                 :             :         std::string desc;
      64                 :             :         std::vector<std::string> rows;
      65                 :             :     };
      66                 :             :     std::unordered_map<size_t, Glyph> m_glyphs;
      67                 :             :         
      68                 :             : public:
      69                 :           4 :     FigFont() = default;
      70                 :           0 :     FigFont(const std::string& vFilePathName) : m_isValid(m_load(vFilePathName)) {}
      71                 :           6 :     ~FigFont() = default;
      72                 :          14 :     bool isValid() { return m_isValid; }
      73                 :           6 :     FigFont& load(const std::string& vFilePathName) {
      74                 :           6 :         m_isValid = m_load(vFilePathName);
      75                 :           6 :         return *this;
      76                 :           6 :         }
      77                 :          10 :     std::string printString(const std::string& vPattern) {
      78                 :          10 :         return m_printString(vPattern);
      79                 :          10 :     }
      80                 :             :         
      81                 :             : private:
      82                 :           6 :         bool m_load(const std::string& vFilePathName) {
      83         [ -  + ]:           6 :         if (vFilePathName.empty()) {
      84                 :           0 :             return false;
      85                 :           0 :         }
      86                 :           6 :         std::ifstream file(vFilePathName);
      87         [ +  + ]:           6 :         if (!file.is_open()) {
      88                 :           2 : #ifdef EZ_TOOLS_LOG
      89                 :           2 :             LogVarError("Failed to open the file %s", vFilePathName.c_str());
      90                 :           2 : #endif // EZ_TOOLS_LOG
      91                 :           2 :             return false;
      92                 :           2 :         }
      93                 :             : 
      94                 :           4 :         std::string header;
      95                 :           4 :         std::getline(file, header);
      96                 :           4 :         std::istringstream headerStream(header);
      97                 :           4 :         std::string magicNumber;
      98                 :           4 :         headerStream >> magicNumber;
      99         [ -  + ]:           4 :         if (magicNumber.substr(0, 5) != "flf2a") {
     100                 :           0 : #ifdef EZ_TOOLS_LOG
     101                 :           0 :             LogVarError("%s", "Not a valid FIGfont file");
     102                 :           0 : #endif  // EZ_TOOLS_LOG
     103                 :           0 :             return false;
     104                 :           0 :         }
     105                 :             : 
     106                 :             :         /*
     107                 :             :           flf2a$ 6 5 20 15 3 0 143 229    NOTE: The first five characters in
     108                 :             :             |  | | | |  |  | |  |   |     the entire file must be "flf2a".                    
     109                 :             :            /  /  | | |  |  | |  |    \             
     110                 :             :   Signature  /  /  | |  |  | |   \   Codetag_Count
     111                 :             :     Hardblank  /  /  |  |  |  \   Full_Layout*
     112                 :             :          Height  /   |  |   \  Print_Direction
     113                 :             :          Baseline   /    \   Comment_Lines
     114                 :             :           Max_Length      Old_Layout*
     115                 :             :         */
     116                 :           4 :         m_header.hardblank = magicNumber[5];
     117                 :           4 :         headerStream >>  //
     118                 :           4 :             m_header.height >>  //
     119                 :           4 :             m_header.baseline >>  //
     120                 :           4 :             m_header.oldLayout >>  //
     121                 :           4 :             m_header.maxLength >>  //
     122                 :           4 :             m_header.commentLines >>  //
     123                 :           4 :             m_header.printDirection >>  //
     124                 :           4 :             m_header.fullLayout >>  //
     125                 :           4 :             m_header.codetagCount;
     126                 :             : 
     127                 :           4 :         std::string line;
     128                 :           4 :         m_header.commentBlock.reserve(m_header.commentLines);
     129         [ +  + ]:          44 :         for (int i = 0; i < m_header.commentLines; ++i) {
     130                 :          40 :             std::getline(file, line);
     131                 :          40 :             m_header.commentBlock.push_back(line);
     132                 :          40 :         }
     133                 :           4 :         size_t idx = 0;
     134                 :           4 :         static constexpr size_t baseChar = 32;
     135                 :           4 :         static constexpr size_t required_chars_count = 127 - baseChar;
     136                 :           4 :         static constexpr size_t additionnal_chars_count = 7;
     137                 :           4 :         std::array<size_t, additionnal_chars_count> additionnal_chars{196, 214, 220, 228, 246, 252, 223};
     138                 :           4 :         size_t cChar = baseChar;
     139         [ +  + ]:        1028 :         while (file) {
     140                 :        1024 :             std::vector<std::string> asciiArt;
     141         [ +  + ]:        1024 :             if (idx < required_chars_count) {
     142                 :         380 :                 cChar = idx + baseChar;
     143         [ -  + ]:         380 :                 if (!m_parseChar(file, cChar)) {
     144                 :             :                     // return false;
     145                 :           0 :                 }
     146         [ +  + ]:         644 :             } else if (idx - required_chars_count < additionnal_chars_count) {
     147                 :          28 :                 cChar = additionnal_chars.at(idx - required_chars_count);
     148         [ -  + ]:          28 :                 if (!m_parseChar(file, cChar)) {
     149                 :             :                     // return false;
     150                 :           0 :                 }
     151                 :         616 :             } else {
     152         [ +  + ]:         616 :                 if (!m_parseChar(file, 0)) {
     153                 :             :                     // return false;
     154                 :           4 :                 }
     155                 :         616 :             }
     156                 :        1024 :             ++idx;
     157                 :        1024 :         }
     158                 :           4 :         return true;
     159                 :           4 :         }
     160                 :             : 
     161                 :        1024 :     bool m_parseChar(std::ifstream& vFile, const size_t vChar) {
     162                 :        1024 :         std::string row;
     163                 :        1024 :         size_t charCode = vChar;
     164                 :        1024 :         Glyph glyph;
     165         [ +  + ]:        1024 :         if (charCode < 32) {
     166                 :         616 :             std::getline(vFile, row);
     167                 :         616 :             size_t spacePos = row.find(' ');
     168         [ +  + ]:         616 :             if (spacePos != std::string::npos) {
     169                 :         612 :                 const auto numStr = row.substr(0, spacePos);
     170                 :         612 :                 const auto descStr = row.substr(spacePos + 1);
     171                 :         612 :                 charCode = static_cast<size_t>(std::stoi(numStr));
     172                 :         612 :             } else {
     173                 :           4 :                 return false;
     174                 :           4 :             }
     175                 :         616 :         }
     176                 :        1020 :         glyph.rows.reserve(m_header.height);
     177         [ +  + ]:        9180 :         for (int i = 0; i < m_header.height; ++i) {
     178                 :        8160 :             std::getline(vFile, row);
     179         [ +  - ]:        8160 :             if (!row.empty()) {
     180         [ +  + ]:       17340 :                 while (row.back() == '@') {
     181                 :        9180 :                     row.pop_back();
     182                 :        9180 :                 }
     183         [ +  + ]:        8160 :                 if (row.front() == ' ') {
     184                 :        8144 :                     row = row.substr(1);
     185                 :        8144 :                 }
     186         [ +  + ]:       57808 :                 for (auto& c : row) {
     187         [ +  + ]:       57808 :                     if (c == static_cast<char>(m_header.hardblank)) {
     188                 :         328 :                         c = ' ';
     189                 :         328 :                     }
     190                 :       57808 :                 }
     191                 :        8160 :             }
     192                 :        8160 :             glyph.rows.push_back(row);
     193                 :        8160 :         }
     194                 :        1020 :         m_glyphs[charCode] = glyph;
     195                 :        1020 :         return true;
     196                 :        1024 :     }
     197                 :             : 
     198                 :          10 :         std::string m_printString(const std::string& vPattern) {
     199                 :          10 :         std::stringstream ret;
     200                 :          10 :         std::vector<std::string> rows;
     201                 :          10 :         rows.resize(m_header.height);
     202                 :          10 :         size_t row_idx = 0;
     203         [ +  + ]:          80 :         for (auto& row : rows) {
     204         [ +  + ]:         896 :             for (const auto c : vPattern) {
     205                 :         896 :                 row += m_getCharRow(c, row_idx);
     206                 :         896 :             }
     207                 :          80 :             ++row_idx;
     208                 :             :             // remove empty rows
     209         [ +  + ]:          80 :             if (row.find_first_not_of(" ") != std::string::npos) {
     210                 :          68 :                 ret << row << std::endl;
     211                 :          68 :             }
     212                 :          80 :         }
     213                 :          10 :         return ret.str();
     214                 :          10 :         }
     215                 :             : 
     216                 :         896 :     std::string m_getCharRow(size_t vC, size_t vRowIdx) {
     217                 :         896 :         auto it = m_glyphs.find(vC);
     218         [ +  - ]:         896 :         if (it != m_glyphs.end()) {
     219         [ +  - ]:         896 :             if (vRowIdx < it->second.rows.size()) {
     220                 :         896 :                 return it->second.rows.at(vRowIdx);
     221                 :         896 :             }
     222                 :         896 :         } 
     223                 :           0 :         return {};
     224                 :         896 :     }
     225                 :             : };
     226                 :             : 
     227                 :             : }
        

Generated by: LCOV version 2.0-1