1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include <functional>
4 #include <map>
5 #include <string>
6 #include <utility>
7 #include <vector>
8 
9 #include <cm/memory>
10 #include <cm/optional>
11 #include <cmext/string_view>
12 
13 #include <cm3p/json/reader.h>
14 #include <cm3p/json/value.h>
15 
16 #include "cmsys/FStream.hxx"
17 
18 #include "cmCMakePresetsFile.h"
19 #include "cmCMakePresetsFileInternal.h"
20 #include "cmJSONHelpers.h"
21 #include "cmVersion.h"
22 
23 namespace {
24 using ReadFileResult = cmCMakePresetsFile::ReadFileResult;
25 using CacheVariable = cmCMakePresetsFile::CacheVariable;
26 using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset;
27 using BuildPreset = cmCMakePresetsFile::BuildPreset;
28 using TestPreset = cmCMakePresetsFile::TestPreset;
29 using ArchToolsetStrategy = cmCMakePresetsFile::ArchToolsetStrategy;
30 
31 constexpr int MIN_VERSION = 1;
32 constexpr int MAX_VERSION = 3;
33 
34 struct CMakeVersion
35 {
36   unsigned int Major = 0;
37   unsigned int Minor = 0;
38   unsigned int Patch = 0;
39 };
40 
41 struct RootPresets
42 {
43   CMakeVersion CMakeMinimumRequired;
44   std::vector<cmCMakePresetsFile::ConfigurePreset> ConfigurePresets;
45   std::vector<cmCMakePresetsFile::BuildPreset> BuildPresets;
46   std::vector<cmCMakePresetsFile::TestPreset> TestPresets;
47 };
48 
InvertCondition(std::unique_ptr<cmCMakePresetsFile::Condition> condition)49 std::unique_ptr<cmCMakePresetsFileInternal::NotCondition> InvertCondition(
50   std::unique_ptr<cmCMakePresetsFile::Condition> condition)
51 {
52   auto retval = cm::make_unique<cmCMakePresetsFileInternal::NotCondition>();
53   retval->SubCondition = std::move(condition);
54   return retval;
55 }
56 
57 auto const ConditionStringHelper = cmJSONStringHelper<ReadFileResult>(
58   ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION);
59 
60 auto const ConditionBoolHelper = cmJSONBoolHelper<ReadFileResult>(
61   ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION);
62 
63 auto const ConditionStringListHelper =
64   cmJSONVectorHelper<std::string, ReadFileResult>(
65     ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION,
66     ConditionStringHelper);
67 
68 auto const ConstConditionHelper =
69   cmJSONObjectHelper<cmCMakePresetsFileInternal::ConstCondition,
70                      ReadFileResult>(ReadFileResult::READ_OK,
71                                      ReadFileResult::INVALID_CONDITION, false)
72     .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
73     .Bind("value"_s, &cmCMakePresetsFileInternal::ConstCondition::Value,
74           ConditionBoolHelper, true);
75 
76 auto const EqualsConditionHelper =
77   cmJSONObjectHelper<cmCMakePresetsFileInternal::EqualsCondition,
78                      ReadFileResult>(ReadFileResult::READ_OK,
79                                      ReadFileResult::INVALID_CONDITION, false)
80     .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
81     .Bind("lhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Lhs,
82           ConditionStringHelper, true)
83     .Bind("rhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Rhs,
84           ConditionStringHelper, true);
85 
86 auto const InListConditionHelper =
87   cmJSONObjectHelper<cmCMakePresetsFileInternal::InListCondition,
88                      ReadFileResult>(ReadFileResult::READ_OK,
89                                      ReadFileResult::INVALID_CONDITION, false)
90     .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
91     .Bind("string"_s, &cmCMakePresetsFileInternal::InListCondition::String,
92           ConditionStringHelper, true)
93     .Bind("list"_s, &cmCMakePresetsFileInternal::InListCondition::List,
94           ConditionStringListHelper, true);
95 
96 auto const MatchesConditionHelper =
97   cmJSONObjectHelper<cmCMakePresetsFileInternal::MatchesCondition,
98                      ReadFileResult>(ReadFileResult::READ_OK,
99                                      ReadFileResult::INVALID_CONDITION, false)
100     .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
101     .Bind("string"_s, &cmCMakePresetsFileInternal::MatchesCondition::String,
102           ConditionStringHelper, true)
103     .Bind("regex"_s, &cmCMakePresetsFileInternal::MatchesCondition::Regex,
104           ConditionStringHelper, true);
105 
106 ReadFileResult SubConditionHelper(
107   std::unique_ptr<cmCMakePresetsFile::Condition>& out,
108   const Json::Value* value);
109 
110 auto const ListConditionVectorHelper =
111   cmJSONVectorHelper<std::unique_ptr<cmCMakePresetsFile::Condition>,
112                      ReadFileResult>(ReadFileResult::READ_OK,
113                                      ReadFileResult::INVALID_CONDITION,
114                                      SubConditionHelper);
115 auto const AnyAllOfConditionHelper =
116   cmJSONObjectHelper<cmCMakePresetsFileInternal::AnyAllOfCondition,
117                      ReadFileResult>(ReadFileResult::READ_OK,
118                                      ReadFileResult::INVALID_CONDITION, false)
119     .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
120     .Bind("conditions"_s,
121           &cmCMakePresetsFileInternal::AnyAllOfCondition::Conditions,
122           ListConditionVectorHelper);
123 
124 auto const NotConditionHelper =
125   cmJSONObjectHelper<cmCMakePresetsFileInternal::NotCondition, ReadFileResult>(
126     ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false)
127     .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
128     .Bind("condition"_s,
129           &cmCMakePresetsFileInternal::NotCondition::SubCondition,
130           SubConditionHelper);
131 
ConditionHelper(std::unique_ptr<cmCMakePresetsFile::Condition> & out,const Json::Value * value)132 ReadFileResult ConditionHelper(
133   std::unique_ptr<cmCMakePresetsFile::Condition>& out,
134   const Json::Value* value)
135 {
136   if (!value) {
137     out.reset();
138     return ReadFileResult::READ_OK;
139   }
140 
141   if (value->isBool()) {
142     auto c = cm::make_unique<cmCMakePresetsFileInternal::ConstCondition>();
143     c->Value = value->asBool();
144     out = std::move(c);
145     return ReadFileResult::READ_OK;
146   }
147 
148   if (value->isNull()) {
149     out = cm::make_unique<cmCMakePresetsFileInternal::NullCondition>();
150     return ReadFileResult::READ_OK;
151   }
152 
153   if (value->isObject()) {
154     if (!value->isMember("type")) {
155       return ReadFileResult::INVALID_CONDITION;
156     }
157 
158     if (!(*value)["type"].isString()) {
159       return ReadFileResult::INVALID_CONDITION;
160     }
161     auto type = (*value)["type"].asString();
162 
163     if (type == "const") {
164       auto c = cm::make_unique<cmCMakePresetsFileInternal::ConstCondition>();
165       CHECK_OK(ConstConditionHelper(*c, value));
166       out = std::move(c);
167       return ReadFileResult::READ_OK;
168     }
169 
170     if (type == "equals" || type == "notEquals") {
171       auto c = cm::make_unique<cmCMakePresetsFileInternal::EqualsCondition>();
172       CHECK_OK(EqualsConditionHelper(*c, value));
173       out = std::move(c);
174       if (type == "notEquals") {
175         out = InvertCondition(std::move(out));
176       }
177       return ReadFileResult::READ_OK;
178     }
179 
180     if (type == "inList" || type == "notInList") {
181       auto c = cm::make_unique<cmCMakePresetsFileInternal::InListCondition>();
182       CHECK_OK(InListConditionHelper(*c, value));
183       out = std::move(c);
184       if (type == "notInList") {
185         out = InvertCondition(std::move(out));
186       }
187       return ReadFileResult::READ_OK;
188     }
189 
190     if (type == "matches" || type == "notMatches") {
191       auto c = cm::make_unique<cmCMakePresetsFileInternal::MatchesCondition>();
192       CHECK_OK(MatchesConditionHelper(*c, value));
193       out = std::move(c);
194       if (type == "notMatches") {
195         out = InvertCondition(std::move(out));
196       }
197       return ReadFileResult::READ_OK;
198     }
199 
200     if (type == "anyOf" || type == "allOf") {
201       auto c =
202         cm::make_unique<cmCMakePresetsFileInternal::AnyAllOfCondition>();
203       c->StopValue = (type == "anyOf");
204       CHECK_OK(AnyAllOfConditionHelper(*c, value));
205       out = std::move(c);
206       return ReadFileResult::READ_OK;
207     }
208 
209     if (type == "not") {
210       auto c = cm::make_unique<cmCMakePresetsFileInternal::NotCondition>();
211       CHECK_OK(NotConditionHelper(*c, value));
212       out = std::move(c);
213       return ReadFileResult::READ_OK;
214     }
215   }
216 
217   return ReadFileResult::INVALID_CONDITION;
218 }
219 
PresetConditionHelper(std::shared_ptr<cmCMakePresetsFile::Condition> & out,const Json::Value * value)220 ReadFileResult PresetConditionHelper(
221   std::shared_ptr<cmCMakePresetsFile::Condition>& out,
222   const Json::Value* value)
223 {
224   std::unique_ptr<cmCMakePresetsFile::Condition> ptr;
225   auto result = ConditionHelper(ptr, value);
226   out = std::move(ptr);
227   return result;
228 }
229 
SubConditionHelper(std::unique_ptr<cmCMakePresetsFile::Condition> & out,const Json::Value * value)230 ReadFileResult SubConditionHelper(
231   std::unique_ptr<cmCMakePresetsFile::Condition>& out,
232   const Json::Value* value)
233 {
234   std::unique_ptr<cmCMakePresetsFile::Condition> ptr;
235   auto result = ConditionHelper(ptr, value);
236   if (ptr && ptr->IsNull()) {
237     return ReadFileResult::INVALID_CONDITION;
238   }
239   out = std::move(ptr);
240   return result;
241 }
242 
VendorHelper(ReadFileResult error)243 cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error)
244 {
245   return [error](std::nullptr_t& /*out*/,
246                  const Json::Value* value) -> ReadFileResult {
247     if (!value) {
248       return ReadFileResult::READ_OK;
249     }
250 
251     if (!value->isObject()) {
252       return error;
253     }
254 
255     return ReadFileResult::READ_OK;
256   };
257 }
258 
259 auto const VersionIntHelper = cmJSONIntHelper<ReadFileResult>(
260   ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
261 
262 auto const VersionHelper = cmJSONRequiredHelper<int, ReadFileResult>(
263   ReadFileResult::NO_VERSION, VersionIntHelper);
264 
265 auto const RootVersionHelper =
266   cmJSONObjectHelper<int, ReadFileResult>(ReadFileResult::READ_OK,
267                                           ReadFileResult::INVALID_ROOT)
268     .Bind("version"_s, VersionHelper, false);
269 
270 auto const VariableStringHelper = cmJSONStringHelper<ReadFileResult>(
271   ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE);
272 
VariableValueHelper(std::string & out,const Json::Value * value)273 ReadFileResult VariableValueHelper(std::string& out, const Json::Value* value)
274 {
275   if (!value) {
276     out.clear();
277     return ReadFileResult::READ_OK;
278   }
279 
280   if (value->isBool()) {
281     out = value->asBool() ? "TRUE" : "FALSE";
282     return ReadFileResult::READ_OK;
283   }
284 
285   return VariableStringHelper(out, value);
286 }
287 
288 auto const VariableObjectHelper =
289   cmJSONObjectHelper<CacheVariable, ReadFileResult>(
290     ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false)
291     .Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false)
292     .Bind("value"_s, &CacheVariable::Value, VariableValueHelper);
293 
VariableHelper(cm::optional<CacheVariable> & out,const Json::Value * value)294 ReadFileResult VariableHelper(cm::optional<CacheVariable>& out,
295                               const Json::Value* value)
296 {
297   if (value->isBool()) {
298     out = CacheVariable{
299       /*Type=*/"BOOL",
300       /*Value=*/value->asBool() ? "TRUE" : "FALSE",
301     };
302     return ReadFileResult::READ_OK;
303   }
304   if (value->isString()) {
305     out = CacheVariable{
306       /*Type=*/"",
307       /*Value=*/value->asString(),
308     };
309     return ReadFileResult::READ_OK;
310   }
311   if (value->isObject()) {
312     out.emplace();
313     return VariableObjectHelper(*out, value);
314   }
315   if (value->isNull()) {
316     out = cm::nullopt;
317     return ReadFileResult::READ_OK;
318   }
319   return ReadFileResult::INVALID_VARIABLE;
320 }
321 
322 auto const VariablesHelper =
323   cmJSONMapHelper<cm::optional<CacheVariable>, ReadFileResult>(
324     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper);
325 
326 auto const PresetStringHelper = cmJSONStringHelper<ReadFileResult>(
327   ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
328 
EnvironmentHelper(cm::optional<std::string> & out,const Json::Value * value)329 ReadFileResult EnvironmentHelper(cm::optional<std::string>& out,
330                                  const Json::Value* value)
331 {
332   if (!value || value->isNull()) {
333     out = cm::nullopt;
334     return ReadFileResult::READ_OK;
335   }
336   if (value->isString()) {
337     out = value->asString();
338     return ReadFileResult::READ_OK;
339   }
340   return ReadFileResult::INVALID_PRESET;
341 }
342 
343 auto const EnvironmentMapHelper =
344   cmJSONMapHelper<cm::optional<std::string>, ReadFileResult>(
345     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
346     EnvironmentHelper);
347 
348 auto const PresetVectorStringHelper =
349   cmJSONVectorHelper<std::string, ReadFileResult>(
350     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
351     PresetStringHelper);
352 
PresetVectorOneOrMoreStringHelper(std::vector<std::string> & out,const Json::Value * value)353 ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out,
354                                                  const Json::Value* value)
355 {
356   out.clear();
357   if (!value) {
358     return ReadFileResult::READ_OK;
359   }
360 
361   if (value->isString()) {
362     out.push_back(value->asString());
363     return ReadFileResult::READ_OK;
364   }
365 
366   return PresetVectorStringHelper(out, value);
367 }
368 
369 auto const PresetBoolHelper = cmJSONBoolHelper<ReadFileResult>(
370   ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
371 
372 auto const PresetOptionalBoolHelper =
373   cmJSONOptionalHelper<bool, ReadFileResult>(ReadFileResult::READ_OK,
374                                              PresetBoolHelper);
375 
376 auto const PresetIntHelper = cmJSONIntHelper<ReadFileResult>(
377   ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
378 
379 auto const PresetOptionalIntHelper = cmJSONOptionalHelper<int, ReadFileResult>(
380   ReadFileResult::READ_OK, PresetIntHelper);
381 
382 auto const PresetVectorIntHelper = cmJSONVectorHelper<int, ReadFileResult>(
383   ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper);
384 
385 auto const PresetWarningsHelper =
386   cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
387     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
388     .Bind("dev"_s, &ConfigurePreset::WarnDev, PresetOptionalBoolHelper, false)
389     .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated,
390           PresetOptionalBoolHelper, false)
391     .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized,
392           PresetOptionalBoolHelper, false)
393     .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli,
394           PresetOptionalBoolHelper, false)
395     .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars,
396           PresetOptionalBoolHelper, false);
397 
398 auto const PresetErrorsHelper =
399   cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
400     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
401     .Bind("dev"_s, &ConfigurePreset::ErrorDev, PresetOptionalBoolHelper, false)
402     .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated,
403           PresetOptionalBoolHelper, false);
404 
405 auto const PresetDebugHelper =
406   cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
407     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
408     .Bind("output"_s, &ConfigurePreset::DebugOutput, PresetOptionalBoolHelper,
409           false)
410     .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile,
411           PresetOptionalBoolHelper, false)
412     .Bind("find"_s, &ConfigurePreset::DebugFind, PresetOptionalBoolHelper,
413           false);
414 
ArchToolsetStrategyHelper(cm::optional<ArchToolsetStrategy> & out,const Json::Value * value)415 ReadFileResult ArchToolsetStrategyHelper(
416   cm::optional<ArchToolsetStrategy>& out, const Json::Value* value)
417 {
418   if (!value) {
419     out = cm::nullopt;
420     return ReadFileResult::READ_OK;
421   }
422 
423   if (!value->isString()) {
424     return ReadFileResult::INVALID_PRESET;
425   }
426 
427   if (value->asString() == "set") {
428     out = ArchToolsetStrategy::Set;
429     return ReadFileResult::READ_OK;
430   }
431 
432   if (value->asString() == "external") {
433     out = ArchToolsetStrategy::External;
434     return ReadFileResult::READ_OK;
435   }
436 
437   return ReadFileResult::INVALID_PRESET;
438 }
439 
440 std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)>
ArchToolsetHelper(std::string ConfigurePreset::* valueField,cm::optional<ArchToolsetStrategy> ConfigurePreset::* strategyField)441 ArchToolsetHelper(
442   std::string ConfigurePreset::*valueField,
443   cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField)
444 {
445   auto const objectHelper =
446     cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
447       ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
448       .Bind("value", valueField, PresetStringHelper, false)
449       .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false);
450   return [valueField, strategyField, objectHelper](
451            ConfigurePreset& out, const Json::Value* value) -> ReadFileResult {
452     if (!value) {
453       (out.*valueField).clear();
454       out.*strategyField = cm::nullopt;
455       return ReadFileResult::READ_OK;
456     }
457 
458     if (value->isString()) {
459       out.*valueField = value->asString();
460       out.*strategyField = cm::nullopt;
461       return ReadFileResult::READ_OK;
462     }
463 
464     if (value->isObject()) {
465       return objectHelper(out, value);
466     }
467 
468     return ReadFileResult::INVALID_PRESET;
469   };
470 }
471 
472 auto const ArchitectureHelper = ArchToolsetHelper(
473   &ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy);
474 auto const ToolsetHelper = ArchToolsetHelper(
475   &ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy);
476 
477 auto const ConfigurePresetHelper =
478   cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
479     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
480     .Bind("name"_s, &ConfigurePreset::Name, PresetStringHelper)
481     .Bind("inherits"_s, &ConfigurePreset::Inherits,
482           PresetVectorOneOrMoreStringHelper, false)
483     .Bind("hidden"_s, &ConfigurePreset::Hidden, PresetBoolHelper, false)
484     .Bind<std::nullptr_t>("vendor"_s, nullptr,
485                           VendorHelper(ReadFileResult::INVALID_PRESET), false)
486     .Bind("displayName"_s, &ConfigurePreset::DisplayName, PresetStringHelper,
487           false)
488     .Bind("description"_s, &ConfigurePreset::Description, PresetStringHelper,
489           false)
490     .Bind("generator"_s, &ConfigurePreset::Generator, PresetStringHelper,
491           false)
492     .Bind("architecture"_s, ArchitectureHelper, false)
493     .Bind("toolset"_s, ToolsetHelper, false)
494     .Bind("toolchainFile"_s, &ConfigurePreset::ToolchainFile,
495           PresetStringHelper, false)
496     .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir, PresetStringHelper,
497           false)
498     .Bind("installDir"_s, &ConfigurePreset::InstallDir, PresetStringHelper,
499           false)
500     .Bind<std::string>("cmakeExecutable"_s, nullptr, PresetStringHelper, false)
501     .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables,
502           VariablesHelper, false)
503     .Bind("environment"_s, &ConfigurePreset::Environment, EnvironmentMapHelper,
504           false)
505     .Bind("warnings"_s, PresetWarningsHelper, false)
506     .Bind("errors"_s, PresetErrorsHelper, false)
507     .Bind("debug"_s, PresetDebugHelper, false)
508     .Bind("condition"_s, &ConfigurePreset::ConditionEvaluator,
509           PresetConditionHelper, false);
510 
511 auto const BuildPresetHelper =
512   cmJSONObjectHelper<BuildPreset, ReadFileResult>(
513     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
514     .Bind("name"_s, &BuildPreset::Name, PresetStringHelper)
515     .Bind("inherits"_s, &BuildPreset::Inherits,
516           PresetVectorOneOrMoreStringHelper, false)
517     .Bind("hidden"_s, &BuildPreset::Hidden, PresetBoolHelper, false)
518     .Bind<std::nullptr_t>("vendor"_s, nullptr,
519                           VendorHelper(ReadFileResult::INVALID_PRESET), false)
520     .Bind("displayName"_s, &BuildPreset::DisplayName, PresetStringHelper,
521           false)
522     .Bind("description"_s, &BuildPreset::Description, PresetStringHelper,
523           false)
524     .Bind("environment"_s, &BuildPreset::Environment, EnvironmentMapHelper,
525           false)
526     .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset,
527           PresetStringHelper, false)
528     .Bind("inheritConfigureEnvironment"_s,
529           &BuildPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
530           false)
531     .Bind("jobs"_s, &BuildPreset::Jobs, PresetOptionalIntHelper, false)
532     .Bind("targets"_s, &BuildPreset::Targets,
533           PresetVectorOneOrMoreStringHelper, false)
534     .Bind("configuration"_s, &BuildPreset::Configuration, PresetStringHelper,
535           false)
536     .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, PresetOptionalBoolHelper,
537           false)
538     .Bind("verbose"_s, &BuildPreset::Verbose, PresetOptionalBoolHelper, false)
539     .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
540           PresetVectorStringHelper, false)
541     .Bind("condition"_s, &BuildPreset::ConditionEvaluator,
542           PresetConditionHelper, false);
543 
TestPresetOutputVerbosityHelper(TestPreset::OutputOptions::VerbosityEnum & out,const Json::Value * value)544 ReadFileResult TestPresetOutputVerbosityHelper(
545   TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value)
546 {
547   if (!value) {
548     out = TestPreset::OutputOptions::VerbosityEnum::Default;
549     return ReadFileResult::READ_OK;
550   }
551 
552   if (!value->isString()) {
553     return ReadFileResult::INVALID_PRESET;
554   }
555 
556   if (value->asString() == "default") {
557     out = TestPreset::OutputOptions::VerbosityEnum::Default;
558     return ReadFileResult::READ_OK;
559   }
560 
561   if (value->asString() == "verbose") {
562     out = TestPreset::OutputOptions::VerbosityEnum::Verbose;
563     return ReadFileResult::READ_OK;
564   }
565 
566   if (value->asString() == "extra") {
567     out = TestPreset::OutputOptions::VerbosityEnum::Extra;
568     return ReadFileResult::READ_OK;
569   }
570 
571   return ReadFileResult::INVALID_PRESET;
572 }
573 
574 auto const TestPresetOptionalOutputVerbosityHelper =
575   cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum,
576                        ReadFileResult>(ReadFileResult::READ_OK,
577                                        TestPresetOutputVerbosityHelper);
578 
579 auto const TestPresetOptionalOutputHelper =
580   cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>(
581     ReadFileResult::READ_OK,
582     cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>(
583       ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
584       .Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress,
585             PresetOptionalBoolHelper, false)
586       .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity,
587             TestPresetOptionalOutputVerbosityHelper, false)
588       .Bind("debug"_s, &TestPreset::OutputOptions::Debug,
589             PresetOptionalBoolHelper, false)
590       .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure,
591             PresetOptionalBoolHelper, false)
592       .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet,
593             PresetOptionalBoolHelper, false)
594       .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile,
595             PresetStringHelper, false)
596       .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary,
597             PresetOptionalBoolHelper, false)
598       .Bind("subprojectSummary"_s,
599             &TestPreset::OutputOptions::SubprojectSummary,
600             PresetOptionalBoolHelper, false)
601       .Bind("maxPassedTestOutputSize"_s,
602             &TestPreset::OutputOptions::MaxPassedTestOutputSize,
603             PresetOptionalIntHelper, false)
604       .Bind("maxFailedTestOutputSize"_s,
605             &TestPreset::OutputOptions::MaxFailedTestOutputSize,
606             PresetOptionalIntHelper, false)
607       .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth,
608             PresetOptionalIntHelper, false));
609 
610 auto const TestPresetOptionalFilterIncludeIndexObjectHelper =
611   cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions,
612                        ReadFileResult>(
613     ReadFileResult::READ_OK,
614     cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions,
615                        ReadFileResult>(ReadFileResult::READ_OK,
616                                        ReadFileResult::INVALID_PRESET)
617       .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start,
618             PresetOptionalIntHelper, false)
619       .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End,
620             PresetOptionalIntHelper, false)
621       .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride,
622             PresetOptionalIntHelper, false)
623       .Bind("specificTests"_s,
624             &TestPreset::IncludeOptions::IndexOptions::SpecificTests,
625             PresetVectorIntHelper, false));
626 
TestPresetOptionalFilterIncludeIndexHelper(cm::optional<TestPreset::IncludeOptions::IndexOptions> & out,const Json::Value * value)627 ReadFileResult TestPresetOptionalFilterIncludeIndexHelper(
628   cm::optional<TestPreset::IncludeOptions::IndexOptions>& out,
629   const Json::Value* value)
630 {
631   if (!value) {
632     out = cm::nullopt;
633     return ReadFileResult::READ_OK;
634   }
635 
636   if (value->isString()) {
637     out.emplace();
638     out->IndexFile = value->asString();
639     return ReadFileResult::READ_OK;
640   }
641 
642   if (value->isObject()) {
643     return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value);
644   }
645 
646   return ReadFileResult::INVALID_PRESET;
647 }
648 
649 auto const TestPresetOptionalFilterIncludeHelper =
650   cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>(
651     ReadFileResult::READ_OK,
652     cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>(
653       ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
654       .Bind("name"_s, &TestPreset::IncludeOptions::Name, PresetStringHelper,
655             false)
656       .Bind("label"_s, &TestPreset::IncludeOptions::Label, PresetStringHelper,
657             false)
658       .Bind("index"_s, &TestPreset::IncludeOptions::Index,
659             TestPresetOptionalFilterIncludeIndexHelper, false)
660       .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion,
661             PresetOptionalBoolHelper, false));
662 
663 auto const TestPresetOptionalFilterExcludeFixturesHelper =
664   cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions,
665                        ReadFileResult>(
666     ReadFileResult::READ_OK,
667     cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions,
668                        ReadFileResult>(ReadFileResult::READ_OK,
669                                        ReadFileResult::INVALID_PRESET)
670       .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any,
671             PresetStringHelper, false)
672       .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup,
673             PresetStringHelper, false)
674       .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup,
675             PresetStringHelper, false));
676 
677 auto const TestPresetOptionalFilterExcludeHelper =
678   cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>(
679     ReadFileResult::READ_OK,
680     cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>(
681       ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
682       .Bind("name"_s, &TestPreset::ExcludeOptions::Name, PresetStringHelper,
683             false)
684       .Bind("label"_s, &TestPreset::ExcludeOptions::Label, PresetStringHelper,
685             false)
686       .Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures,
687             TestPresetOptionalFilterExcludeFixturesHelper, false));
688 
TestPresetExecutionShowOnlyHelper(TestPreset::ExecutionOptions::ShowOnlyEnum & out,const Json::Value * value)689 ReadFileResult TestPresetExecutionShowOnlyHelper(
690   TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value)
691 {
692   if (!value || !value->isString()) {
693     return ReadFileResult::INVALID_PRESET;
694   }
695 
696   if (value->asString() == "human") {
697     out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human;
698     return ReadFileResult::READ_OK;
699   }
700 
701   if (value->asString() == "json-v1") {
702     out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1;
703     return ReadFileResult::READ_OK;
704   }
705 
706   return ReadFileResult::INVALID_PRESET;
707 }
708 
709 auto const TestPresetOptionalExecutionShowOnlyHelper =
710   cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum,
711                        ReadFileResult>(ReadFileResult::READ_OK,
712                                        TestPresetExecutionShowOnlyHelper);
713 
TestPresetExecutionModeHelper(TestPreset::ExecutionOptions::RepeatOptions::ModeEnum & out,const Json::Value * value)714 ReadFileResult TestPresetExecutionModeHelper(
715   TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out,
716   const Json::Value* value)
717 {
718   if (!value) {
719     return ReadFileResult::READ_OK;
720   }
721 
722   if (!value->isString()) {
723     return ReadFileResult::INVALID_PRESET;
724   }
725 
726   if (value->asString() == "until-fail") {
727     out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail;
728     return ReadFileResult::READ_OK;
729   }
730 
731   if (value->asString() == "until-pass") {
732     out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass;
733     return ReadFileResult::READ_OK;
734   }
735 
736   if (value->asString() == "after-timeout") {
737     out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout;
738     return ReadFileResult::READ_OK;
739   }
740 
741   return ReadFileResult::INVALID_PRESET;
742 }
743 
744 auto const TestPresetOptionalExecutionRepeatHelper =
745   cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions,
746                        ReadFileResult>(
747     ReadFileResult::READ_OK,
748     cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions,
749                        ReadFileResult>(ReadFileResult::READ_OK,
750                                        ReadFileResult::INVALID_PRESET)
751       .Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode,
752             TestPresetExecutionModeHelper, true)
753       .Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count,
754             PresetIntHelper, true));
755 
TestPresetExecutionNoTestsActionHelper(TestPreset::ExecutionOptions::NoTestsActionEnum & out,const Json::Value * value)756 ReadFileResult TestPresetExecutionNoTestsActionHelper(
757   TestPreset::ExecutionOptions::NoTestsActionEnum& out,
758   const Json::Value* value)
759 {
760   if (!value) {
761     out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
762     return ReadFileResult::READ_OK;
763   }
764 
765   if (!value->isString()) {
766     return ReadFileResult::INVALID_PRESET;
767   }
768 
769   if (value->asString() == "default") {
770     out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
771     return ReadFileResult::READ_OK;
772   }
773 
774   if (value->asString() == "error") {
775     out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error;
776     return ReadFileResult::READ_OK;
777   }
778 
779   if (value->asString() == "ignore") {
780     out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore;
781     return ReadFileResult::READ_OK;
782   }
783 
784   return ReadFileResult::INVALID_PRESET;
785 }
786 
787 auto const TestPresetOptionalExecutionNoTestsActionHelper =
788   cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum,
789                        ReadFileResult>(ReadFileResult::READ_OK,
790                                        TestPresetExecutionNoTestsActionHelper);
791 
792 auto const TestPresetExecutionHelper =
793   cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>(
794     ReadFileResult::READ_OK,
795     cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>(
796       ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
797       .Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure,
798             PresetOptionalBoolHelper, false)
799       .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover,
800             PresetOptionalBoolHelper, false)
801       .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs,
802             PresetOptionalIntHelper, false)
803       .Bind("resourceSpecFile"_s,
804             &TestPreset::ExecutionOptions::ResourceSpecFile,
805             PresetStringHelper, false)
806       .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad,
807             PresetOptionalIntHelper, false)
808       .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly,
809             TestPresetOptionalExecutionShowOnlyHelper, false)
810       .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat,
811             TestPresetOptionalExecutionRepeatHelper, false)
812       .Bind("interactiveDebugging"_s,
813             &TestPreset::ExecutionOptions::InteractiveDebugging,
814             PresetOptionalBoolHelper, false)
815       .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom,
816             PresetOptionalBoolHelper, false)
817       .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout,
818             PresetOptionalIntHelper, false)
819       .Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction,
820             TestPresetOptionalExecutionNoTestsActionHelper, false));
821 
822 auto const TestPresetFilterHelper =
823   cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>(
824     ReadFileResult::READ_OK,
825     cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>(
826       ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
827       .Bind("include"_s, &TestPreset::FilterOptions::Include,
828             TestPresetOptionalFilterIncludeHelper, false)
829       .Bind("exclude"_s, &TestPreset::FilterOptions::Exclude,
830             TestPresetOptionalFilterExcludeHelper, false));
831 
832 auto const TestPresetHelper =
833   cmJSONObjectHelper<TestPreset, ReadFileResult>(
834     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
835     .Bind("name"_s, &TestPreset::Name, PresetStringHelper)
836     .Bind("inherits"_s, &TestPreset::Inherits,
837           PresetVectorOneOrMoreStringHelper, false)
838     .Bind("hidden"_s, &TestPreset::Hidden, PresetBoolHelper, false)
839     .Bind<std::nullptr_t>("vendor"_s, nullptr,
840                           VendorHelper(ReadFileResult::INVALID_PRESET), false)
841     .Bind("displayName"_s, &TestPreset::DisplayName, PresetStringHelper, false)
842     .Bind("description"_s, &TestPreset::Description, PresetStringHelper, false)
843     .Bind("environment"_s, &TestPreset::Environment, EnvironmentMapHelper,
844           false)
845     .Bind("configurePreset"_s, &TestPreset::ConfigurePreset,
846           PresetStringHelper, false)
847     .Bind("inheritConfigureEnvironment"_s,
848           &TestPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
849           false)
850     .Bind("configuration"_s, &TestPreset::Configuration, PresetStringHelper,
851           false)
852     .Bind("overwriteConfigurationFile"_s,
853           &TestPreset::OverwriteConfigurationFile, PresetVectorStringHelper,
854           false)
855     .Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper,
856           false)
857     .Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false)
858     .Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper,
859           false)
860     .Bind("condition"_s, &TestPreset::ConditionEvaluator,
861           PresetConditionHelper, false);
862 
863 auto const ConfigurePresetsHelper =
864   cmJSONVectorHelper<ConfigurePreset, ReadFileResult>(
865     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
866     ConfigurePresetHelper);
867 
868 auto const BuildPresetsHelper =
869   cmJSONVectorHelper<BuildPreset, ReadFileResult>(
870     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
871     BuildPresetHelper);
872 
873 auto const TestPresetsHelper = cmJSONVectorHelper<TestPreset, ReadFileResult>(
874   ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, TestPresetHelper);
875 
876 auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>(
877   ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
878 
879 auto const CMakeVersionHelper =
880   cmJSONObjectHelper<CMakeVersion, ReadFileResult>(
881     ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false)
882     .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false)
883     .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
884     .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
885 
886 auto const RootPresetsHelper =
887   cmJSONObjectHelper<RootPresets, ReadFileResult>(
888     ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
889     .Bind<int>("version"_s, nullptr, VersionHelper)
890     .Bind("configurePresets"_s, &RootPresets::ConfigurePresets,
891           ConfigurePresetsHelper, false)
892     .Bind("buildPresets"_s, &RootPresets::BuildPresets, BuildPresetsHelper,
893           false)
894     .Bind("testPresets"_s, &RootPresets::TestPresets, TestPresetsHelper, false)
895     .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
896           CMakeVersionHelper, false)
897     .Bind<std::nullptr_t>("vendor"_s, nullptr,
898                           VendorHelper(ReadFileResult::INVALID_ROOT), false);
899 }
900 
ReadJSONFile(const std::string & filename,bool user)901 cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile(
902   const std::string& filename, bool user)
903 {
904   cmsys::ifstream fin(filename.c_str());
905   if (!fin) {
906     return ReadFileResult::FILE_NOT_FOUND;
907   }
908   // If there's a BOM, toss it.
909   cmsys::FStream::ReadBOM(fin);
910 
911   Json::Value root;
912   Json::CharReaderBuilder builder;
913   Json::CharReaderBuilder::strictMode(&builder.settings_);
914   if (!Json::parseFromStream(builder, fin, &root, nullptr)) {
915     return ReadFileResult::JSON_PARSE_ERROR;
916   }
917 
918   int v = 0;
919   auto result = RootVersionHelper(v, &root);
920   if (result != ReadFileResult::READ_OK) {
921     return result;
922   }
923   if (v < MIN_VERSION || v > MAX_VERSION) {
924     return ReadFileResult::UNRECOGNIZED_VERSION;
925   }
926   if (user) {
927     this->UserVersion = v;
928   } else {
929     this->Version = v;
930   }
931 
932   // Support for build and test presets added in version 2.
933   if (v < 2 &&
934       (root.isMember("buildPresets") || root.isMember("testPresets"))) {
935     return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED;
936   }
937 
938   RootPresets presets;
939   if ((result = RootPresetsHelper(presets, &root)) !=
940       ReadFileResult::READ_OK) {
941     return result;
942   }
943 
944   unsigned int currentMajor = cmVersion::GetMajorVersion();
945   unsigned int currentMinor = cmVersion::GetMinorVersion();
946   unsigned int currentPatch = cmVersion::GetPatchVersion();
947   auto const& required = presets.CMakeMinimumRequired;
948   if (required.Major > currentMajor ||
949       (required.Major == currentMajor &&
950        (required.Minor > currentMinor ||
951         (required.Minor == currentMinor &&
952          (required.Patch > currentPatch))))) {
953     return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION;
954   }
955 
956   for (auto& preset : presets.ConfigurePresets) {
957     preset.User = user;
958     if (preset.Name.empty()) {
959       return ReadFileResult::INVALID_PRESET;
960     }
961 
962     PresetPair<ConfigurePreset> presetPair;
963     presetPair.Unexpanded = preset;
964     presetPair.Expanded = cm::nullopt;
965     if (!this->ConfigurePresets
966            .emplace(std::make_pair(preset.Name, presetPair))
967            .second) {
968       return ReadFileResult::DUPLICATE_PRESETS;
969     }
970 
971     // Support for installDir presets added in version 3.
972     if (v < 3 && !preset.InstallDir.empty()) {
973       return ReadFileResult::INSTALL_PREFIX_UNSUPPORTED;
974     }
975 
976     // Support for conditions added in version 3.
977     if (v < 3 && preset.ConditionEvaluator) {
978       return ReadFileResult::CONDITION_UNSUPPORTED;
979     }
980 
981     // Support for toolchainFile presets added in version 3.
982     if (v < 3 && !preset.ToolchainFile.empty()) {
983       return ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED;
984     }
985 
986     this->ConfigurePresetOrder.push_back(preset.Name);
987   }
988 
989   for (auto& preset : presets.BuildPresets) {
990     preset.User = user;
991     if (preset.Name.empty()) {
992       return ReadFileResult::INVALID_PRESET;
993     }
994 
995     PresetPair<BuildPreset> presetPair;
996     presetPair.Unexpanded = preset;
997     presetPair.Expanded = cm::nullopt;
998     if (!this->BuildPresets.emplace(preset.Name, presetPair).second) {
999       return ReadFileResult::DUPLICATE_PRESETS;
1000     }
1001 
1002     // Support for conditions added in version 3.
1003     if (v < 3 && preset.ConditionEvaluator) {
1004       return ReadFileResult::CONDITION_UNSUPPORTED;
1005     }
1006 
1007     this->BuildPresetOrder.push_back(preset.Name);
1008   }
1009 
1010   for (auto& preset : presets.TestPresets) {
1011     preset.User = user;
1012     if (preset.Name.empty()) {
1013       return ReadFileResult::INVALID_PRESET;
1014     }
1015 
1016     PresetPair<TestPreset> presetPair;
1017     presetPair.Unexpanded = preset;
1018     presetPair.Expanded = cm::nullopt;
1019     if (!this->TestPresets.emplace(preset.Name, presetPair).second) {
1020       return ReadFileResult::DUPLICATE_PRESETS;
1021     }
1022 
1023     // Support for conditions added in version 3.
1024     if (v < 3 && preset.ConditionEvaluator) {
1025       return ReadFileResult::CONDITION_UNSUPPORTED;
1026     }
1027 
1028     this->TestPresetOrder.push_back(preset.Name);
1029   }
1030 
1031   return ReadFileResult::READ_OK;
1032 }
1033