std::optional parseLine()

in xar/XarParser.cpp [105:163]


std::optional<XarParserError> parseLine(
    const std::string& line,
    XarHeader* xarHeader,
    std::set<std::string>* foundNames) {
  // Split line into up to 2 parts
  auto nameValue = tools::xar::split(/* delim */ '=', line, /* nsplits */ 1);
  if (nameValue.size() != 2) {
    return XarParserError(XarParserErrorType::MALFORMED_LINE, line);
  }
  const std::string name = std::move(nameValue[0]);
  const std::string wrappedValue = std::move(nameValue[1]);

  if (name.empty() || wrappedValue.size() < 2 || wrappedValue.front() != '"' ||
      wrappedValue.back() != '"') {
    return XarParserError(XarParserErrorType::MALFORMED_LINE, line);
  }
  // Skip quotes around value
  const std::string value = wrappedValue.substr(1, wrappedValue.size() - 2);
  // Check value does not contain '"'
  if (value.find('"') != std::string::npos) {
    return XarParserError(XarParserErrorType::MALFORMED_LINE, line);
  }
  if (foundNames->find(name) != foundNames->end()) {
    // Variable already set. Though we might be able to ignore this, this is
    // probably a bug.
    return XarParserError(XarParserErrorType::DUPLICATE_PARAMETER, name);
  }
  foundNames->emplace(name);

  // Set field in header that corresponds to name
  if (name == kOffsetName) {
    if (auto maybeErrorMsg = parseUll(value, &xarHeader->offset);
        !maybeErrorMsg.empty()) {
      return XarParserError(XarParserErrorType::INVALID_OFFSET, maybeErrorMsg);
    }
    // Verify offset is a strictly positive multiple of kHeaderSizeBase
    if (xarHeader->offset % kHeaderSizeBase != 0 || xarHeader->offset == 0) {
      return XarParserError(
          XarParserErrorType::INVALID_OFFSET,
          std::to_string(xarHeader->offset) +
              " is not a positive multiple of " +
              std::to_string(kHeaderSizeBase));
    }
  } else if (name == kVersion) {
    xarHeader->version = value;
  } else if (name == kUuidName) {
    xarHeader->uuid = value;
  } else if (name == kXarexecTarget) {
    xarHeader->xarexecTarget = value;
  } else if (name == kXarexecTrampolineNames) {
    if (auto maybeError =
            parseTrampolineNames(value, &xarHeader->xarexecTrampolineNames)) {
      return maybeError;
    }
  } else {
    // Unknown parameter or offset (which has already been parsed). Ignore.
  }
  return {};
}