diff --git a/src/ascii-parser.cc b/src/ascii-parser.cc index 20b21833d..5429baeb5 100644 --- a/src/ascii-parser.cc +++ b/src/ascii-parser.cc @@ -1420,10 +1420,12 @@ bool AsciiParser::ReadPrimAttrIdentifier(std::string *token) { ss << c; } - // ':' must lie in the middle of string literal - if (ss.str().back() == ':') { - PUSH_ERROR_AND_RETURN("PrimAttr name must not ends with `:`\n"); - return false; + { + std::string name_err; + if (!pathutil::ValidatePropPath(Path("", ss.str()), &name_err)) { + PUSH_ERROR_AND_RETURN_TAG(kAscii, + fmt::format("Invalid Property name `{}`: {}", ss.str(), name_err)); + } } // '.' must lie in the middle of string literal @@ -1432,7 +1434,7 @@ bool AsciiParser::ReadPrimAttrIdentifier(std::string *token) { return false; } - // Currently we only support '.connect' + std::string tok = ss.str(); if (contains(tok, '.')) { @@ -3140,6 +3142,15 @@ bool AsciiParser::ParseAttrMeta(AttrMeta *out_meta) { fmt::format("Unsupported Property metadatum name: {}", varname)); } + { + std::string name_err; + if (!pathutil::ValidatePropPath(Path("", varname), &name_err)) { + PUSH_ERROR_AND_RETURN_TAG(kAscii, + fmt::format("Invalid Property name `{}`: {}", varname, name_err)); + } + } + + if (!SkipWhitespaceAndNewline()) { return false; } @@ -3260,7 +3271,7 @@ bool AsciiParser::ParseAttrMeta(AttrMeta *out_meta) { metavar.set_name(varname); // add to custom meta - out_meta->meta.emplace(varname, metavar); + out_meta->meta[varname] = metavar; } else { // This should not happen though. diff --git a/src/path-util.cc b/src/path-util.cc index babffbb58..fe98d23d4 100644 --- a/src/path-util.cc +++ b/src/path-util.cc @@ -173,5 +173,40 @@ bool ResolveRelativePath(const Path &base_prim_path, const Path &relative_path, return true; } +bool ValidatePropPath(const Path &path, std::string *err) { + if (path.prop_part() == ":") { + if (err) { + (*err) = "Namespace delimiter only in Property path."; + } + return false; + } + + if (startsWith(path.prop_part(), ":")) { + if (err) { + (*err) = "Property path starts with namespace delimiter."; + } + return false; + } + + if (endsWith(path.prop_part(), ":")) { + if (err) { + (*err) = "Property path ends with namespace delimiter."; + } + return false; + } + + if (contains_str(path.prop_part(), "::")) { + if (err) { + (*err) = "Empty path among namespace delimiters(`::`) in Property path."; + } + return false; + } + + // TODO: more validation + + return true; + +} + } // namespace pathutil } // namespace tinyusdz diff --git a/tests/usda/fail-case/empty-namespace-propname-000.usda b/tests/usda/fail-case/empty-namespace-propname-000.usda new file mode 100644 index 000000000..be8307435 --- /dev/null +++ b/tests/usda/fail-case/empty-namespace-propname-000.usda @@ -0,0 +1,5 @@ +#usda 1.0 + +def "bora" { + int bora::dora = 3 +} diff --git a/tests/usdc/failure-case/issue-namespace-000.usdc b/tests/usdc/failure-case/issue-namespace-000.usdc new file mode 100644 index 000000000..c950964ba Binary files /dev/null and b/tests/usdc/failure-case/issue-namespace-000.usdc differ