1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/autofill/autofill_xml_parser.h"
6
7#include <stdlib.h>
8#include <string.h>
9
10#include "base/logging.h"
11#include "third_party/libjingle/overrides/talk/xmllite/qname.h"
12
13AutofillXmlParser::AutofillXmlParser()
14    : succeeded_(true) {
15}
16
17void AutofillXmlParser::CharacterData(
18    buzz::XmlParseContext* context, const char* text, int len) {
19}
20
21void AutofillXmlParser::EndElement(buzz::XmlParseContext* context,
22                                   const char* name) {
23}
24
25void AutofillXmlParser::Error(buzz::XmlParseContext* context,
26                              XML_Error error_code) {
27  succeeded_ = false;
28}
29
30AutofillQueryXmlParser::AutofillQueryXmlParser(
31    std::vector<AutofillFieldType>* field_types,
32    UploadRequired* upload_required,
33    std::string* experiment_id)
34    : field_types_(field_types),
35      upload_required_(upload_required),
36      experiment_id_(experiment_id) {
37  DCHECK(upload_required_);
38  DCHECK(experiment_id_);
39}
40
41void AutofillQueryXmlParser::StartElement(buzz::XmlParseContext* context,
42                                          const char* name,
43                                          const char** attrs) {
44  buzz::QName qname = context->ResolveQName(name, false);
45  const std::string& element = qname.LocalPart();
46  if (element.compare("autofillqueryresponse") == 0) {
47    // We check for the upload required attribute below, but if it's not
48    // present, we use the default upload rates. Likewise, by default we assume
49    // an empty experiment id.
50    *upload_required_ = USE_UPLOAD_RATES;
51    *experiment_id_ = std::string();
52
53    // |attrs| is a NULL-terminated list of (attribute, value) pairs.
54    while (*attrs) {
55      buzz::QName attribute_qname = context->ResolveQName(attrs[0], true);
56      const std::string& attribute_name = attribute_qname.LocalPart();
57      if (attribute_name.compare("uploadrequired") == 0) {
58        if (strcmp(attrs[1], "true") == 0)
59          *upload_required_ = UPLOAD_REQUIRED;
60        else if (strcmp(attrs[1], "false") == 0)
61          *upload_required_ = UPLOAD_NOT_REQUIRED;
62      } else if (attribute_name.compare("experimentid") == 0) {
63        *experiment_id_ = attrs[1];
64      }
65
66      // Advance to the next (attribute, value) pair.
67      attrs += 2;
68    }
69  } else if (element.compare("field") == 0) {
70    if (!attrs[0]) {
71      // Missing the "autofilltype" attribute, abort.
72      context->RaiseError(XML_ERROR_ABORTED);
73      return;
74    }
75
76    // Determine the field type from the attribute value.  There should be one
77    // attribute (autofilltype) with an integer value.
78    AutofillFieldType field_type = UNKNOWN_TYPE;
79    buzz::QName attribute_qname = context->ResolveQName(attrs[0], true);
80    const std::string& attribute_name = attribute_qname.LocalPart();
81
82    if (attribute_name.compare("autofilltype") == 0) {
83      int value = GetIntValue(context, attrs[1]);
84      field_type = static_cast<AutofillFieldType>(value);
85      if (field_type < 0 || field_type > MAX_VALID_FIELD_TYPE) {
86        field_type = NO_SERVER_DATA;
87      }
88    }
89
90    // Record this field type.
91    field_types_->push_back(field_type);
92  }
93}
94
95int AutofillQueryXmlParser::GetIntValue(buzz::XmlParseContext* context,
96                                        const char* attribute) {
97  char* attr_end = NULL;
98  int value = strtol(attribute, &attr_end, 10);
99  if (attr_end != NULL && attr_end == attribute) {
100    context->RaiseError(XML_ERROR_SYNTAX);
101    return 0;
102  }
103  return value;
104}
105
106AutofillUploadXmlParser::AutofillUploadXmlParser(double* positive_upload_rate,
107                                                 double* negative_upload_rate)
108    : succeeded_(false),
109      positive_upload_rate_(positive_upload_rate),
110      negative_upload_rate_(negative_upload_rate) {
111  DCHECK(positive_upload_rate_);
112  DCHECK(negative_upload_rate_);
113}
114
115void AutofillUploadXmlParser::StartElement(buzz::XmlParseContext* context,
116                                           const char* name,
117                                           const char** attrs) {
118  buzz::QName qname = context->ResolveQName(name, false);
119  const std::string &element = qname.LocalPart();
120  if (element.compare("autofilluploadresponse") == 0) {
121    // Loop over all attributes to get the upload rates.
122    while (*attrs) {
123      buzz::QName attribute_qname = context->ResolveQName(attrs[0], true);
124      const std::string &attribute_name = attribute_qname.LocalPart();
125      if (attribute_name.compare("positiveuploadrate") == 0) {
126        *positive_upload_rate_ = GetDoubleValue(context, attrs[1]);
127      } else if (attribute_name.compare("negativeuploadrate") == 0) {
128        *negative_upload_rate_ = GetDoubleValue(context, attrs[1]);
129      }
130      attrs += 2;  // We peeked at attrs[0] and attrs[1], skip past both.
131    }
132  }
133}
134
135double AutofillUploadXmlParser::GetDoubleValue(buzz::XmlParseContext* context,
136                                               const char* attribute) {
137  char* attr_end = NULL;
138  double value = strtod(attribute, &attr_end);
139  if (attr_end != NULL && attr_end == attribute) {
140    context->RaiseError(XML_ERROR_SYNTAX);
141    return 0.0;
142  }
143  return value;
144}
145