/* * Style parent's are a bit different. We accept the following formats: * * @[[*]package:][style/]<entry> * ?[[*]package:]style/<entry> * <[*]package>:[style/]<entry> * [[*]package:style/]<entry> */ Maybe<Reference> parseStyleParentReference(const StringPiece16& str, std::string* outError) { if (str.empty()) { return {}; } StringPiece16 name = str; bool hasLeadingIdentifiers = false; bool privateRef = false; // Skip over these identifiers. A style's parent is a normal reference. if (name.data()[0] == u'@' || name.data()[0] == u'?') { hasLeadingIdentifiers = true; name = name.substr(1, name.size() - 1); } if (name.data()[0] == u'*') { privateRef = true; name = name.substr(1, name.size() - 1); } ResourceNameRef ref; ref.type = ResourceType::kStyle; StringPiece16 typeStr; extractResourceName(name, &ref.package, &typeStr, &ref.entry); if (!typeStr.empty()) { // If we have a type, make sure it is a Style. const ResourceType* parsedType = parseResourceType(typeStr); if (!parsedType || *parsedType != ResourceType::kStyle) { std::stringstream err; err << "invalid resource type '" << typeStr << "' for parent of style"; *outError = err.str(); return {}; } } if (!hasLeadingIdentifiers && ref.package.empty() && !typeStr.empty()) { std::stringstream err; err << "invalid parent reference '" << str << "'"; *outError = err.str(); return {}; } Reference result(ref); result.privateReference = privateRef; return result; }
Maybe<std::u16string> extractPackageFromNamespace(const std::u16string& namespaceUri) { if (stringStartsWith<char16_t>(namespaceUri, kSchemaPrefix)) { StringPiece16 schemaPrefix = kSchemaPrefix; StringPiece16 package = namespaceUri; return package.substr(schemaPrefix.size(), package.size() - schemaPrefix.size()) .toString(); } else if (namespaceUri == kSchemaAuto) { return std::u16string(); } return {}; }
std::u16string Pseudolocalizer::text(const StringPiece16& text) { std::u16string out; size_t depth = mLastDepth; size_t lastpos, pos; const size_t length = text.size(); const char16_t* str = text.data(); bool escaped = false; for (lastpos = pos = 0; pos < length; pos++) { char16_t c = str[pos]; if (escaped) { escaped = false; continue; } if (c == '\'') { escaped = true; continue; } if (c == k_arg_start) { depth++; } else if (c == k_arg_end && depth) { depth--; } if (mLastDepth != depth || pos == length - 1) { bool pseudo = ((mLastDepth % 2) == 0); size_t nextpos = pos; if (!pseudo || depth == mLastDepth) { nextpos++; } size_t size = nextpos - lastpos; if (size) { std::u16string chunk = text.substr(lastpos, size).toString(); if (pseudo) { chunk = mImpl->text(chunk); } else if (str[lastpos] == k_arg_start && str[nextpos - 1] == k_arg_end) { chunk = mImpl->placeholder(chunk); } out.append(chunk); } if (pseudo && depth < mLastDepth) { // End of message out.append(mImpl->end()); } else if (!pseudo && depth > mLastDepth) { // Start of message out.append(mImpl->start()); } lastpos = nextpos; mLastDepth = depth; } } return out; }
bool BindingXmlPullParser::readExpressions() { mOverride = true; std::vector<XmlPullParser::Attribute> expressions; std::string idValue; const auto endAttrIter = mParser->endAttributes(); for (auto attr = mParser->beginAttributes(); attr != endAttrIter; ++attr) { if (attr->namespaceUri == kAndroidNamespaceUri && attr->name == u"id") { idValue = util::utf16ToUtf8(attr->value); } else { StringPiece16 value = util::trimWhitespace(attr->value); if (util::stringStartsWith<char16_t>(value, u"@{") && util::stringEndsWith<char16_t>(value, u"}")) { // This is attribute's value is an expression of the form // @{expression}. We need to capture the expression inside. expressions.push_back(XmlPullParser::Attribute{ attr->namespaceUri, attr->name, value.substr(2, value.size() - 3).toString() }); } else { // This is a normal attribute, use as is. mAttributes.emplace_back(*attr); } } } // Check if we have any expressions. if (!expressions.empty()) { // We have expressions, so let's assign the target a tag number // and add it to our targets list. int32_t targetId = mNextTagId++; mTargets.push_back(Target{ util::utf16ToUtf8(mParser->getElementName()), idValue, targetId, std::move(expressions) }); std::stringstream numGen; numGen << kBindingTagPrefix << targetId; mAttributes.push_back(XmlPullParser::Attribute{ std::u16string(kAndroidNamespaceUri), std::u16string(u"tag"), util::utf8ToUtf16(numGen.str()) }); } return true; }
bool parseResourceName(const StringPiece16& str, ResourceNameRef* outRef, bool* outPrivate) { if (str.empty()) { return false; } size_t offset = 0; bool priv = false; if (str.data()[0] == u'*') { priv = true; offset = 1; } StringPiece16 package; StringPiece16 type; StringPiece16 entry; if (!extractResourceName(str.substr(offset, str.size() - offset), &package, &type, &entry)) { return false; } const ResourceType* parsedType = parseResourceType(type); if (!parsedType) { return false; } if (entry.empty()) { return false; } if (outRef) { outRef->package = package; outRef->type = *parsedType; outRef->entry = entry; } if (outPrivate) { *outPrivate = priv; } return true; }