// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_BASE_PARSE_NUMBER_H_
#define NET_BASE_PARSE_NUMBER_H_

#include "base/compiler_specific.h"
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"

// This file contains utility functions for parsing numbers, in the context of
// network protocols.
//
// Q: Doesn't //base already provide these in string_number_conversions.h, with
//    functions like base::StringToInt()?
//
// A: Yes, and those functions are used under the hood by these implementations.
//
//    However using the base::StringTo*() has historically led to subtle bugs
//    in the context of parsing network protocols:
//
//      * Permitting a leading '+'
//      * Incorrectly classifying overflow/underflow from a parsing failure
//      * Allowing negative numbers for non-negative fields
//
//   This API tries to avoid these problems by picking sensible defaults for
//   //net code. For more details see crbug.com/596523.

namespace net {

// Format to use when parsing integers.
enum class ParseIntFormat {
  // Accepts non-negative base 10 integers of the form:
  //
  //    1*DIGIT
  //
  // This construction is used in a variety of IETF standards, such as RFC 7230
  // (HTTP).
  //
  // When attempting to parse a negative number using this format, the failure
  // will be FAILED_PARSE since it violated the expected format (and not
  // FAILED_UNDERFLOW).
  //
  // Also note that inputs need not be in minimal encoding: "0003" is valid and
  // equivalent to "3".
  NON_NEGATIVE,

  // Accept optionally negative base 10 integers of the form:
  //
  //    ["-"] 1*DIGIT
  //
  // In other words, this accepts the same things as NON_NEGATIVE, and
  // additionally recognizes those numbers prefixed with a '-'.
  //
  // Note that by this defintion "-0" IS a valid input.
  OPTIONALLY_NEGATIVE
};

// The specific reason why a ParseInt*() function failed.
enum class ParseIntError {
  // The parsed number couldn't fit into the provided output type because it was
  // too high.
  FAILED_OVERFLOW,

  // The parsed number couldn't fit into the provided output type because it was
  // too low.
  FAILED_UNDERFLOW,

  // The number failed to be parsed because it wasn't a valid decimal number (as
  // determined by the policy).
  FAILED_PARSE,
};

// The ParseInt*() functions parse a string representing a number.
//
// The format of the strings that are accepted is controlled by the |format|
// parameter. This allows rejecting negative numbers.
//
// These functions return true on success, and fill |*output| with the result.
//
// On failure, it is guaranteed that |*output| was not modified. If
// |optional_error| was non-null, then it is filled with the reason for the
// failure.
NET_EXPORT bool ParseInt32(const base::StringPiece& input,
                           ParseIntFormat format,
                           int32_t* output,
                           ParseIntError* optional_error = nullptr)
    WARN_UNUSED_RESULT;

NET_EXPORT bool ParseInt64(const base::StringPiece& input,
                           ParseIntFormat format,
                           int64_t* output,
                           ParseIntError* optional_error = nullptr)
    WARN_UNUSED_RESULT;

// The ParseUint*() functions parse a string representing a number.
//
// These are equivalent to calling ParseInt*() with a format string of
// ParseIntFormat::NON_NEGATIVE and unsigned output types.
NET_EXPORT bool ParseUint32(const base::StringPiece& input,
                            uint32_t* output,
                            ParseIntError* optional_error = nullptr)
    WARN_UNUSED_RESULT;

NET_EXPORT bool ParseUint64(const base::StringPiece& input,
                            uint64_t* output,
                            ParseIntError* optional_error = nullptr)
    WARN_UNUSED_RESULT;

}  // namespace net

#endif  // NET_BASE_PARSE_NUMBER_H_
