Home | History | Annotate | Download | only in url
      1 // Copyright 2013 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 "url/url_canon_internal.h"
      6 
      7 #include <errno.h>
      8 #include <stdlib.h>
      9 
     10 #include <cstdio>
     11 #include <string>
     12 
     13 #include "base/strings/utf_string_conversion_utils.h"
     14 
     15 namespace url {
     16 
     17 namespace {
     18 
     19 template<typename CHAR, typename UCHAR>
     20 void DoAppendStringOfType(const CHAR* source, int length,
     21                           SharedCharTypes type,
     22                           CanonOutput* output) {
     23   for (int i = 0; i < length; i++) {
     24     if (static_cast<UCHAR>(source[i]) >= 0x80) {
     25       // ReadChar will fill the code point with kUnicodeReplacementCharacter
     26       // when the input is invalid, which is what we want.
     27       unsigned code_point;
     28       ReadUTFChar(source, &i, length, &code_point);
     29       AppendUTF8EscapedValue(code_point, output);
     30     } else {
     31       // Just append the 7-bit character, possibly escaping it.
     32       unsigned char uch = static_cast<unsigned char>(source[i]);
     33       if (!IsCharOfType(uch, type))
     34         AppendEscapedChar(uch, output);
     35       else
     36         output->push_back(uch);
     37     }
     38   }
     39 }
     40 
     41 // This function assumes the input values are all contained in 8-bit,
     42 // although it allows any type. Returns true if input is valid, false if not.
     43 template<typename CHAR, typename UCHAR>
     44 void DoAppendInvalidNarrowString(const CHAR* spec, int begin, int end,
     45                                  CanonOutput* output) {
     46   for (int i = begin; i < end; i++) {
     47     UCHAR uch = static_cast<UCHAR>(spec[i]);
     48     if (uch >= 0x80) {
     49       // Handle UTF-8/16 encodings. This call will correctly handle the error
     50       // case by appending the invalid character.
     51       AppendUTF8EscapedChar(spec, &i, end, output);
     52     } else if (uch <= ' ' || uch == 0x7f) {
     53       // This function is for error handling, so we escape all control
     54       // characters and spaces, but not anything else since we lack
     55       // context to do something more specific.
     56       AppendEscapedChar(static_cast<unsigned char>(uch), output);
     57     } else {
     58       output->push_back(static_cast<char>(uch));
     59     }
     60   }
     61 }
     62 
     63 // Overrides one component, see the Replacements structure for
     64 // what the various combionations of source pointer and component mean.
     65 void DoOverrideComponent(const char* override_source,
     66                          const Component& override_component,
     67                          const char** dest,
     68                          Component* dest_component) {
     69   if (override_source) {
     70     *dest = override_source;
     71     *dest_component = override_component;
     72   }
     73 }
     74 
     75 // Similar to DoOverrideComponent except that it takes a UTF-16 input and does
     76 // not actually set the output character pointer.
     77 //
     78 // The input is converted to UTF-8 at the end of the given buffer as a temporary
     79 // holding place. The component identifying the portion of the buffer used in
     80 // the |utf8_buffer| will be specified in |*dest_component|.
     81 //
     82 // This will not actually set any |dest| pointer like DoOverrideComponent
     83 // does because all of the pointers will point into the |utf8_buffer|, which
     84 // may get resized while we're overriding a subsequent component. Instead, the
     85 // caller should use the beginning of the |utf8_buffer| as the string pointer
     86 // for all components once all overrides have been prepared.
     87 bool PrepareUTF16OverrideComponent(const base::char16* override_source,
     88                                    const Component& override_component,
     89                                    CanonOutput* utf8_buffer,
     90                                    Component* dest_component) {
     91   bool success = true;
     92   if (override_source) {
     93     if (!override_component.is_valid()) {
     94       // Non-"valid" component (means delete), so we need to preserve that.
     95       *dest_component = Component();
     96     } else {
     97       // Convert to UTF-8.
     98       dest_component->begin = utf8_buffer->length();
     99       success = ConvertUTF16ToUTF8(&override_source[override_component.begin],
    100                                    override_component.len, utf8_buffer);
    101       dest_component->len = utf8_buffer->length() - dest_component->begin;
    102     }
    103   }
    104   return success;
    105 }
    106 
    107 }  // namespace
    108 
    109 // See the header file for this array's declaration.
    110 const unsigned char kSharedCharTypeTable[0x100] = {
    111     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0x00 - 0x0f
    112     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0x10 - 0x1f
    113     0,                           // 0x20  ' ' (escape spaces in queries)
    114     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x21  !
    115     0,                           // 0x22  "
    116     0,                           // 0x23  #  (invalid in query since it marks the ref)
    117     CHAR_QUERY | CHAR_USERINFO,  // 0x24  $
    118     CHAR_QUERY | CHAR_USERINFO,  // 0x25  %
    119     CHAR_QUERY | CHAR_USERINFO,  // 0x26  &
    120     0,                           // 0x27  '  (Try to prevent XSS.)
    121     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x28  (
    122     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x29  )
    123     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x2a  *
    124     CHAR_QUERY | CHAR_USERINFO,  // 0x2b  +
    125     CHAR_QUERY | CHAR_USERINFO,  // 0x2c  ,
    126     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x2d  -
    127     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_COMPONENT,  // 0x2e  .
    128     CHAR_QUERY,                  // 0x2f  /
    129     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_DEC | CHAR_OCT | CHAR_COMPONENT,  // 0x30  0
    130     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_DEC | CHAR_OCT | CHAR_COMPONENT,  // 0x31  1
    131     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_DEC | CHAR_OCT | CHAR_COMPONENT,  // 0x32  2
    132     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_DEC | CHAR_OCT | CHAR_COMPONENT,  // 0x33  3
    133     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_DEC | CHAR_OCT | CHAR_COMPONENT,  // 0x34  4
    134     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_DEC | CHAR_OCT | CHAR_COMPONENT,  // 0x35  5
    135     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_DEC | CHAR_OCT | CHAR_COMPONENT,  // 0x36  6
    136     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_DEC | CHAR_OCT | CHAR_COMPONENT,  // 0x37  7
    137     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_DEC | CHAR_COMPONENT,             // 0x38  8
    138     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_DEC | CHAR_COMPONENT,             // 0x39  9
    139     CHAR_QUERY,  // 0x3a  :
    140     CHAR_QUERY,  // 0x3b  ;
    141     0,           // 0x3c  <  (Try to prevent certain types of XSS.)
    142     CHAR_QUERY,  // 0x3d  =
    143     0,           // 0x3e  >  (Try to prevent certain types of XSS.)
    144     CHAR_QUERY,  // 0x3f  ?
    145     CHAR_QUERY,  // 0x40  @
    146     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x41  A
    147     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x42  B
    148     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x43  C
    149     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x44  D
    150     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x45  E
    151     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x46  F
    152     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x47  G
    153     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x48  H
    154     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x49  I
    155     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x4a  J
    156     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x4b  K
    157     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x4c  L
    158     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x4d  M
    159     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x4e  N
    160     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x4f  O
    161     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x50  P
    162     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x51  Q
    163     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x52  R
    164     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x53  S
    165     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x54  T
    166     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x55  U
    167     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x56  V
    168     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x57  W
    169     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_COMPONENT, // 0x58  X
    170     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x59  Y
    171     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x5a  Z
    172     CHAR_QUERY,  // 0x5b  [
    173     CHAR_QUERY,  // 0x5c  '\'
    174     CHAR_QUERY,  // 0x5d  ]
    175     CHAR_QUERY,  // 0x5e  ^
    176     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x5f  _
    177     CHAR_QUERY,  // 0x60  `
    178     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x61  a
    179     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x62  b
    180     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x63  c
    181     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x64  d
    182     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x65  e
    183     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_HEX | CHAR_COMPONENT,  // 0x66  f
    184     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x67  g
    185     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x68  h
    186     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x69  i
    187     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x6a  j
    188     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x6b  k
    189     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x6c  l
    190     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x6d  m
    191     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x6e  n
    192     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x6f  o
    193     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x70  p
    194     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x71  q
    195     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x72  r
    196     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x73  s
    197     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x74  t
    198     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x75  u
    199     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x76  v
    200     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x77  w
    201     CHAR_QUERY | CHAR_USERINFO | CHAR_IPV4 | CHAR_COMPONENT,  // 0x78  x
    202     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x79  y
    203     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x7a  z
    204     CHAR_QUERY,  // 0x7b  {
    205     CHAR_QUERY,  // 0x7c  |
    206     CHAR_QUERY,  // 0x7d  }
    207     CHAR_QUERY | CHAR_USERINFO | CHAR_COMPONENT,  // 0x7e  ~
    208     0,           // 0x7f
    209     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0x80 - 0x8f
    210     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0x90 - 0x9f
    211     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0xa0 - 0xaf
    212     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0xb0 - 0xbf
    213     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0xc0 - 0xcf
    214     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0xd0 - 0xdf
    215     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0xe0 - 0xef
    216     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0xf0 - 0xff
    217 };
    218 
    219 const char kHexCharLookup[0x10] = {
    220     '0', '1', '2', '3', '4', '5', '6', '7',
    221     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
    222 };
    223 
    224 const char kCharToHexLookup[8] = {
    225     0,         // 0x00 - 0x1f
    226     '0',       // 0x20 - 0x3f: digits 0 - 9 are 0x30 - 0x39
    227     'A' - 10,  // 0x40 - 0x5f: letters A - F are 0x41 - 0x46
    228     'a' - 10,  // 0x60 - 0x7f: letters a - f are 0x61 - 0x66
    229     0,         // 0x80 - 0x9F
    230     0,         // 0xA0 - 0xBF
    231     0,         // 0xC0 - 0xDF
    232     0,         // 0xE0 - 0xFF
    233 };
    234 
    235 const base::char16 kUnicodeReplacementCharacter = 0xfffd;
    236 
    237 void AppendStringOfType(const char* source, int length,
    238                         SharedCharTypes type,
    239                         CanonOutput* output) {
    240   DoAppendStringOfType<char, unsigned char>(source, length, type, output);
    241 }
    242 
    243 void AppendStringOfType(const base::char16* source, int length,
    244                         SharedCharTypes type,
    245                         CanonOutput* output) {
    246   DoAppendStringOfType<base::char16, base::char16>(
    247       source, length, type, output);
    248 }
    249 
    250 bool ReadUTFChar(const char* str, int* begin, int length,
    251                  unsigned* code_point_out) {
    252   // This depends on ints and int32s being the same thing.  If they're not, it
    253   // will fail to compile.
    254   // TODO(mmenke):  This should probably be fixed.
    255   if (!base::ReadUnicodeCharacter(str, length, begin, code_point_out) ||
    256       !base::IsValidCharacter(*code_point_out)) {
    257     *code_point_out = kUnicodeReplacementCharacter;
    258     return false;
    259   }
    260   return true;
    261 }
    262 
    263 bool ReadUTFChar(const base::char16* str, int* begin, int length,
    264                  unsigned* code_point_out) {
    265   // This depends on ints and int32s being the same thing.  If they're not, it
    266   // will fail to compile.
    267   // TODO(mmenke):  This should probably be fixed.
    268   if (!base::ReadUnicodeCharacter(str, length, begin, code_point_out) ||
    269       !base::IsValidCharacter(*code_point_out)) {
    270     *code_point_out = kUnicodeReplacementCharacter;
    271     return false;
    272   }
    273   return true;
    274 }
    275 
    276 void AppendInvalidNarrowString(const char* spec, int begin, int end,
    277                                CanonOutput* output) {
    278   DoAppendInvalidNarrowString<char, unsigned char>(spec, begin, end, output);
    279 }
    280 
    281 void AppendInvalidNarrowString(const base::char16* spec, int begin, int end,
    282                                CanonOutput* output) {
    283   DoAppendInvalidNarrowString<base::char16, base::char16>(
    284       spec, begin, end, output);
    285 }
    286 
    287 bool ConvertUTF16ToUTF8(const base::char16* input, int input_len,
    288                         CanonOutput* output) {
    289   bool success = true;
    290   for (int i = 0; i < input_len; i++) {
    291     unsigned code_point;
    292     success &= ReadUTFChar(input, &i, input_len, &code_point);
    293     AppendUTF8Value(code_point, output);
    294   }
    295   return success;
    296 }
    297 
    298 bool ConvertUTF8ToUTF16(const char* input, int input_len,
    299                         CanonOutputT<base::char16>* output) {
    300   bool success = true;
    301   for (int i = 0; i < input_len; i++) {
    302     unsigned code_point;
    303     success &= ReadUTFChar(input, &i, input_len, &code_point);
    304     AppendUTF16Value(code_point, output);
    305   }
    306   return success;
    307 }
    308 
    309 void SetupOverrideComponents(const char* base,
    310                              const Replacements<char>& repl,
    311                              URLComponentSource<char>* source,
    312                              Parsed* parsed) {
    313   // Get the source and parsed structures of the things we are replacing.
    314   const URLComponentSource<char>& repl_source = repl.sources();
    315   const Parsed& repl_parsed = repl.components();
    316 
    317   DoOverrideComponent(repl_source.scheme, repl_parsed.scheme,
    318                       &source->scheme, &parsed->scheme);
    319   DoOverrideComponent(repl_source.username, repl_parsed.username,
    320                       &source->username, &parsed->username);
    321   DoOverrideComponent(repl_source.password, repl_parsed.password,
    322                       &source->password, &parsed->password);
    323 
    324   // Our host should be empty if not present, so override the default setup.
    325   DoOverrideComponent(repl_source.host, repl_parsed.host,
    326                       &source->host, &parsed->host);
    327   if (parsed->host.len == -1)
    328     parsed->host.len = 0;
    329 
    330   DoOverrideComponent(repl_source.port, repl_parsed.port,
    331                       &source->port, &parsed->port);
    332   DoOverrideComponent(repl_source.path, repl_parsed.path,
    333                       &source->path, &parsed->path);
    334   DoOverrideComponent(repl_source.query, repl_parsed.query,
    335                       &source->query, &parsed->query);
    336   DoOverrideComponent(repl_source.ref, repl_parsed.ref,
    337                       &source->ref, &parsed->ref);
    338 }
    339 
    340 bool SetupUTF16OverrideComponents(const char* base,
    341                                   const Replacements<base::char16>& repl,
    342                                   CanonOutput* utf8_buffer,
    343                                   URLComponentSource<char>* source,
    344                                   Parsed* parsed) {
    345   bool success = true;
    346 
    347   // Get the source and parsed structures of the things we are replacing.
    348   const URLComponentSource<base::char16>& repl_source = repl.sources();
    349   const Parsed& repl_parsed = repl.components();
    350 
    351   success &= PrepareUTF16OverrideComponent(
    352       repl_source.scheme, repl_parsed.scheme,
    353       utf8_buffer, &parsed->scheme);
    354   success &= PrepareUTF16OverrideComponent(
    355       repl_source.username, repl_parsed.username,
    356       utf8_buffer, &parsed->username);
    357   success &= PrepareUTF16OverrideComponent(
    358       repl_source.password, repl_parsed.password,
    359       utf8_buffer, &parsed->password);
    360   success &= PrepareUTF16OverrideComponent(
    361       repl_source.host, repl_parsed.host,
    362       utf8_buffer, &parsed->host);
    363   success &= PrepareUTF16OverrideComponent(
    364       repl_source.port, repl_parsed.port,
    365       utf8_buffer, &parsed->port);
    366   success &= PrepareUTF16OverrideComponent(
    367       repl_source.path, repl_parsed.path,
    368       utf8_buffer, &parsed->path);
    369   success &= PrepareUTF16OverrideComponent(
    370       repl_source.query, repl_parsed.query,
    371       utf8_buffer, &parsed->query);
    372   success &= PrepareUTF16OverrideComponent(
    373       repl_source.ref, repl_parsed.ref,
    374       utf8_buffer, &parsed->ref);
    375 
    376   // PrepareUTF16OverrideComponent will not have set the data pointer since the
    377   // buffer could be resized, invalidating the pointers. We set the data
    378   // pointers for affected components now that the buffer is finalized.
    379   if (repl_source.scheme)   source->scheme = utf8_buffer->data();
    380   if (repl_source.username) source->username = utf8_buffer->data();
    381   if (repl_source.password) source->password = utf8_buffer->data();
    382   if (repl_source.host)     source->host = utf8_buffer->data();
    383   if (repl_source.port)     source->port = utf8_buffer->data();
    384   if (repl_source.path)     source->path = utf8_buffer->data();
    385   if (repl_source.query)    source->query = utf8_buffer->data();
    386   if (repl_source.ref)      source->ref = utf8_buffer->data();
    387 
    388   return success;
    389 }
    390 
    391 #ifndef WIN32
    392 
    393 int _itoa_s(int value, char* buffer, size_t size_in_chars, int radix) {
    394   const char* format_str;
    395   if (radix == 10)
    396     format_str = "%d";
    397   else if (radix == 16)
    398     format_str = "%x";
    399   else
    400     return EINVAL;
    401 
    402   int written = snprintf(buffer, size_in_chars, format_str, value);
    403   if (static_cast<size_t>(written) >= size_in_chars) {
    404     // Output was truncated, or written was negative.
    405     return EINVAL;
    406   }
    407   return 0;
    408 }
    409 
    410 int _itow_s(int value, base::char16* buffer, size_t size_in_chars, int radix) {
    411   if (radix != 10)
    412     return EINVAL;
    413 
    414   // No more than 12 characters will be required for a 32-bit integer.
    415   // Add an extra byte for the terminating null.
    416   char temp[13];
    417   int written = snprintf(temp, sizeof(temp), "%d", value);
    418   if (static_cast<size_t>(written) >= size_in_chars) {
    419     // Output was truncated, or written was negative.
    420     return EINVAL;
    421   }
    422 
    423   for (int i = 0; i < written; ++i) {
    424     buffer[i] = static_cast<base::char16>(temp[i]);
    425   }
    426   buffer[written] = '\0';
    427   return 0;
    428 }
    429 
    430 #endif  // !WIN32
    431 
    432 }  // namespace url
    433