blob: 508d76a9413ce521a109b79f1da8c9a8980aa00e [file] [log] [blame]
csharptest2cf6e1b2011-09-16 10:55:10 -05001using System;
2using System.IO;
3using System.Text;
4
5namespace Google.ProtocolBuffers.Serialization.Http
6{
7 /// <summary>
8 /// Allows reading messages from a name/value dictionary
9 /// </summary>
10 public class FormUrlEncodedReader : AbstractTextReader
11 {
12 private readonly TextReader _input;
13 private string _fieldName, _fieldValue;
14 private bool _ready;
15
16 /// <summary>
17 /// Creates a dictionary reader from an enumeration of KeyValuePair data, like an IDictionary
18 /// </summary>
19 FormUrlEncodedReader(TextReader input)
20 {
21 _input = input;
22 int ch = input.Peek();
23 if (ch == '?')
24 {
25 input.Read();
26 }
27 _ready = ReadNext();
28 }
29
30 #region CreateInstance overloads
31 /// <summary>
32 /// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
33 /// </summary>
34 public static FormUrlEncodedReader CreateInstance(Stream stream)
35 {
36 return new FormUrlEncodedReader(new StreamReader(stream, Encoding.UTF8, false));
37 }
38
39 /// <summary>
40 /// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
41 /// </summary>
42 public static FormUrlEncodedReader CreateInstance(byte[] bytes)
43 {
44 return new FormUrlEncodedReader(new StreamReader(new MemoryStream(bytes, false), Encoding.UTF8, false));
45 }
46
47 /// <summary>
48 /// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
49 /// </summary>
50 public static FormUrlEncodedReader CreateInstance(string text)
51 {
52 return new FormUrlEncodedReader(new StringReader(text));
53 }
54
55 /// <summary>
56 /// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
57 /// </summary>
58 public static FormUrlEncodedReader CreateInstance(TextReader input)
59 {
60 return new FormUrlEncodedReader(input);
61 }
62 #endregion
63
64 private bool ReadNext()
65 {
66 StringBuilder field = new StringBuilder(32);
67 StringBuilder value = new StringBuilder(64);
68 int ch;
69 while (-1 != (ch = _input.Read()) && ch != '=' && ch != '&')
70 {
71 field.Append((char)ch);
72 }
73
74 if (ch != -1 && ch != '&')
75 {
76 while (-1 != (ch = _input.Read()) && ch != '&')
77 {
78 value.Append((char)ch);
79 }
80 }
81
82 _fieldName = field.ToString();
83 _fieldValue = Uri.UnescapeDataString(value.Replace('+', ' ').ToString());
84
85 return !String.IsNullOrEmpty(_fieldName);
86 }
87
88 /// <summary>
89 /// No-op
90 /// </summary>
91 public override void ReadMessageStart()
92 { }
93
94 /// <summary>
95 /// No-op
96 /// </summary>
97 public override void ReadMessageEnd()
98 { }
99
100 /// <summary>
101 /// Merges the contents of stream into the provided message builder
102 /// </summary>
103 public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)
104 {
105 builder.WeakMergeFrom(this, registry);
106 return builder;
107 }
108
109 /// <summary>
110 /// Causes the reader to skip past this field
111 /// </summary>
112 protected override void Skip()
113 {
114 _ready = ReadNext();
115 }
116
117 /// <summary>
118 /// Peeks at the next field in the input stream and returns what information is available.
119 /// </summary>
120 /// <remarks>
121 /// This may be called multiple times without actually reading the field. Only after the field
122 /// is either read, or skipped, should PeekNext return a different value.
123 /// </remarks>
124 protected override bool PeekNext(out string field)
125 {
126 field = _ready ? _fieldName : null;
127 return field != null;
128 }
129
130 /// <summary>
131 /// Returns true if it was able to read a String from the input
132 /// </summary>
133 protected override bool ReadAsText(ref string value, Type typeInfo)
134 {
135 if (_ready)
136 {
137 value = _fieldValue;
138 _ready = ReadNext();
139 return true;
140 }
141 return false;
142 }
143
144 /// <summary>
145 /// It's unlikely this will work for anything but text data as bytes UTF8 are transformed to text and back to bytes
146 /// </summary>
147 protected override ByteString DecodeBytes(string bytes)
148 { return ByteString.CopyFromUtf8(bytes); }
149
150 /// <summary>
151 /// Not Supported
152 /// </summary>
153 public override bool ReadGroup(IBuilderLite value, ExtensionRegistry registry)
154 { throw new NotSupportedException(); }
155
156 /// <summary>
157 /// Not Supported
158 /// </summary>
159 protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry)
160 { throw new NotSupportedException(); }
161 }
162}