1f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org/*
2f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *
4f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
5f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
6f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
7f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
8f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org */
10f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
11f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/stringencode.h"
12f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
13f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <stdio.h>
14f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <stdlib.h>
15f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
16f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/basictypes.h"
176ae5a6d7fefff6759d338b5a3e3613e050ebaa62andrew@webrtc.org#include "webrtc/base/checks.h"
18f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/stringutils.h"
19f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
20f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgnamespace rtc {
21f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
22f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org/////////////////////////////////////////////////////////////////////////////
23f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org// String Encoding Utilities
24f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org/////////////////////////////////////////////////////////////////////////////
25f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
26f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t escape(char * buffer, size_t buflen,
27f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org              const char * source, size_t srclen,
28f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org              const char * illegal, char escape) {
2991d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(buffer);  // TODO(grunell): estimate output size
30f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen <= 0)
31f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
32f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
33f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t srcpos = 0, bufpos = 0;
34f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
35f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    char ch = source[srcpos++];
36f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if ((ch == escape) || ::strchr(illegal, ch)) {
37f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (bufpos + 2 >= buflen)
38f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        break;
39f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = escape;
40f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
41f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[bufpos++] = ch;
42f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
43f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
44f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffer[bufpos] = '\0';
45f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return bufpos;
46f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
47f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
48f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t unescape(char * buffer, size_t buflen,
49f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                const char * source, size_t srclen,
50f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                char escape) {
5191d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(buffer);  // TODO(grunell): estimate output size
52f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen <= 0)
53f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
54f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
55f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t srcpos = 0, bufpos = 0;
56f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
57f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    char ch = source[srcpos++];
58f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if ((ch == escape) && (srcpos < srclen)) {
59f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      ch = source[srcpos++];
60f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
61f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[bufpos++] = ch;
62f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
63f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffer[bufpos] = '\0';
64f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return bufpos;
65f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
66f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
67f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t encode(char * buffer, size_t buflen,
68f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org              const char * source, size_t srclen,
69f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org              const char * illegal, char escape) {
7091d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(buffer);  // TODO(grunell): estimate output size
71f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen <= 0)
72f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
73f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
74f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t srcpos = 0, bufpos = 0;
75f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
76f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    char ch = source[srcpos++];
77f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if ((ch != escape) && !::strchr(illegal, ch)) {
78f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = ch;
79f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if (bufpos + 3 >= buflen) {
80f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      break;
81f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else {
82f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos+0] = escape;
83f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos+1] = hex_encode((static_cast<unsigned char>(ch) >> 4) & 0xF);
84f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos+2] = hex_encode((static_cast<unsigned char>(ch)     ) & 0xF);
85f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      bufpos += 3;
86f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
87f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
88f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffer[bufpos] = '\0';
89f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return bufpos;
90f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
91f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
92f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t decode(char * buffer, size_t buflen,
93f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org              const char * source, size_t srclen,
94f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org              char escape) {
95f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen <= 0)
96f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
97f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
98f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  unsigned char h1, h2;
99f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t srcpos = 0, bufpos = 0;
100f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
101f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    char ch = source[srcpos++];
102f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if ((ch == escape)
103f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        && (srcpos + 1 < srclen)
104f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        && hex_decode(source[srcpos], &h1)
105f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        && hex_decode(source[srcpos+1], &h2)) {
106f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = (h1 << 4) | h2;
107f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      srcpos += 2;
108f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else {
109f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = ch;
110f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
111f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
112f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffer[bufpos] = '\0';
113f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return bufpos;
114f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
115f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
116f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgconst char* unsafe_filename_characters() {
117f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // It might be better to have a single specification which is the union of
118f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // all operating systems, unless one system is overly restrictive.
119f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#if defined(WEBRTC_WIN)
120f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return "\\/:*?\"<>|";
1216ae5a6d7fefff6759d338b5a3e3613e050ebaa62andrew@webrtc.org#else  // !WEBRTC_WIN
12291d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  // TODO(grunell): Should this never be reached?
12391d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(false);
124f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return "";
125f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#endif  // !WEBRTC_WIN
126f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
127f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
128f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgconst unsigned char URL_UNSAFE  = 0x1; // 0-33 "#$%&+,/:;<=>?@[\]^`{|} 127
129f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgconst unsigned char XML_UNSAFE  = 0x2; // "&'<>
130f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgconst unsigned char HTML_UNSAFE = 0x2; // "&'<>
131f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
132f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org//  ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 6 5 7 8 9 : ; < = > ?
133f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org//@ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _
134f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org//` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
135f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
136f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgconst unsigned char ASCII_CLASS[128] = {
137f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
138f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  1,0,3,1,1,1,3,2,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,3,1,3,1,
139f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,
140f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,
141f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org};
142f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
143f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t url_encode(char * buffer, size_t buflen,
144f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                  const char * source, size_t srclen) {
145f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (NULL == buffer)
146f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return srclen * 3 + 1;
147f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen <= 0)
148f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
149f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
150f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t srcpos = 0, bufpos = 0;
151f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
152f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    unsigned char ch = source[srcpos++];
153f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if ((ch < 128) && (ASCII_CLASS[ch] & URL_UNSAFE)) {
154f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (bufpos + 3 >= buflen) {
155f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        break;
156f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
157f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos+0] = '%';
158f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos+1] = hex_encode((ch >> 4) & 0xF);
159f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos+2] = hex_encode((ch     ) & 0xF);
160f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      bufpos += 3;
161f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else {
162f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = ch;
163f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
164f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
165f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffer[bufpos] = '\0';
166f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return bufpos;
167f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
168f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
169f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t url_decode(char * buffer, size_t buflen,
170f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                  const char * source, size_t srclen) {
171f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (NULL == buffer)
172f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return srclen + 1;
173f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen <= 0)
174f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
175f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
176f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  unsigned char h1, h2;
177f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t srcpos = 0, bufpos = 0;
178f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
179f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    unsigned char ch = source[srcpos++];
180f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (ch == '+') {
181f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = ' ';
182f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if ((ch == '%')
183f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org               && (srcpos + 1 < srclen)
184f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org               && hex_decode(source[srcpos], &h1)
185f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org               && hex_decode(source[srcpos+1], &h2))
186f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    {
187f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = (h1 << 4) | h2;
188f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      srcpos += 2;
189f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else {
190f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = ch;
191f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
192f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
193f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffer[bufpos] = '\0';
194f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return bufpos;
195f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
196f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
197f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t utf8_decode(const char* source, size_t srclen, unsigned long* value) {
198f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  const unsigned char* s = reinterpret_cast<const unsigned char*>(source);
199f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((s[0] & 0x80) == 0x00) {                    // Check s[0] == 0xxxxxxx
200f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    *value = s[0];
201f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 1;
202f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
203f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((srclen < 2) || ((s[1] & 0xC0) != 0x80)) {  // Check s[1] != 10xxxxxx
204f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
205f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
206f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Accumulate the trailer byte values in value16, and combine it with the
207f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // relevant bits from s[0], once we've determined the sequence length.
208f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  unsigned long value16 = (s[1] & 0x3F);
209f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((s[0] & 0xE0) == 0xC0) {                    // Check s[0] == 110xxxxx
210f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    *value = ((s[0] & 0x1F) << 6) | value16;
211f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 2;
212f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
213f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((srclen < 3) || ((s[2] & 0xC0) != 0x80)) {  // Check s[2] != 10xxxxxx
214f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
215f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
216f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  value16 = (value16 << 6) | (s[2] & 0x3F);
217f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((s[0] & 0xF0) == 0xE0) {                    // Check s[0] == 1110xxxx
218f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    *value = ((s[0] & 0x0F) << 12) | value16;
219f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 3;
220f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
221f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((srclen < 4) || ((s[3] & 0xC0) != 0x80)) {  // Check s[3] != 10xxxxxx
222f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
223f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
224f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  value16 = (value16 << 6) | (s[3] & 0x3F);
225f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((s[0] & 0xF8) == 0xF0) {                    // Check s[0] == 11110xxx
226f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    *value = ((s[0] & 0x07) << 18) | value16;
227f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 4;
228f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
229f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return 0;
230f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
231f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
232f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t utf8_encode(char* buffer, size_t buflen, unsigned long value) {
233f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((value <= 0x7F) && (buflen >= 1)) {
234f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[0] = static_cast<unsigned char>(value);
235f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 1;
236f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
237f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((value <= 0x7FF) && (buflen >= 2)) {
238f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[0] = 0xC0 | static_cast<unsigned char>(value >> 6);
239f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[1] = 0x80 | static_cast<unsigned char>(value & 0x3F);
240f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 2;
241f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
242f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((value <= 0xFFFF) && (buflen >= 3)) {
243f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[0] = 0xE0 | static_cast<unsigned char>(value >> 12);
244f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[1] = 0x80 | static_cast<unsigned char>((value >> 6) & 0x3F);
245f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[2] = 0x80 | static_cast<unsigned char>(value & 0x3F);
246f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 3;
247f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
248f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((value <= 0x1FFFFF) && (buflen >= 4)) {
249f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[0] = 0xF0 | static_cast<unsigned char>(value >> 18);
250f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[1] = 0x80 | static_cast<unsigned char>((value >> 12) & 0x3F);
251f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[2] = 0x80 | static_cast<unsigned char>((value >> 6) & 0x3F);
252f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[3] = 0x80 | static_cast<unsigned char>(value & 0x3F);
253f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 4;
254f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
255f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return 0;
256f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
257f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
258f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t html_encode(char * buffer, size_t buflen,
259f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                   const char * source, size_t srclen) {
26091d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(buffer);  // TODO(grunell): estimate output size
261f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen <= 0)
262f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
263f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
264f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t srcpos = 0, bufpos = 0;
265f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
266f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    unsigned char ch = source[srcpos];
267f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (ch < 128) {
268f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      srcpos += 1;
269f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (ASCII_CLASS[ch] & HTML_UNSAFE) {
270f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        const char * escseq = 0;
271f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        size_t esclen = 0;
272f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        switch (ch) {
273f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          case '<':  escseq = "&lt;";   esclen = 4; break;
274f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          case '>':  escseq = "&gt;";   esclen = 4; break;
275f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          case '\'': escseq = "&#39;";  esclen = 5; break;
276f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          case '\"': escseq = "&quot;"; esclen = 6; break;
277f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          case '&':  escseq = "&amp;";  esclen = 5; break;
27891d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg          default: RTC_DCHECK(false);
279f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        }
280f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        if (bufpos + esclen >= buflen) {
281f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          break;
282f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        }
283f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        memcpy(buffer + bufpos, escseq, esclen);
284f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        bufpos += esclen;
285f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      } else {
286f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        buffer[bufpos++] = ch;
287f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
288f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else {
289f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      // Largest value is 0x1FFFFF => &#2097151;  (10 characters)
2906ae5a6d7fefff6759d338b5a3e3613e050ebaa62andrew@webrtc.org      const size_t kEscseqSize = 11;
2916ae5a6d7fefff6759d338b5a3e3613e050ebaa62andrew@webrtc.org      char escseq[kEscseqSize];
292f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      unsigned long val;
293f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (size_t vallen = utf8_decode(&source[srcpos], srclen - srcpos, &val)) {
294f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        srcpos += vallen;
295f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      } else {
296f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        // Not a valid utf8 sequence, just use the raw character.
297f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        val = static_cast<unsigned char>(source[srcpos++]);
298f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
2996ae5a6d7fefff6759d338b5a3e3613e050ebaa62andrew@webrtc.org      size_t esclen = sprintfn(escseq, kEscseqSize, "&#%lu;", val);
300f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (bufpos + esclen >= buflen) {
301f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        break;
302f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
303f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      memcpy(buffer + bufpos, escseq, esclen);
304f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      bufpos += esclen;
305f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
306f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
307f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffer[bufpos] = '\0';
308f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return bufpos;
309f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
310f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
311f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t html_decode(char * buffer, size_t buflen,
312f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                   const char * source, size_t srclen) {
31391d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(buffer);  // TODO(grunell): estimate output size
314f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return xml_decode(buffer, buflen, source, srclen);
315f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
316f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
317f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t xml_encode(char * buffer, size_t buflen,
318f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                  const char * source, size_t srclen) {
31991d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(buffer);  // TODO(grunell): estimate output size
320f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen <= 0)
321f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
322f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
323f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t srcpos = 0, bufpos = 0;
324f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
325f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    unsigned char ch = source[srcpos++];
326f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if ((ch < 128) && (ASCII_CLASS[ch] & XML_UNSAFE)) {
327f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      const char * escseq = 0;
328f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      size_t esclen = 0;
329f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      switch (ch) {
330f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        case '<':  escseq = "&lt;";   esclen = 4; break;
331f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        case '>':  escseq = "&gt;";   esclen = 4; break;
332f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        case '\'': escseq = "&apos;"; esclen = 6; break;
333f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        case '\"': escseq = "&quot;"; esclen = 6; break;
334f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        case '&':  escseq = "&amp;";  esclen = 5; break;
33591d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg        default: RTC_DCHECK(false);
336f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
337f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (bufpos + esclen >= buflen) {
338f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        break;
339f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
340f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      memcpy(buffer + bufpos, escseq, esclen);
341f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      bufpos += esclen;
342f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else {
343f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = ch;
344f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
345f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
346f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffer[bufpos] = '\0';
347f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return bufpos;
348f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
349f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
350f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t xml_decode(char * buffer, size_t buflen,
351f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                  const char * source, size_t srclen) {
35291d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(buffer);  // TODO(grunell): estimate output size
353f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen <= 0)
354f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
355f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
356f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t srcpos = 0, bufpos = 0;
357f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
358f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    unsigned char ch = source[srcpos++];
359f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (ch != '&') {
360f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = ch;
361f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if ((srcpos + 2 < srclen)
362f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org               && (memcmp(source + srcpos, "lt;", 3) == 0)) {
363f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = '<';
364f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      srcpos += 3;
365f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if ((srcpos + 2 < srclen)
366f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org               && (memcmp(source + srcpos, "gt;", 3) == 0)) {
367f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = '>';
368f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      srcpos += 3;
369f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if ((srcpos + 4 < srclen)
370f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org               && (memcmp(source + srcpos, "apos;", 5) == 0)) {
371f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = '\'';
372f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      srcpos += 5;
373f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if ((srcpos + 4 < srclen)
374f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org               && (memcmp(source + srcpos, "quot;", 5) == 0)) {
375f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = '\"';
376f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      srcpos += 5;
377f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if ((srcpos + 3 < srclen)
378f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org               && (memcmp(source + srcpos, "amp;", 4) == 0)) {
379f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos++] = '&';
380f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      srcpos += 4;
381f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if ((srcpos < srclen) && (source[srcpos] == '#')) {
382f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      int int_base = 10;
383f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if ((srcpos + 1 < srclen) && (source[srcpos+1] == 'x')) {
384f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        int_base = 16;
385f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        srcpos += 1;
386f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
387f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      char * ptr;
38891d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg      // TODO(grunell): Fix hack (ptr may go past end of data)
389f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      unsigned long val = strtoul(source + srcpos + 1, &ptr, int_base);
390f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if ((static_cast<size_t>(ptr - source) < srclen) && (*ptr == ';')) {
391f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        srcpos = ptr - source + 1;
392f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      } else {
393f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        // Not a valid escape sequence.
394f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        break;
395f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
396f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (size_t esclen = utf8_encode(buffer + bufpos, buflen - bufpos, val)) {
397f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        bufpos += esclen;
398f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      } else {
399f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        // Not enough room to encode the character, or illegal character
400f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        break;
401f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
402f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else {
403f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      // Unrecognized escape sequence.
404f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      break;
405f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
406f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
407f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffer[bufpos] = '\0';
408f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return bufpos;
409f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
410f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
411f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgstatic const char HEX[] = "0123456789abcdef";
412f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
413f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgchar hex_encode(unsigned char val) {
41491d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK_LT(val, 16);
415f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return (val < 16) ? HEX[val] : '!';
416f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
417f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
418f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgbool hex_decode(char ch, unsigned char* val) {
419f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((ch >= '0') && (ch <= '9')) {
420f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    *val = ch - '0';
421f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if ((ch >= 'A') && (ch <= 'Z')) {
422f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    *val = (ch - 'A') + 10;
423f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if ((ch >= 'a') && (ch <= 'z')) {
424f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    *val = (ch - 'a') + 10;
425f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else {
426f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return false;
427f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
428f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return true;
429f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
430f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
431f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t hex_encode(char* buffer, size_t buflen,
432f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                  const char* csource, size_t srclen) {
433f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return hex_encode_with_delimiter(buffer, buflen, csource, srclen, 0);
434f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
435f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
436f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t hex_encode_with_delimiter(char* buffer, size_t buflen,
437f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                 const char* csource, size_t srclen,
438f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                 char delimiter) {
43991d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(buffer);  // TODO(grunell): estimate output size
440f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen == 0)
441f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
442f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
443f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Init and check bounds.
444f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  const unsigned char* bsource =
445f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      reinterpret_cast<const unsigned char*>(csource);
446f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t srcpos = 0, bufpos = 0;
447f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t needed = delimiter ? (srclen * 3) : (srclen * 2 + 1);
448f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen < needed)
449f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
450f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
451f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while (srcpos < srclen) {
452f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    unsigned char ch = bsource[srcpos++];
453f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[bufpos  ] = hex_encode((ch >> 4) & 0xF);
454f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    buffer[bufpos+1] = hex_encode((ch     ) & 0xF);
455f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    bufpos += 2;
456f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
457f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    // Don't write a delimiter after the last byte.
458f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (delimiter && (srcpos < srclen)) {
459f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      buffer[bufpos] = delimiter;
460f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      ++bufpos;
461f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
462f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
463f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
464f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Null terminate.
465f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffer[bufpos] = '\0';
466f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return bufpos;
467f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
468f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
4691cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcherstd::string hex_encode(const std::string& str) {
4701cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  return hex_encode(str.c_str(), str.size());
4711cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher}
4721cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher
473f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgstd::string hex_encode(const char* source, size_t srclen) {
474f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return hex_encode_with_delimiter(source, srclen, 0);
475f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
476f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
477f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgstd::string hex_encode_with_delimiter(const char* source, size_t srclen,
478f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                      char delimiter) {
479f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  const size_t kBufferSize = srclen * 3;
480f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  char* buffer = STACK_ARRAY(char, kBufferSize);
481f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t length = hex_encode_with_delimiter(buffer, kBufferSize,
482f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                            source, srclen, delimiter);
48391d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(srclen == 0 || length > 0);
484f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return std::string(buffer, length);
485f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
486f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
487f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t hex_decode(char * cbuffer, size_t buflen,
488f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                  const char * source, size_t srclen) {
489f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0);
490f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
491f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
492f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t hex_decode_with_delimiter(char* cbuffer, size_t buflen,
493f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                 const char* source, size_t srclen,
494f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                 char delimiter) {
49591d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(cbuffer);  // TODO(grunell): estimate output size
496f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen == 0)
497f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
498f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
499f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Init and bounds check.
500f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer);
501f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t srcpos = 0, bufpos = 0;
502f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
503f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buflen < needed)
504f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return 0;
505f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
506f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while (srcpos < srclen) {
507f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if ((srclen - srcpos) < 2) {
508f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      // This means we have an odd number of bytes.
509f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return 0;
510f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
511f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
512f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    unsigned char h1, h2;
513f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (!hex_decode(source[srcpos], &h1) ||
514f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        !hex_decode(source[srcpos + 1], &h2))
515f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return 0;
516f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
517f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    bbuffer[bufpos++] = (h1 << 4) | h2;
518f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    srcpos += 2;
519f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
520f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    // Remove the delimiter if needed.
521f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (delimiter && (srclen - srcpos) > 1) {
522f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (source[srcpos] != delimiter)
523f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        return 0;
524f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      ++srcpos;
525f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
526f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
527f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
528f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return bufpos;
529f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
530f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
531f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t hex_decode(char* buffer, size_t buflen, const std::string& source) {
532f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return hex_decode_with_delimiter(buffer, buflen, source, 0);
533f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
534f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t hex_decode_with_delimiter(char* buffer, size_t buflen,
535f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                 const std::string& source, char delimiter) {
536f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return hex_decode_with_delimiter(buffer, buflen,
537f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                   source.c_str(), source.length(), delimiter);
538f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
539f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
540f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t transform(std::string& value, size_t maxlen, const std::string& source,
541f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                 Transform t) {
542f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  char* buffer = STACK_ARRAY(char, maxlen + 1);
543f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t length = t(buffer, maxlen + 1, source.data(), source.length());
544f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  value.assign(buffer, length);
545f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return length;
546f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
547f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
548f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgstd::string s_transform(const std::string& source, Transform t) {
549f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Ask transformation function to approximate the destination size (returns upper bound)
550f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t maxlen = t(NULL, 0, source.data(), source.length());
551f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  char * buffer = STACK_ARRAY(char, maxlen);
552f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t len = t(buffer, maxlen, source.data(), source.length());
553f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  std::string result(buffer, len);
554f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return result;
555f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
556f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
557f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t tokenize(const std::string& source, char delimiter,
558f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                std::vector<std::string>* fields) {
559f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  fields->clear();
560f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t last = 0;
561f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  for (size_t i = 0; i < source.length(); ++i) {
562f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (source[i] == delimiter) {
563f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (i != last) {
564f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        fields->push_back(source.substr(last, i - last));
565f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
566f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      last = i + 1;
567f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
568f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
569f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (last != source.length()) {
570f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    fields->push_back(source.substr(last, source.length() - last));
571f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
572f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return fields->size();
573f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
574f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
5750a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeefsize_t tokenize_with_empty_tokens(const std::string& source,
5760a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef                                  char delimiter,
5770a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef                                  std::vector<std::string>* fields) {
5780a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef  fields->clear();
5790a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef  size_t last = 0;
5800a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef  for (size_t i = 0; i < source.length(); ++i) {
5810a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef    if (source[i] == delimiter) {
5820a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef      fields->push_back(source.substr(last, i - last));
5830a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef      last = i + 1;
5840a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef    }
5850a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef  }
5860a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef  fields->push_back(source.substr(last, source.length() - last));
5870a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef  return fields->size();
5880a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef}
5890a6c4ca942f3a25c15c7af64a9515d381c34cd9cdeadbeef
590f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t tokenize_append(const std::string& source, char delimiter,
591f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                       std::vector<std::string>* fields) {
592f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (!fields) return 0;
593f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
594f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  std::vector<std::string> new_fields;
595f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  tokenize(source, delimiter, &new_fields);
596f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  fields->insert(fields->end(), new_fields.begin(), new_fields.end());
597f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return fields->size();
598f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
599f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
600f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t tokenize(const std::string& source, char delimiter, char start_mark,
601f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                char end_mark, std::vector<std::string>* fields) {
602f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (!fields) return 0;
603f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  fields->clear();
604f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
605f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  std::string remain_source = source;
606f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  while (!remain_source.empty()) {
607f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    size_t start_pos = remain_source.find(start_mark);
608f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (std::string::npos == start_pos) break;
609f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    std::string pre_mark;
610f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (start_pos > 0) {
611f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      pre_mark = remain_source.substr(0, start_pos - 1);
612f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
613f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
614f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    ++start_pos;
615f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    size_t end_pos = remain_source.find(end_mark, start_pos);
616f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (std::string::npos == end_pos) break;
617f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
618f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    // We have found the matching marks. First tokenize the pre-mask. Then add
619f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    // the marked part as a single field. Finally, loop back for the post-mark.
620f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    tokenize_append(pre_mark, delimiter, fields);
621f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    fields->push_back(remain_source.substr(start_pos, end_pos - start_pos));
622f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    remain_source = remain_source.substr(end_pos + 1);
623f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
624f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
625f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return tokenize_append(remain_source, delimiter, fields);
626f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
627f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
628144d01850bd3e07222d3f8696debec689dcdccf5Donald Curtisbool tokenize_first(const std::string& source,
629144d01850bd3e07222d3f8696debec689dcdccf5Donald Curtis                    const char delimiter,
630144d01850bd3e07222d3f8696debec689dcdccf5Donald Curtis                    std::string* token,
631144d01850bd3e07222d3f8696debec689dcdccf5Donald Curtis                    std::string* rest) {
6320e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis  // Find the first delimiter
6330e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis  size_t left_pos = source.find(delimiter);
6340e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis  if (left_pos == std::string::npos) {
6350e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis    return false;
6360e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis  }
6370e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis
6380e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis  // Look for additional occurrances of delimiter.
6390e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis  size_t right_pos = left_pos + 1;
640144d01850bd3e07222d3f8696debec689dcdccf5Donald Curtis  while (source[right_pos] == delimiter) {
6410e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis    right_pos++;
6420e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis  }
6430e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis
6440e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis  *token = source.substr(0, left_pos);
6450e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis  *rest = source.substr(right_pos);
6460e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis  return true;
6470e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis}
6480e07f92043b333acfdaed8f22da5df903a70e0e9Donald Curtis
649f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgsize_t split(const std::string& source, char delimiter,
650f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org             std::vector<std::string>* fields) {
65191d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(fields);
652f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  fields->clear();
653f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t last = 0;
654f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  for (size_t i = 0; i < source.length(); ++i) {
655f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (source[i] == delimiter) {
656f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      fields->push_back(source.substr(last, i - last));
657f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      last = i + 1;
658f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
659f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
660f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  fields->push_back(source.substr(last, source.length() - last));
661f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return fields->size();
662f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
663f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
664f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgchar make_char_safe_for_filename(char c) {
665f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (c < 32)
666f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return '_';
667f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
668f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  switch (c) {
669f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case '<':
670f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case '>':
671f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case ':':
672f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case '"':
673f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case '/':
674f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case '\\':
675f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case '|':
676f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case '*':
677f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case '?':
678f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return '_';
679f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
680f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    default:
681f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return c;
682f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
683f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
684f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
685f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org/*
686f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid sprintf(std::string& value, size_t maxlen, const char * format, ...) {
687f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  char * buffer = STACK_ARRAY(char, maxlen + 1);
688f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  va_list args;
689f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  va_start(args, format);
690f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  value.assign(buffer, vsprintfn(buffer, maxlen + 1, format, args));
691f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  va_end(args);
692f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
693f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org*/
694f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
695f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org/////////////////////////////////////////////////////////////////////////////
696f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
697f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}  // namespace rtc
698