49 if (value == L"true") return true; |
50 if (value == L"true") return true; |
50 else if (value == L"false") return false; |
51 else if (value == L"false") return false; |
51 else throw relpipe::reader::RelpipeReaderException(L"Unable to parse boolean value: " + value + L" (expecting true or false)"); |
52 else throw relpipe::reader::RelpipeReaderException(L"Unable to parse boolean value: " + value + L" (expecting true or false)"); |
52 } |
53 } |
53 |
54 |
|
55 EscapingProcessor::QuotingType parseQuotingType(const relpipe::common::type::StringX& value) { |
|
56 if (value == quoting::None) return EscapingProcessor::QuotingType::None; |
|
57 else if (value == quoting::Apostrophes) return EscapingProcessor::QuotingType::Apostrophes; |
|
58 else if (value == quoting::Quotes) return EscapingProcessor::QuotingType::Quotes; |
|
59 else throw relpipe::reader::RelpipeReaderException(L"Unsupported quoting type:" + value); |
|
60 } |
|
61 |
|
62 class QuotingRule { |
|
63 public: |
|
64 EscapingProcessor::QuotingType type = EscapingProcessor::QuotingType::None; |
|
65 relpipe::common::type::StringX pattern; |
|
66 |
|
67 EscapingProcessor::QuotingType findEffectiveQuotingType(const relpipe::common::type::StringX& value) { |
|
68 if (type == EscapingProcessor::QuotingType::None) return type; |
|
69 else if (pattern.empty()) return type; |
|
70 else return std::regex_match(value, std::wregex(pattern)) ? type : EscapingProcessor::QuotingType::None; |
|
71 } |
|
72 }; |
|
73 |
|
74 QuotingRule quotingForSections; |
|
75 QuotingRule quotingForKeys; |
|
76 QuotingRule quotingForValues; |
|
77 |
54 std::string escape(const relpipe::common::type::StringX& value, EscapingProcessor::TextType type) { |
78 std::string escape(const relpipe::common::type::StringX& value, EscapingProcessor::TextType type) { |
55 relpipe::common::type::StringX result = value; |
79 relpipe::common::type::StringX result = value; |
56 EscapingProcessor::QuotingType quotingType = EscapingProcessor::QuotingType::None; |
80 |
|
81 EscapingProcessor::QuotingType quotingType; |
|
82 if (type == EscapingProcessor::TextType::SectionName || type == EscapingProcessor::TextType::SectionTag) quotingType = quotingForSections.findEffectiveQuotingType(value); |
|
83 else if (type == EscapingProcessor::TextType::EntryKey || type == EscapingProcessor::TextType::EntrySubKey) quotingType = quotingForKeys.findEffectiveQuotingType(value); |
|
84 else if (type == EscapingProcessor::TextType::EntryValue) quotingType = quotingForValues.findEffectiveQuotingType(value); |
|
85 else quotingType = EscapingProcessor::QuotingType::None; |
|
86 |
57 for (ConfiguredEscapingProcessor p : escapingProcessors) if (p.enbaled) result = p.processor->escape(result, type, quotingType); |
87 for (ConfiguredEscapingProcessor p : escapingProcessors) if (p.enbaled) result = p.processor->escape(result, type, quotingType); |
|
88 |
|
89 if (quotingType == EscapingProcessor::QuotingType::Quotes) result = L"\"" + result + L"\""; |
|
90 else if (quotingType == EscapingProcessor::QuotingType::Apostrophes) result = L"'" + result + L"'"; |
|
91 |
58 return convertor.to_bytes(result); |
92 return convertor.to_bytes(result); |
59 } |
93 } |
60 |
94 |
61 class ConfiguredEscapingProcessor { |
95 class ConfiguredEscapingProcessor { |
62 public: |
96 public: |
135 |
169 |
136 virtual ~INIWriter() { |
170 virtual ~INIWriter() { |
137 }; |
171 }; |
138 |
172 |
139 void setOption(relpipe::common::type::StringX uri, relpipe::common::type::StringX value) { |
173 void setOption(relpipe::common::type::StringX uri, relpipe::common::type::StringX value) { |
140 // TODO: setOption(): escaping, quotes, allow-sections |
|
141 if (uri == option::Dialect) setDialect(value); |
174 if (uri == option::Dialect) setDialect(value); |
142 else if (uri == option::CommentSeparatorForSections) commentSeparatorForSections = convertor.to_bytes(value); |
175 else if (uri == option::CommentSeparatorForSections) commentSeparatorForSections = convertor.to_bytes(value); |
143 else if (uri == option::CommentSeparatorForEntries) commentSeparatorForEntries = convertor.to_bytes(value); |
176 else if (uri == option::CommentSeparatorForEntries) commentSeparatorForEntries = convertor.to_bytes(value); |
144 else if (uri == option::CommentSeparatorStandalone) commentSeparatorStandalone = convertor.to_bytes(value); |
177 else if (uri == option::CommentSeparatorStandalone) commentSeparatorStandalone = convertor.to_bytes(value); |
145 else if (uri == option::KeyValueSeparator) keyValueSeparator = convertor.to_bytes(value); |
178 else if (uri == option::KeyValueSeparator) keyValueSeparator = convertor.to_bytes(value); |
146 else if (uri == option::AllowSections); |
179 else if (uri == option::AllowSections); // TODO: allow sections |
147 else if (uri == option::Quotes); |
180 else if (uri == option::QuotesTypeForSections) quotingForSections.type = parseQuotingType(value); |
|
181 else if (uri == option::QuotesTypeForKeys) quotingForKeys.type = parseQuotingType(value); |
|
182 else if (uri == option::QuotesTypeForValues) quotingForValues.type = parseQuotingType(value); |
|
183 else if (uri == option::QuotesPatternForSections) quotingForSections.pattern = value; |
|
184 else if (uri == option::QuotesPatternForKeys) quotingForKeys.pattern = value; |
|
185 else if (uri == option::QuotesPatternForValues) quotingForValues.pattern = value; |
148 else if (setEscaping(uri, value)); |
186 else if (setEscaping(uri, value)); |
149 else throw relpipe::reader::RelpipeReaderException(L"Unsupported writer option: " + uri); |
187 else throw relpipe::reader::RelpipeReaderException(L"Unsupported writer option: " + uri); |
150 } |
188 } |
151 |
189 |
152 void addDialect(std::shared_ptr<Dialect> dialect, const relpipe::common::type::StringX uri, bool enabledByDefault) { |
190 void addDialect(std::shared_ptr<Dialect> dialect, const relpipe::common::type::StringX uri, bool enabledByDefault) { |