Home | History | Annotate | Download | only in xml
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "xml/XmlActionExecutor.h"
     18 
     19 using ::android::StringPiece;
     20 
     21 namespace aapt {
     22 namespace xml {
     23 
     24 static bool wrapper_one(XmlNodeAction::ActionFunc& f, Element* el, SourcePathDiagnostics*) {
     25   return f(el);
     26 }
     27 
     28 static bool wrapper_two(XmlNodeAction::ActionFuncWithDiag& f, Element* el,
     29                         SourcePathDiagnostics* diag) {
     30   return f(el, diag);
     31 }
     32 
     33 void XmlNodeAction::Action(XmlNodeAction::ActionFunc f) {
     34   actions_.emplace_back(std::bind(
     35       wrapper_one, std::move(f), std::placeholders::_1, std::placeholders::_2));
     36 }
     37 
     38 void XmlNodeAction::Action(XmlNodeAction::ActionFuncWithDiag f) {
     39   actions_.emplace_back(std::bind(
     40       wrapper_two, std::move(f), std::placeholders::_1, std::placeholders::_2));
     41 }
     42 
     43 static void PrintElementToDiagMessage(const Element* el, DiagMessage* msg) {
     44   *msg << "<";
     45   if (!el->namespace_uri.empty()) {
     46     *msg << el->namespace_uri << ":";
     47   }
     48   *msg << el->name << ">";
     49 }
     50 
     51 bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, std::vector<StringPiece>* bread_crumb,
     52                             SourcePathDiagnostics* diag, Element* el) const {
     53   bool error = false;
     54   for (const ActionFuncWithDiag& action : actions_) {
     55     error |= !action(el, diag);
     56   }
     57 
     58   for (Element* child_el : el->GetChildElements()) {
     59     if (child_el->namespace_uri.empty()) {
     60       std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(child_el->name);
     61       if (iter != map_.end()) {
     62         // Use the iterator's copy of the element name, because the element may be modified.
     63         bread_crumb->push_back(iter->first);
     64         error |= !iter->second.Execute(policy, bread_crumb, diag, child_el);
     65         bread_crumb->pop_back();
     66         continue;
     67       }
     68 
     69       if (policy != XmlActionExecutorPolicy::kNone) {
     70         DiagMessage error_msg(child_el->line_number);
     71         error_msg << "unexpected element ";
     72         PrintElementToDiagMessage(child_el, &error_msg);
     73         error_msg << " found in ";
     74         for (const StringPiece& element : *bread_crumb) {
     75           error_msg << "<" << element << ">";
     76         }
     77         if (policy == XmlActionExecutorPolicy::kWhitelistWarning) {
     78           // Treat the error only as a warning.
     79           diag->Warn(error_msg);
     80         } else {
     81           // Policy is XmlActionExecutorPolicy::kWhitelist, we should fail.
     82           diag->Error(error_msg);
     83           error = true;
     84         }
     85       }
     86     }
     87   }
     88   return !error;
     89 }
     90 
     91 bool XmlActionExecutor::Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag,
     92                                 XmlResource* doc) const {
     93   SourcePathDiagnostics source_diag(doc->file.source, diag);
     94 
     95   Element* el = doc->root.get();
     96   if (!el) {
     97     if (policy == XmlActionExecutorPolicy::kWhitelist) {
     98       source_diag.Error(DiagMessage() << "no root XML tag found");
     99       return false;
    100     }
    101     return true;
    102   }
    103 
    104   if (el->namespace_uri.empty()) {
    105     std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(el->name);
    106     if (iter != map_.end()) {
    107       std::vector<StringPiece> bread_crumb;
    108       bread_crumb.push_back(iter->first);
    109       return iter->second.Execute(policy, &bread_crumb, &source_diag, el);
    110     }
    111 
    112     if (policy == XmlActionExecutorPolicy::kWhitelist) {
    113       DiagMessage error_msg(el->line_number);
    114       error_msg << "unexpected root element ";
    115       PrintElementToDiagMessage(el, &error_msg);
    116       source_diag.Error(error_msg);
    117       return false;
    118     }
    119   }
    120   return true;
    121 }
    122 
    123 }  // namespace xml
    124 }  // namespace aapt
    125