/* * Author: Patrick-Christopher Mattulat * Company: Lynar Studios * E-Mail: webmaster@lynarstudios.com * Created: 2023-02-14 * Changed: 2025-12-21 * * */ #include #include #include #include #include using ls::std::core::Class; using ls::std::core::NullPointerArgumentEvaluator; using ls::std::core::type::byte_field; using ls::std::io::section_pair_row_list_element; using ls::std::io::SectionPairRow; using ls::std::io::SectionPairRowEnumType; using ls::std::io::SectionPairSection; using ls::std::io::SectionPairSectionArgumentEvaluator; using ls::std::io::SerializableSectionPairParameter; using ls::std::io::SerializableSectionPairSection; using std::dynamic_pointer_cast; using std::make_shared; using std::shared_ptr; using std::string; using std::string_view; SerializableSectionPairSection::SerializableSectionPairSection(const SerializableSectionPairParameter &_parameter) : Class("SerializableSectionPairSection"), parameter(_parameter) { const string message = this->getClassName() + ": model reference is null!"; NullPointerArgumentEvaluator(_parameter.getValue(), message).evaluate(); } SerializableSectionPairSection::~SerializableSectionPairSection() noexcept = default; shared_ptr SerializableSectionPairSection::getValue() const { return this->parameter.getValue(); } byte_field SerializableSectionPairSection::marshal() { byte_field serializedSection{}; serializedSection += this->_marshalSectionId(); serializedSection += this->_marshalRows(); return serializedSection; } void SerializableSectionPairSection::unmarshal(const byte_field &_data) { SectionPairSectionArgumentEvaluator{_data}.evaluate(); const size_t sectionHeaderSize = this->_unmarshalSectionHeader(_data); this->_unmarshalRows(_data.substr(sectionHeaderSize)); } byte_field SerializableSectionPairSection::_collectSectionRow(const byte_field &_currentRows, SectionPairRowEnumType &_type) const { string row{}; const string newLine = this->parameter.getNewLine(); const string firstRow = _currentRows.substr(0, _currentRows.find(newLine) + newLine.size()); if (_isSingleValueRow(firstRow)) { row = _collectSectionSingleValueRow(firstRow, _type); } if (_isListValueRow(firstRow)) { row = this->_collectSectionListValueRow(_currentRows, _type); } return row; } byte_field SerializableSectionPairSection::_collectSectionListValueRow(const byte_field &_currentRows, SectionPairRowEnumType &_type) const { byte_field currentRows = _currentRows; byte_field currentRow{}; byte_field row{}; const string newLine = this->parameter.getNewLine(); _type = SectionPairRowEnumType::SECTION_PAIR_ROW_LIST_VALUE; size_t iterations{}; bool isStillListRow{}; do { if (currentRows.empty() && iterations > 1) { break; } ++iterations; currentRow = currentRows.substr(0, currentRows.find(newLine) + newLine.size()); currentRows = currentRows.substr(currentRow.size()); isStillListRow = !SerializableSectionPairSection::_isStartingValueRow(currentRow) || iterations == 1; if (isStillListRow) { row += currentRow; } } while (isStillListRow); return row; } byte_field SerializableSectionPairSection::_collectSectionSingleValueRow(const byte_field &_firstRow, SectionPairRowEnumType &_type) { _type = SectionPairRowEnumType::SECTION_PAIR_ROW_SINGLE_VALUE; return _firstRow; } size_t SerializableSectionPairSection::_getNthSubStringPosition(const string_view _text, const string_view _subText) { size_t position = string::npos; size_t amount{}; for (size_t index = 0; index < (_text.size() - _subText.size()); index++) { if (_text.substr(index, _subText.size()) == _subText) { ++amount; } if (amount == 2) { position = index; break; } } return position; } byte_field SerializableSectionPairSection::_getSectionHeader(const byte_field &_data) const { byte_field sectionHeader{}; const string newLine = this->parameter.getNewLine(); if (const size_t position = _getNthSubStringPosition(_data, newLine); position != string::npos) { sectionHeader = _data.substr(0, position + 2 * newLine.size()); } return sectionHeader; } byte_field SerializableSectionPairSection::_getSectionId(const string_view _sectionHeader) { auto sectionId = byte_field{_sectionHeader.substr(_sectionHeader.find('[') + 1)}; return sectionId.substr(0, sectionId.find(']')); } bool SerializableSectionPairSection::_isListValueRow(const string_view _currentRow) { return _currentRow.find(':') != string::npos; } bool SerializableSectionPairSection::_isStartingValueRow(const string &_currentRow) { const bool isSingleValue = _isSingleValueRow(_currentRow); const bool isListValue = _isListValueRow(_currentRow); return isSingleValue || isListValue; } bool SerializableSectionPairSection::_isSingleValueRow(const string_view _currentRow) { return _currentRow.find('=') != string::npos; } byte_field SerializableSectionPairSection::_marshalRows() const { byte_field serializedSectionRows{}; for (const auto &_row : dynamic_pointer_cast(this->parameter.getValue())->getList()) { _row->reserveNewLine(this->parameter.getNewLine()); serializedSectionRows += _row->marshal(); } return serializedSectionRows; } byte_field SerializableSectionPairSection::_marshalSectionId() const { const string newLine = this->parameter.getNewLine(); return newLine + "[" + dynamic_pointer_cast(this->parameter.getValue())->getSectionId() + "]" + newLine + newLine; } void SerializableSectionPairSection::_unmarshalRow(const string &_sectionRow, SectionPairRowEnumType _type) const { const auto row = make_shared("tmp-dir", _type); row->reserveNewLine(this->parameter.getNewLine()); row->unmarshal(_sectionRow); dynamic_pointer_cast(this->parameter.getValue())->add(row); } void SerializableSectionPairSection::_unmarshalRows(const byte_field &_serializedRows) const { string currentRows = _serializedRows; SectionPairRowEnumType type{}; while (!currentRows.empty()) { string sectionRow = this->_collectSectionRow(currentRows, type); this->_unmarshalRow(sectionRow, type); currentRows = currentRows.substr(sectionRow.size()); } } size_t SerializableSectionPairSection::_unmarshalSectionHeader(const byte_field &_data) const { const byte_field sectionHeader = this->_getSectionHeader(_data); dynamic_pointer_cast(this->parameter.getValue())->setSectionId(SerializableSectionPairSection::_getSectionId(sectionHeader)); return sectionHeader.size(); }