Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
protobuf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
protobuf
Commits
1353315d
Commit
1353315d
authored
Aug 14, 2008
by
Jon Skeet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implemented TextFormatter
parent
b84310e1
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
475 additions
and
15 deletions
+475
-15
ByteString.cs
csharp/ProtocolBuffers/ByteString.cs
+11
-1
ProtocolBuffers.csproj
csharp/ProtocolBuffers/ProtocolBuffers.csproj
+1
-0
TextFormat.cs
csharp/ProtocolBuffers/TextFormat.cs
+383
-14
TextGenerator.cs
csharp/ProtocolBuffers/TextGenerator.cs
+80
-0
No files found.
csharp/ProtocolBuffers/ByteString.cs
View file @
1353315d
...
@@ -15,13 +15,15 @@
...
@@ -15,13 +15,15 @@
// limitations under the License.
// limitations under the License.
using
System.Text
;
using
System.Text
;
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections
;
namespace
Google.ProtocolBuffers
{
namespace
Google.ProtocolBuffers
{
/// <summary>
/// <summary>
/// Immutable array of bytes.
/// Immutable array of bytes.
/// TODO(jonskeet): Implement the common collection interfaces?
/// TODO(jonskeet): Implement the common collection interfaces?
/// </summary>
/// </summary>
public
sealed
class
ByteString
{
public
sealed
class
ByteString
:
IEnumerable
<
byte
>
{
private
static
readonly
ByteString
empty
=
new
ByteString
(
new
byte
[
0
]);
private
static
readonly
ByteString
empty
=
new
ByteString
(
new
byte
[
0
]);
...
@@ -105,6 +107,14 @@ namespace Google.ProtocolBuffers {
...
@@ -105,6 +107,14 @@ namespace Google.ProtocolBuffers {
return
ToString
(
Encoding
.
UTF8
);
return
ToString
(
Encoding
.
UTF8
);
}
}
public
IEnumerator
<
byte
>
GetEnumerator
()
{
return
((
IEnumerable
<
byte
>)
bytes
).
GetEnumerator
();
}
IEnumerator
IEnumerable
.
GetEnumerator
()
{
return
GetEnumerator
();
}
/// <summary>
/// <summary>
/// Creates a CodedInputStream from this ByteString's data.
/// Creates a CodedInputStream from this ByteString's data.
/// </summary>
/// </summary>
...
...
csharp/ProtocolBuffers/ProtocolBuffers.csproj
View file @
1353315d
...
@@ -87,6 +87,7 @@
...
@@ -87,6 +87,7 @@
<Compile
Include=
"InvalidProtocolBufferException.cs"
/>
<Compile
Include=
"InvalidProtocolBufferException.cs"
/>
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
<Compile
Include=
"TextFormat.cs"
/>
<Compile
Include=
"TextFormat.cs"
/>
<Compile
Include=
"TextGenerator.cs"
/>
<Compile
Include=
"UninitializedMessageException.cs"
/>
<Compile
Include=
"UninitializedMessageException.cs"
/>
<Compile
Include=
"UnknownField.cs"
/>
<Compile
Include=
"UnknownField.cs"
/>
<Compile
Include=
"UnknownFieldSet.cs"
/>
<Compile
Include=
"UnknownFieldSet.cs"
/>
...
...
csharp/ProtocolBuffers/TextFormat.cs
View file @
1353315d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Text
;
using
System.Text
;
using
Google.ProtocolBuffers.Descriptors
;
using
System.Collections
;
namespace
Google.ProtocolBuffers
{
namespace
Google.ProtocolBuffers
{
public
class
TextFormat
{
/// <summary>
/// Provides ASCII text formatting support for messages.
/// TODO(jonskeet): Parsing support.
/// </summary>
public
static
class
TextFormat
{
/// <summary>
/// Outputs a textual representation of the Protocol Message supplied into
/// the parameter output.
/// </summary>
public
static
void
Print
(
IMessage
message
,
TextWriter
output
)
{
TextGenerator
generator
=
new
TextGenerator
(
output
);
Print
(
message
,
generator
);
}
/// <summary>
/// Outputs a textual representation of <paramref name="fields" /> to <paramref name="output"/>.
/// </summary>
/// <param name="fields"></param>
/// <param name="output"></param>
public
static
void
Print
(
UnknownFieldSet
fields
,
TextWriter
output
)
{
TextGenerator
generator
=
new
TextGenerator
(
output
);
PrintUnknownFields
(
fields
,
generator
);
}
public
static
string
PrintToString
(
IMessage
message
)
{
public
static
string
PrintToString
(
IMessage
message
)
{
throw
new
NotImplementedException
();
StringWriter
text
=
new
StringWriter
();
Print
(
message
,
text
);
return
text
.
ToString
();
}
public
static
string
PrintToString
(
UnknownFieldSet
fields
)
{
StringWriter
text
=
new
StringWriter
();
Print
(
fields
,
text
);
return
text
.
ToString
();
}
private
static
void
Print
(
IMessage
message
,
TextGenerator
generator
)
{
MessageDescriptor
descriptor
=
message
.
DescriptorForType
;
foreach
(
KeyValuePair
<
FieldDescriptor
,
object
>
entry
in
message
.
AllFields
)
{
PrintField
(
entry
.
Key
,
entry
.
Value
,
generator
);
}
PrintUnknownFields
(
message
.
UnknownFields
,
generator
);
}
internal
static
void
PrintField
(
FieldDescriptor
field
,
object
value
,
TextGenerator
generator
)
{
if
(
field
.
IsRepeated
)
{
// Repeated field. Print each element.
foreach
(
object
element
in
(
IEnumerable
)
value
)
{
PrintSingleField
(
field
,
element
,
generator
);
}
}
else
{
PrintSingleField
(
field
,
value
,
generator
);
}
}
private
static
void
PrintSingleField
(
FieldDescriptor
field
,
Object
value
,
TextGenerator
generator
)
{
if
(
field
.
IsExtension
)
{
generator
.
Print
(
"["
);
// We special-case MessageSet elements for compatibility with proto1.
if
(
field
.
ContainingType
.
Options
.
MessageSetWireFormat
&&
field
.
FieldType
==
FieldType
.
Message
&&
field
.
IsOptional
// object equality (TODO(jonskeet): Work out what this comment means!)
&&
field
.
ExtensionScope
==
field
.
MessageType
)
{
generator
.
Print
(
field
.
MessageType
.
FullName
);
}
else
{
generator
.
Print
(
field
.
FullName
);
}
generator
.
Print
(
"]"
);
}
else
{
if
(
field
.
FieldType
==
FieldType
.
Group
)
{
// Groups must be serialized with their original capitalization.
generator
.
Print
(
field
.
MessageType
.
Name
);
}
else
{
generator
.
Print
(
field
.
Name
);
}
}
if
(
field
.
MappedType
==
MappedType
.
Message
)
{
generator
.
Print
(
" {\n"
);
generator
.
Indent
();
}
else
{
generator
.
Print
(
": "
);
}
}
internal
static
string
PrintToString
(
UnknownFieldSet
unknownFieldSet
)
{
PrintFieldValue
(
field
,
value
,
generator
);
throw
new
NotImplementedException
();
if
(
field
.
MappedType
==
MappedType
.
Message
)
{
generator
.
Outdent
();
generator
.
Print
(
"}"
);
}
generator
.
Print
(
"\n"
);
}
private
static
void
PrintFieldValue
(
FieldDescriptor
field
,
object
value
,
TextGenerator
generator
)
{
switch
(
field
.
FieldType
)
{
case
FieldType
.
Int32
:
case
FieldType
.
Int64
:
case
FieldType
.
SInt32
:
case
FieldType
.
SInt64
:
case
FieldType
.
SFixed32
:
case
FieldType
.
SFixed64
:
case
FieldType
.
Float
:
case
FieldType
.
Double
:
case
FieldType
.
UInt32
:
case
FieldType
.
UInt64
:
case
FieldType
.
Fixed32
:
case
FieldType
.
Fixed64
:
// Good old ToString() does what we want for these types. (Including the
// unsigned ones, unlike with Java.)
generator
.
Print
(
value
.
ToString
());
break
;
case
FieldType
.
Bool
:
// Explicitly use the Java true/false
generator
.
Print
((
bool
)
value
?
"true"
:
"false"
);
break
;
case
FieldType
.
String
:
generator
.
Print
(
"\""
);
generator
.
Print
(
EscapeText
((
string
)
value
));
generator
.
Print
(
"\""
);
break
;
case
FieldType
.
Bytes
:
{
generator
.
Print
(
"\""
);
generator
.
Print
(
EscapeBytes
((
ByteString
)
value
));
generator
.
Print
(
"\""
);
break
;
}
case
FieldType
.
Enum
:
{
generator
.
Print
(((
EnumValueDescriptor
)
value
).
Name
);
break
;
}
case
FieldType
.
Message
:
case
FieldType
.
Group
:
Print
((
IMessage
)
value
,
generator
);
break
;
}
}
}
private
static
void
PrintUnknownFields
(
UnknownFieldSet
unknownFields
,
TextGenerator
generator
)
{
foreach
(
KeyValuePair
<
int
,
UnknownField
>
entry
in
unknownFields
.
FieldDictionary
)
{
String
prefix
=
entry
.
Key
.
ToString
()
+
": "
;
UnknownField
field
=
entry
.
Value
;
internal
static
object
ParseUInt64
(
string
p
)
{
foreach
(
ulong
value
in
field
.
VarintList
)
{
throw
new
NotImplementedException
();
generator
.
Print
(
entry
.
Key
.
ToString
());
generator
.
Print
(
": "
);
generator
.
Print
(
value
.
ToString
());
generator
.
Print
(
"\n"
);
}
foreach
(
uint
value
in
field
.
Fixed32List
)
{
generator
.
Print
(
entry
.
Key
.
ToString
());
generator
.
Print
(
": "
);
// FIXME(jonskeet): Get format of this right; in Java it's %08x. Find out what this means
// Also check we're okay in terms of signed/unsigned.
generator
.
Print
(
string
.
Format
(
"0x{0:x}"
,
value
));
generator
.
Print
(
"\n"
);
}
foreach
(
ulong
value
in
field
.
Fixed64List
)
{
generator
.
Print
(
entry
.
Key
.
ToString
());
generator
.
Print
(
": "
);
// FIXME(jonskeet): Get format of this right; in Java it's %016x. Find out what this means
// Also check we're okay in terms of signed/unsigned.
generator
.
Print
(
string
.
Format
(
"0x{0:x}"
,
value
));
generator
.
Print
(
"\n"
);
}
foreach
(
ByteString
value
in
field
.
LengthDelimitedList
)
{
generator
.
Print
(
entry
.
Key
.
ToString
());
generator
.
Print
(
": \""
);
generator
.
Print
(
EscapeBytes
(
value
));
generator
.
Print
(
"\"\n"
);
}
foreach
(
UnknownFieldSet
value
in
field
.
GroupList
)
{
generator
.
Print
(
entry
.
Key
.
ToString
());
generator
.
Print
(
" {\n"
);
generator
.
Indent
();
PrintUnknownFields
(
value
,
generator
);
generator
.
Outdent
();
generator
.
Print
(
"}\n"
);
}
}
}
}
internal
static
object
ParseInt64
(
string
p
)
{
throw
new
NotImplementedException
();
internal
static
ulong
ParseUInt64
(
string
text
)
{
return
(
ulong
)
ParseInteger
(
text
,
true
,
false
);
}
}
internal
static
object
ParseUInt32
(
string
p
)
{
internal
static
long
ParseInt64
(
string
text
)
{
throw
new
NotImplementedException
(
);
return
ParseInteger
(
text
,
true
,
false
);
}
}
internal
static
object
ParseInt32
(
string
p
)
{
internal
static
uint
ParseUInt32
(
string
text
)
{
throw
new
NotImplementedException
();
return
(
uint
)
ParseInteger
(
text
,
true
,
false
);
}
internal
static
int
ParseInt32
(
string
text
)
{
return
(
int
)
ParseInteger
(
text
,
true
,
false
);
}
/// <summary>
/// Parses an integer in hex (leading 0x), decimal (no prefix) or octal (leading 0).
/// Only a negative sign is permitted, and it must come before the radix indicator.
/// </summary>
private
static
long
ParseInteger
(
string
text
,
bool
isSigned
,
bool
isLong
)
{
string
original
=
text
;
bool
negative
=
false
;
if
(
text
.
StartsWith
(
"-"
))
{
if
(!
isSigned
)
{
throw
new
FormatException
(
"Number must be positive: "
+
original
);
}
negative
=
true
;
text
=
text
.
Substring
(
1
);
}
int
radix
=
10
;
if
(
text
.
StartsWith
(
"0x"
))
{
radix
=
16
;
text
=
text
.
Substring
(
2
);
}
else
if
(
text
.
StartsWith
(
"0"
))
{
radix
=
8
;
text
=
text
.
Substring
(
1
);
}
ulong
result
=
Convert
.
ToUInt64
(
text
,
radix
);
if
(
negative
)
{
ulong
max
=
isLong
?
0x8000000U
L
:
0x8000L
;
if
(
result
>
max
)
{
throw
new
FormatException
(
"Number of out range: "
+
original
);
}
return
-((
long
)
result
);
}
else
{
ulong
max
=
isSigned
?
(
isLong
?
(
ulong
)
long
.
MaxValue
:
int
.
MaxValue
)
:
(
isLong
?
ulong
.
MaxValue
:
uint
.
MaxValue
);
if
(
result
>
max
)
{
throw
new
FormatException
(
"Number of out range: "
+
original
);
}
return
(
long
)
result
;
}
}
/// <summary>
/// Tests a character to see if it's an octal digit.
/// </summary>
private
static
bool
IsOctal
(
char
c
)
{
return
'0'
<=
c
&&
c
<=
'7'
;
}
/// <summary>
/// Tests a character to see if it's a hex digit.
/// </summary>
private
static
bool
IsHex
(
char
c
)
{
return
(
'0'
<=
c
&&
c
<=
'9'
)
||
(
'a'
<=
c
&&
c
<=
'f'
)
||
(
'A'
<=
c
&&
c
<=
'F'
);
}
/// <summary>
/// Interprets a character as a digit (in any base up to 36) and returns the
/// numeric value.
/// </summary>
private
static
int
ParseDigit
(
char
c
)
{
if
(
'0'
<=
c
&&
c
<=
'9'
)
{
return
c
-
'0'
;
}
else
if
(
'a'
<=
c
&&
c
<=
'z'
)
{
return
c
-
'a'
+
10
;
}
else
{
return
c
-
'A'
+
10
;
}
}
/// <summary>
/// Like <see cref="EscapeBytes" /> but escapes a text string.
/// The string is first encoded as UTF-8, then each byte escaped individually.
/// The returned value is guaranteed to be entirely ASCII.
/// </summary>
static
String
EscapeText
(
string
input
)
{
return
EscapeBytes
(
ByteString
.
CopyFromUtf8
(
input
));
}
/// <summary>
/// Escapes bytes in the format used in protocol buffer text format, which
/// is the same as the format used for C string literals. All bytes
/// that are not printable 7-bit ASCII characters are escaped, as well as
/// backslash, single-quote, and double-quote characters. Characters for
/// which no defined short-hand escape sequence is defined will be escaped
/// using 3-digit octal sequences.
/// The returned value is guaranteed to be entirely ASCII.
/// </summary>
private
static
String
EscapeBytes
(
ByteString
input
)
{
StringBuilder
builder
=
new
StringBuilder
(
input
.
Length
);
foreach
(
byte
b
in
input
)
{
switch
(
b
)
{
// C# does not use \a or \v
case
0x07
:
builder
.
Append
(
"\\a"
);
break
;
case
(
byte
)
'\b'
:
builder
.
Append
(
"\\b"
);
break
;
case
(
byte
)
'\f'
:
builder
.
Append
(
"\\f"
);
break
;
case
(
byte
)
'\n'
:
builder
.
Append
(
"\\n"
);
break
;
case
(
byte
)
'\r'
:
builder
.
Append
(
"\\r"
);
break
;
case
(
byte
)
'\t'
:
builder
.
Append
(
"\\t"
);
break
;
case
0x0b
:
builder
.
Append
(
"\\v"
);
break
;
case
(
byte
)
'\\'
:
builder
.
Append
(
"\\\\"
);
break
;
case
(
byte
)
'\''
:
builder
.
Append
(
"\\\'"
);
break
;
case
(
byte
)
'"'
:
builder
.
Append
(
"\\\""
);
break
;
default
:
if
(
b
>=
0x20
)
{
builder
.
Append
((
char
)
b
);
}
else
{
builder
.
Append
(
'\\'
);
builder
.
Append
((
char
)
(
'0'
+
((
b
>>
6
)
&
3
)));
builder
.
Append
((
char
)
(
'0'
+
((
b
>>
3
)
&
7
)));
builder
.
Append
((
char
)
(
'0'
+
(
b
&
7
)));
}
break
;
}
}
return
builder
.
ToString
();
}
/// <summary>
/// Performs string unescaping from C style (octal, hex, form feeds, tab etc) into a byte string.
/// </summary>
internal
static
ByteString
UnescapeBytes
(
string
input
)
{
byte
[]
result
=
new
byte
[
input
.
Length
];
int
pos
=
0
;
for
(
int
i
=
0
;
i
<
input
.
Length
;
i
++)
{
char
c
=
input
[
i
];
if
(
c
>
127
||
c
<
32
)
{
throw
new
FormatException
(
"Escaped string must only contain ASCII"
);
}
if
(
c
!=
'\\'
)
{
result
[
pos
++]
=
(
byte
)
c
;
continue
;
}
if
(
i
+
1
>=
input
.
Length
)
{
throw
new
FormatException
(
"Invalid escape sequence: '\\' at end of string."
);
}
i
++;
c
=
input
[
i
];
if
(
c
>=
'0'
&&
c
<=
'7'
)
{
// Octal escape.
int
code
=
ParseDigit
(
c
);
if
(
i
+
1
<
input
.
Length
&&
IsOctal
(
input
[
i
+
1
]))
{
i
++;
code
=
code
*
8
+
ParseDigit
(
input
[
i
]);
}
if
(
i
+
1
<
input
.
Length
&&
IsOctal
(
input
[
i
+
1
]))
{
i
++;
code
=
code
*
8
+
ParseDigit
(
input
[
i
]);
}
result
[
pos
++]
=
(
byte
)
code
;
}
else
{
switch
(
c
)
{
case
'a'
:
result
[
pos
++]
=
0x07
;
break
;
case
'b'
:
result
[
pos
++]
=
(
byte
)
'\b'
;
break
;
case
'f'
:
result
[
pos
++]
=
(
byte
)
'\f'
;
break
;
case
'n'
:
result
[
pos
++]
=
(
byte
)
'\n'
;
break
;
case
'r'
:
result
[
pos
++]
=
(
byte
)
'\r'
;
break
;
case
't'
:
result
[
pos
++]
=
(
byte
)
'\t'
;
break
;
case
'v'
:
result
[
pos
++]
=
0x0b
;
break
;
case
'\\'
:
result
[
pos
++]
=
(
byte
)
'\\'
;
break
;
case
'\''
:
result
[
pos
++]
=
(
byte
)
'\''
;
break
;
case
'"'
:
result
[
pos
++]
=
(
byte
)
'\"'
;
break
;
case
'x'
:
// hex escape
int
code
;
if
(
i
+
1
<
input
.
Length
&&
IsHex
(
input
[
i
+
1
]))
{
i
++;
code
=
ParseDigit
(
input
[
i
]);
}
else
{
throw
new
FormatException
(
"Invalid escape sequence: '\\x' with no digits"
);
}
if
(
i
+
1
<
input
.
Length
&&
IsHex
(
input
[
i
+
1
]))
{
++
i
;
code
=
code
*
16
+
ParseDigit
(
input
[
i
]);
}
result
[
pos
++]
=
(
byte
)
code
;
break
;
default
:
throw
new
FormatException
(
"Invalid escape sequence: '\\"
+
c
+
"'"
);
}
}
}
}
internal
static
object
UnescapeBytes
(
string
p
)
{
return
ByteString
.
CopyFrom
(
result
,
0
,
pos
);
throw
new
NotImplementedException
();
}
}
}
}
}
}
csharp/ProtocolBuffers/TextGenerator.cs
0 → 100644
View file @
1353315d
using
System
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Text
;
namespace
Google.ProtocolBuffers
{
/// <summary>
/// Helper class to control indentation
/// </summary>
internal
class
TextGenerator
{
/// <summary>
/// Writer to write formatted text to.
/// </summary>
private
readonly
TextWriter
writer
;
/// <summary>
/// Keeps track of whether the next piece of text should be indented
/// </summary>
bool
atStartOfLine
=
true
;
/// <summary>
/// Keeps track of the current level of indentation
/// </summary>
readonly
StringBuilder
indent
=
new
StringBuilder
();
/// <summary>
/// Creates a generator writing to the given writer.
/// </summary>
internal
TextGenerator
(
TextWriter
writer
)
{
this
.
writer
=
writer
;
}
/// <summary>
/// Indents text by two spaces. After calling Indent(), two spaces
/// will be inserted at the beginning of each line of text. Indent() may
/// be called multiple times to produce deeper indents.
/// </summary>
internal
void
Indent
()
{
indent
.
Append
(
" "
);
}
/// <summary>
/// Reduces the current indent level by two spaces.
/// </summary>
internal
void
Outdent
()
{
if
(
indent
.
Length
==
0
)
{
throw
new
InvalidOperationException
(
"Too many calls to Outdent()"
);
}
indent
.
Length
-=
2
;
}
/// <summary>
/// Prints the given text to the output stream, indenting at line boundaries.
/// </summary>
/// <param name="text"></param>
public
void
Print
(
string
text
)
{
int
pos
=
0
;
for
(
int
i
=
0
;
i
<
text
.
Length
;
i
++)
{
if
(
text
[
i
]
==
'\n'
)
{
// TODO(jonskeet): Use Environment.NewLine?
Write
(
text
.
Substring
(
pos
,
i
-
pos
+
1
));
pos
=
i
+
1
;
atStartOfLine
=
true
;
}
}
Write
(
text
.
Substring
(
pos
));
}
private
void
Write
(
string
data
)
{
if
(
atStartOfLine
)
{
atStartOfLine
=
false
;
writer
.
Write
(
indent
);
}
writer
.
Write
(
data
);
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment