diff --git a/CHANGES.txt b/CHANGES.txt
new file mode 100644
index 0000000000..d3e5a85a8b
--- /dev/null
+++ b/CHANGES.txt
@@ -0,0 +1,92 @@
+===============================================================================
+Welcome to the C# port of Google Protocol Buffers, written by Jon Skeet
+(skeet@pobox.com) based on the work of many talented people.
+
+For more information about this port, visit its homepage:
+http://protobuf-csharp-port.googlecode.com
+
+For more information about Protocol Buffers in general, visit the project page
+for the C++, Java and Python project:
+http://protobuf.googlecode.com
+===============================================================================
+RELEASE NOTES - Version TBD
+===============================================================================
+
+(PENDING MERGE)
+- Issue 20: Support for decorating classes [Serializable]
+- Issue 22: Reusable Builder classes
+- Issue 24: Support for using Json/Xml formats with ICodedInputStream
+
+Features:
+- Added option service_generator_type to control service generation with
+ NONE, GENERIC, INTERFACE, or IRPCDISPATCH
+- Added interfaces IRpcDispatch and IRpcServerStub to provide for blocking
+ services and implementations.
+- Added ProtoGen.exe command-line argument "--protoc_dir=" to specify the
+ location of protoc.exe.
+- Extracted interfaces for ICodedInputStream and ICodedOutputStream to allow
+ custom implementation of writers with both speed and size optimizations.
+- Addition of the "Google.ProtoBuffers.Serialization" assembly to support
+ reading and writing messages to/from XML, JSON, IDictionary<,> and others.
+- Several performance related fixes and tweeks
+- Issue 3: Add option to mark generated code with attribute
+- Issue 21: Decorate fields with [deprecated=true] as [System.Obsolete]
+
+Fixes:
+- Issue 13: Message with Field same name as message causes uncompilable .cs
+- Issue 16: Does not integrate well with other tooling
+- Issue 19: Support for negative enum values
+- Issue 26: AddRange in GeneratedBuilder iterates twice.
+- Issue 27: Remove XML documentation output from test projects to clear
+ warnings/errors.
+- Big-endian support for float, and double on Silverlight
+- Packed and Unpacked parsing allow for all repeated, as per version 2.3
+- Fix for leaving Builder a public ctor on internal classes for use with
+ generic "where T: new()" constraints.
+
+Other:
+- Reformatted all code and line-endings to C# defaults
+- Reworking of performance benchmarks to produce reliable results, option /v2
+
+===============================================================================
+RELEASE NOTES - Version 2.3.0.277
+===============================================================================
+
+Features:
+- Added cls_compliance option to generate attributes indicating
+ non-CLS-compliance.
+- Added file_extension option to control the generated output file's extension.
+- Added umbrella_namespace option to place the umbrella class into a nested
+ namespace to address issues with proto files having the same name as a
+ message it contains.
+- Added output_directory option to set the output path for the source file(s).
+- Added ignore_google_protobuf option to avoid generating code for includes
+ from the google.protobuf package.
+- Added the LITE framework (Google.ProtoBuffersLite.dll) and the ability to
+ generate code with "option optimize_for = LITE_RUNTIME;".
+- Added ability to invoke protoc.exe from within ProtoGen.exe.
+- Upgraded to protoc.exe (2.3) compiler.
+
+Fixes:
+- Issue 9: Class cannot be static and sealed error
+- Issue 12: default value for enumerate fields must be filled out
+
+Other:
+- Rewrite of build using MSBbuild instead of NAnt
+- Moved to NUnit Version 2.2.8.0
+- Changed to using secure .snk for releases
+
+===============================================================================
+RELEASE NOTES - Version 0.9.1
+===============================================================================
+
+Fixes:
+- issue 10: Incorrect encoding of packed fields when serialized
+
+===============================================================================
+RELEASE NOTES - Version 0.9.0
+===============================================================================
+
+- Initial release
+
+===============================================================================
\ No newline at end of file
diff --git a/build/Build.bat b/build/Build.bat
index 3269d54b83..2b246cadf8 100644
--- a/build/Build.bat
+++ b/build/Build.bat
@@ -1,10 +1,10 @@
-@echo off
-SET BUILD_TARGET=%1
-SET BUILD_CONFIG=%2
-
-IF "%BUILD_TARGET%"=="" SET BUILD_TARGET=Rebuild
-IF "%BUILD_CONFIG%"=="" SET BUILD_CONFIG=Debug
-
-CMD.exe /Q /C "CD %~dp0 && %WINDIR%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe build.csproj %3 %4 %5 %6 /t:%BUILD_TARGET% /p:BuildConfiguration=%BUILD_CONFIG% /p:Platform="Any CPU" /p:BuildTools=4.0 /toolsversion:4.0"
-
+@echo off
+SET BUILD_TARGET=%1
+SET BUILD_CONFIG=%2
+
+IF "%BUILD_TARGET%"=="" SET BUILD_TARGET=Rebuild
+IF "%BUILD_CONFIG%"=="" SET BUILD_CONFIG=Debug
+
+CMD.exe /Q /C "CD %~dp0 && %WINDIR%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe build.csproj %3 %4 %5 %6 /t:%BUILD_TARGET% /p:BuildConfiguration=%BUILD_CONFIG% /p:Platform="Any CPU" /p:BuildTools=4.0 /toolsversion:4.0"
+
pause
\ No newline at end of file
diff --git a/build/BuildAll.bat b/build/BuildAll.bat
index 984fb7910a..e80ac8d909 100644
--- a/build/BuildAll.bat
+++ b/build/BuildAll.bat
@@ -1,42 +1,42 @@
-@ECHO OFF
-
-SET PREV_WORKING_DIR=%CD%
-CD %~dp0
-
-REM -- 3.5 Debug build, ensure this continues to work
-%WINDIR%\Microsoft.NET\Framework\v3.5\MSBuild.exe build.csproj /t:Rebuild /p:BuildConfiguration=Debug /p:Platform="Any CPU" /p:BuildTools=3.5 /toolsversion:3.5"
-IF ERRORLEVEL 1 GOTO ERROR
-
-REM -- 4.0 Debug build
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild /p:BuildConfiguration=Debug /p:Platform="Any CPU"
-IF ERRORLEVEL 1 GOTO ERROR
-
-REM -- 4.0 Release build
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild /p:BuildConfiguration=Release /p:Platform="Any CPU"
-IF ERRORLEVEL 1 GOTO ERROR
-
-IF EXIST "%ProgramFiles%\MSBuild\Microsoft\Silverlight\v2.0\Microsoft.Silverlight.CSharp.targets" GOTO SILVERLIGHT
-IF EXIST "%ProgramFiles(x86)%\MSBuild\Microsoft\Silverlight\v2.0\Microsoft.Silverlight.CSharp.targets" GOTO SILVERLIGHT
-
-ECHO Unable to locate %ProgramFiles(x86)%\MSBuild\Microsoft\Silverlight\v2.0
-GOTO ERROR
-
-:SILVERLIGHT
-
-REM -- 4.0 Debug_Silverlight2 build
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild /p:BuildConfiguration=Debug_Silverlight2 /p:Platform="Any CPU"
-IF ERRORLEVEL 1 GOTO ERROR
-
-REM -- 4.0 Release_Silverlight2 build
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild /p:BuildConfiguration=Release_Silverlight2 /p:Platform="Any CPU"
-IF ERRORLEVEL 1 GOTO ERROR
-
-GOTO END
-
-:ERROR
-CD %PREV_WORKING_DIR%
-PAUSE
-
-:END
-CD %PREV_WORKING_DIR%
+@ECHO OFF
+
+SET PREV_WORKING_DIR=%CD%
+CD %~dp0
+
+REM -- 3.5 Debug build, ensure this continues to work
+%WINDIR%\Microsoft.NET\Framework\v3.5\MSBuild.exe build.csproj /t:Rebuild /p:BuildConfiguration=Debug /p:Platform="Any CPU" /p:BuildTools=3.5 /toolsversion:3.5"
+IF ERRORLEVEL 1 GOTO ERROR
+
+REM -- 4.0 Debug build
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild /p:BuildConfiguration=Debug /p:Platform="Any CPU"
+IF ERRORLEVEL 1 GOTO ERROR
+
+REM -- 4.0 Release build
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild /p:BuildConfiguration=Release /p:Platform="Any CPU"
+IF ERRORLEVEL 1 GOTO ERROR
+
+IF EXIST "%ProgramFiles%\MSBuild\Microsoft\Silverlight\v2.0\Microsoft.Silverlight.CSharp.targets" GOTO SILVERLIGHT
+IF EXIST "%ProgramFiles(x86)%\MSBuild\Microsoft\Silverlight\v2.0\Microsoft.Silverlight.CSharp.targets" GOTO SILVERLIGHT
+
+ECHO Unable to locate %ProgramFiles(x86)%\MSBuild\Microsoft\Silverlight\v2.0
+GOTO ERROR
+
+:SILVERLIGHT
+
+REM -- 4.0 Debug_Silverlight2 build
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild /p:BuildConfiguration=Debug_Silverlight2 /p:Platform="Any CPU"
+IF ERRORLEVEL 1 GOTO ERROR
+
+REM -- 4.0 Release_Silverlight2 build
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild /p:BuildConfiguration=Release_Silverlight2 /p:Platform="Any CPU"
+IF ERRORLEVEL 1 GOTO ERROR
+
+GOTO END
+
+:ERROR
+CD %PREV_WORKING_DIR%
+PAUSE
+
+:END
+CD %PREV_WORKING_DIR%
SET PREV_WORKING_DIR=
\ No newline at end of file
diff --git a/build/BuildSilverlight2.bat b/build/BuildSilverlight2.bat
index bc1dd21e97..1baccacfdf 100644
--- a/build/BuildSilverlight2.bat
+++ b/build/BuildSilverlight2.bat
@@ -1,5 +1,5 @@
-@echo off
-
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Build /p:BuildConfiguration=Debug_Silverlight2 /p:Platform="Any CPU"
-
+@echo off
+
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Build /p:BuildConfiguration=Debug_Silverlight2 /p:Platform="Any CPU"
+
pause
\ No newline at end of file
diff --git a/build/GenerateCompletePackage.bat b/build/GenerateCompletePackage.bat
index 6aa3b379ce..e281596116 100644
--- a/build/GenerateCompletePackage.bat
+++ b/build/GenerateCompletePackage.bat
@@ -1,19 +1,19 @@
-@ECHO OFF
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:PrepareOutputDirectory
-IF ERRORLEVEL 1 GOTO END
-
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Debug /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
-IF ERRORLEVEL 1 GOTO END
-
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Debug_Silverlight2 /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
-IF ERRORLEVEL 1 GOTO END
-
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Release /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
-IF ERRORLEVEL 1 GOTO END
-
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Release_Silverlight2 /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
-IF ERRORLEVEL 1 GOTO END
-
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:GeneratePackage /p:PackageName=AllBinariesAndSource.zip /p:Platform="Any CPU"
-
+@ECHO OFF
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:PrepareOutputDirectory
+IF ERRORLEVEL 1 GOTO END
+
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Debug /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
+IF ERRORLEVEL 1 GOTO END
+
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Debug_Silverlight2 /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
+IF ERRORLEVEL 1 GOTO END
+
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Release /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
+IF ERRORLEVEL 1 GOTO END
+
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Release_Silverlight2 /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
+IF ERRORLEVEL 1 GOTO END
+
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:GeneratePackage /p:PackageName=AllBinariesAndSource.zip /p:Platform="Any CPU"
+
:END
\ No newline at end of file
diff --git a/build/GenerateReleasePackage.bat b/build/GenerateReleasePackage.bat
index 921de95724..bd2a7f867f 100644
--- a/build/GenerateReleasePackage.bat
+++ b/build/GenerateReleasePackage.bat
@@ -1,13 +1,13 @@
-@ECHO OFF
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:PrepareOutputDirectory
-IF ERRORLEVEL 1 GOTO END
-
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Release /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
-IF ERRORLEVEL 1 GOTO END
-
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Release_Silverlight2 /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
-IF ERRORLEVEL 1 GOTO END
-
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:GeneratePackage /p:PackageName=ReleaseBinaries.zip /p:Platform="Any CPU"
-
+@ECHO OFF
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:PrepareOutputDirectory
+IF ERRORLEVEL 1 GOTO END
+
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Release /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
+IF ERRORLEVEL 1 GOTO END
+
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:Rebuild;PreparePackageComponent /p:BuildConfiguration=Release_Silverlight2 /p:Platform="Any CPU" %PROTOBUF_KEY_FILE%
+IF ERRORLEVEL 1 GOTO END
+
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild build.csproj /m /t:GeneratePackage /p:PackageName=ReleaseBinaries.zip /p:Platform="Any CPU"
+
:END
\ No newline at end of file
diff --git a/build/RunBenchmarks.bat b/build/RunBenchmarks.bat
index 863eafaead..5a32f3f2b3 100644
--- a/build/RunBenchmarks.bat
+++ b/build/RunBenchmarks.bat
@@ -1,5 +1,5 @@
-@echo off
-
-%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild %~dp0\build.csproj /m /t:RunBenchmarks /p:BuildConfiguration=Release /p:Platform="Any CPU"
-
+@echo off
+
+%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild %~dp0\build.csproj /m /t:RunBenchmarks /p:BuildConfiguration=Release /p:Platform="Any CPU"
+
pause
\ No newline at end of file
diff --git a/build/build35.bat b/build/build35.bat
index 87729d8f8c..02f803bd93 100644
--- a/build/build35.bat
+++ b/build/build35.bat
@@ -1,8 +1,8 @@
-@echo off
-SET BUILD_TARGET=%1
-SET BUILD_CONFIG=%2
-
-IF "%BUILD_TARGET%"=="" SET BUILD_TARGET=Rebuild
-IF "%BUILD_CONFIG%"=="" SET BUILD_CONFIG=Debug
-
-CMD.exe /Q /C "CD %~dp0 && %WINDIR%\Microsoft.NET\Framework\v3.5\MSBuild.exe build.csproj %3 %4 %5 %6 /t:%BUILD_TARGET% /p:BuildConfiguration=%BUILD_CONFIG% /p:Platform="Any CPU" /p:BuildTools=3.5 /toolsversion:3.5"
+@echo off
+SET BUILD_TARGET=%1
+SET BUILD_CONFIG=%2
+
+IF "%BUILD_TARGET%"=="" SET BUILD_TARGET=Rebuild
+IF "%BUILD_CONFIG%"=="" SET BUILD_CONFIG=Debug
+
+CMD.exe /Q /C "CD %~dp0 && %WINDIR%\Microsoft.NET\Framework\v3.5\MSBuild.exe build.csproj %3 %4 %5 %6 /t:%BUILD_TARGET% /p:BuildConfiguration=%BUILD_CONFIG% /p:Platform="Any CPU" /p:BuildTools=3.5 /toolsversion:3.5"
diff --git a/license.txt b/license.txt
index b8e773b2e0..2715f7b89e 100644
--- a/license.txt
+++ b/license.txt
@@ -1,31 +1,31 @@
-Protocol Buffers - Google's data interchange format
-Copyright 2008-2010 Google Inc. All rights reserved.
-http://github.com/jskeet/dotnet-protobufs/
-Original C++/Java/Python code:
-http://code.google.com/p/protobuf/
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+Protocol Buffers - Google's data interchange format
+Copyright 2008-2010 Google Inc. All rights reserved.
+http://github.com/jskeet/dotnet-protobufs/
+Original C++/Java/Python code:
+http://code.google.com/p/protobuf/
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/protos/extest/unittest_extras_xmltest.proto b/protos/extest/unittest_extras_xmltest.proto
index 7fc4e3a2e9..ab8088a76b 100644
--- a/protos/extest/unittest_extras_xmltest.proto
+++ b/protos/extest/unittest_extras_xmltest.proto
@@ -8,46 +8,44 @@ package protobuf_unittest_extra;
option optimize_for = SPEED;
enum EnumOptions {
- ONE = 0;
- TWO = 1;
- THREE = 2;
+ ONE = 0;
+ TWO = 1;
+ THREE = 2;
}
-message TestXmlChild
-{
- repeated EnumOptions options = 3;
- optional bytes binary = 4;
+message TestXmlChild {
+ repeated EnumOptions options = 3;
+ optional bytes binary = 4;
}
message TestXmlNoFields {
}
message TestXmlRescursive {
- optional TestXmlRescursive child = 1;
+ optional TestXmlRescursive child = 1;
}
message TestXmlMessage {
- optional int64 number = 6;
- repeated int32 numbers = 2;
- optional string text = 3;
- repeated string textlines = 700;
- optional bool valid = 5;
-
- optional TestXmlChild child = 1;
- repeated group Children = 401
- {
- repeated EnumOptions options = 3;
- optional bytes binary = 4;
- }
-
- extensions 100 to 199;
+ optional int64 number = 6;
+ repeated int32 numbers = 2;
+ optional string text = 3;
+ repeated string textlines = 700;
+ optional bool valid = 5;
+
+ optional TestXmlChild child = 1;
+ repeated group Children = 401 {
+ repeated EnumOptions options = 3;
+ optional bytes binary = 4;
+ }
+
+extensions 100 to 199;
}
message TestXmlExtension {
required int32 number = 1;
}
-
+
extend TestXmlMessage {
optional EnumOptions extension_enum = 101;
optional string extension_text = 102;
diff --git a/protos/extest/unittest_issues.proto b/protos/extest/unittest_issues.proto
index 459e58f865..5e0da0aefc 100644
--- a/protos/extest/unittest_issues.proto
+++ b/protos/extest/unittest_issues.proto
@@ -86,3 +86,47 @@ message NumberField {
optional int32 _01 = 1;
}
+// Issue 28: Circular message dependencies result in null defaults for DefaultInstance
+
+message MyMessageAReferenceB {
+ required MyMessageBReferenceA value = 1;
+}
+
+message MyMessageBReferenceA {
+ required MyMessageAReferenceB value = 1;
+}
+
+// issue 19 - negative enum values
+
+enum NegativeEnum {
+ FiveBelow = -5;
+ MinusOne = -1;
+ Zero = 0;
+}
+
+message NegativeEnumMessage {
+ optional NegativeEnum value = 1;
+ repeated NegativeEnum values = 2;
+ repeated NegativeEnum packed_values = 3 [packed=true];
+}
+
+// Issue 21: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=21
+// Decorate fields with [deprecated=true] as [System.Obsolete]
+
+message DeprecatedChild {
+}
+
+enum DeprecatedEnum {
+ one = 1;
+}
+
+message DeprecatedFieldsMessage {
+ optional int32 PrimitiveValue = 1 [deprecated = true];
+ repeated int32 PrimitiveArray = 2 [deprecated = true];
+
+ optional DeprecatedChild MessageValue = 3 [deprecated = true];
+ repeated DeprecatedChild MessageArray = 4 [deprecated = true];
+
+ optional DeprecatedEnum EnumValue = 5 [deprecated = true];
+ repeated DeprecatedEnum EnumArray = 6 [deprecated = true];
+}
\ No newline at end of file
diff --git a/protos/npp.language.xml b/protos/npp.language.xml
new file mode 100644
index 0000000000..c6122180ac
--- /dev/null
+++ b/protos/npp.language.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+ [00]00
+ {
+ }
+ =
+ 1option 1package 1import 2; 0//
+ message enum service extend
+ required optional repeated extensions to rpc returns
+ double float int32 int64 uint32 uint64 sint32 sint64 fixed32 fixed64 sfixed32 sfixed64 bool string bytes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/readme.txt b/readme.txt
deleted file mode 100644
index 52228845b6..0000000000
--- a/readme.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-Welcome to the C# port of Google Protocol Buffers, written by Jon Skeet
-(skeet@pobox.com) based on the work of many talented people.
-
-For more information about this port, visit its homepage:
-http://protobuf-csharp-port.googlecode.com
-
-For more information about Protocol Buffers in general, visit the
-project page for the C++, Java and Python project:
-http://protobuf.googlecode.com
-
-
-Release 0.9.1
--------------
-
-Fix to release 0.9:
-
-- Include protos in binary download
-- Fix issue 10: incorrect encoding of packed fields when serialized
- size wasn't fetched first
-
-
-Release 0.9
------------
-
-Due to popular demand, I have built a version of the binaries to put
-on the web site. Currently these are set at assembly version 0.9,
-and an assembly file version of 0.9. This should be seen as a mark
-of the readiness of the release process more than the stability of
-the code. As far as I'm aware, the code itself is perfectly fine: I
-certainly have plans for more features particularly around making
-code generation simpler, but you should feel confident about the
-parsing and serialization of messages produced with this version of
-the library. Of course, if you do find any problems, *please* report
-them at the web site.
-
-Currently the downloadable release is built with the snk file which
-is in the open source library. I am considering having a privately
-held key so that you can check that you're building against a
-"blessed" release - feedback on this (and any other aspect of the
-release process) is very welcome.
diff --git a/src/AddressBook/AddressBookProtos.cs b/src/AddressBook/AddressBookProtos.cs
index 4d391f0fe1..7fc1c64dbb 100644
--- a/src/AddressBook/AddressBookProtos.cs
+++ b/src/AddressBook/AddressBookProtos.cs
@@ -1,5 +1,5 @@
// Generated by ProtoGen, Version=2.3.0.277, Culture=neutral, PublicKeyToken=17b3b1f090c3ea48. DO NOT EDIT!
-#pragma warning disable 1591
+#pragma warning disable 1591, 0612
#region Designer generated code
using pb = global::Google.ProtocolBuffers;
@@ -68,7 +68,8 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.3.0.277")]
public sealed partial class Person : pb::GeneratedMessage {
- private static readonly Person defaultInstance = new Builder().BuildPartial();
+ private Person() { }
+ private static readonly Person defaultInstance = new Person().MakeReadOnly();
private static readonly string[] _personFieldNames = new string[] { "email", "id", "name", "phone" };
private static readonly uint[] _personFieldTags = new uint[] { 26, 16, 10, 34 };
public static Person DefaultInstance {
@@ -76,7 +77,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override Person DefaultInstanceForType {
- get { return defaultInstance; }
+ get { return DefaultInstance; }
}
protected override Person ThisMessage {
@@ -108,7 +109,8 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.3.0.277")]
public sealed partial class PhoneNumber : pb::GeneratedMessage {
- private static readonly PhoneNumber defaultInstance = new Builder().BuildPartial();
+ private PhoneNumber() { }
+ private static readonly PhoneNumber defaultInstance = new PhoneNumber().MakeReadOnly();
private static readonly string[] _phoneNumberFieldNames = new string[] { "number", "type" };
private static readonly uint[] _phoneNumberFieldTags = new uint[] { 10, 16 };
public static PhoneNumber DefaultInstance {
@@ -116,7 +118,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override PhoneNumber DefaultInstanceForType {
- get { return defaultInstance; }
+ get { return DefaultInstance; }
}
protected override PhoneNumber ThisMessage {
@@ -219,11 +221,15 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
public static PhoneNumber ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
}
+ private PhoneNumber MakeReadOnly() {
+ return this;
+ }
+
public static Builder CreateBuilder() { return new Builder(); }
public override Builder ToBuilder() { return CreateBuilder(this); }
public override Builder CreateBuilderForType() { return new Builder(); }
public static Builder CreateBuilder(PhoneNumber prototype) {
- return (Builder) new Builder().MergeFrom(prototype);
+ return new Builder(prototype);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -233,21 +239,48 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
protected override Builder ThisBuilder {
get { return this; }
}
- public Builder() {}
+ public Builder() {
+ result = DefaultInstance;
+ resultIsReadOnly = true;
+ }
+ internal Builder(PhoneNumber cloneFrom) {
+ result = cloneFrom;
+ resultIsReadOnly = true;
+ }
+
+ private bool resultIsReadOnly;
+ private PhoneNumber result;
- PhoneNumber result = new PhoneNumber();
+ private PhoneNumber PrepareBuilder() {
+ if (resultIsReadOnly) {
+ PhoneNumber original = result;
+ result = new PhoneNumber();
+ resultIsReadOnly = false;
+ MergeFrom(original);
+ }
+ return result;
+ }
+
+ public override bool IsInitialized {
+ get { return result.IsInitialized; }
+ }
protected override PhoneNumber MessageBeingBuilt {
- get { return result; }
+ get { return PrepareBuilder(); }
}
public override Builder Clear() {
- result = new PhoneNumber();
+ result = DefaultInstance;
+ resultIsReadOnly = true;
return this;
}
public override Builder Clone() {
- return new Builder().MergeFrom(result);
+ if (resultIsReadOnly) {
+ return new Builder(result);
+ } else {
+ return new Builder().MergeFrom(result);
+ }
}
public override pbd::MessageDescriptor DescriptorForType {
@@ -259,12 +292,11 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override PhoneNumber BuildPartial() {
- if (result == null) {
- throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+ if (resultIsReadOnly) {
+ return result;
}
- PhoneNumber returnMe = result;
- result = null;
- return returnMe;
+ resultIsReadOnly = true;
+ return result.MakeReadOnly();
}
public override Builder MergeFrom(pb::IMessage other) {
@@ -278,6 +310,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
public override Builder MergeFrom(PhoneNumber other) {
if (other == global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber.DefaultInstance) return this;
+ PrepareBuilder();
if (other.HasNumber) {
Number = other.Number;
}
@@ -293,6 +326,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+ PrepareBuilder();
pb::UnknownFieldSet.Builder unknownFields = null;
uint tag;
string field_name;
@@ -361,11 +395,13 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public Builder SetNumber(string value) {
pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
result.hasNumber = true;
result.number_ = value;
return this;
}
public Builder ClearNumber() {
+ PrepareBuilder();
result.hasNumber = false;
result.number_ = "";
return this;
@@ -379,11 +415,13 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
set { SetType(value); }
}
public Builder SetType(global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneType value) {
+ PrepareBuilder();
result.hasType = true;
result.type_ = value;
return this;
}
public Builder ClearType() {
+ PrepareBuilder();
result.hasType = false;
result.type_ = global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneType.HOME;
return this;
@@ -523,11 +561,16 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
public static Person ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
}
+ private Person MakeReadOnly() {
+ phone_.MakeReadOnly();
+ return this;
+ }
+
public static Builder CreateBuilder() { return new Builder(); }
public override Builder ToBuilder() { return CreateBuilder(this); }
public override Builder CreateBuilderForType() { return new Builder(); }
public static Builder CreateBuilder(Person prototype) {
- return (Builder) new Builder().MergeFrom(prototype);
+ return new Builder(prototype);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -537,21 +580,48 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
protected override Builder ThisBuilder {
get { return this; }
}
- public Builder() {}
+ public Builder() {
+ result = DefaultInstance;
+ resultIsReadOnly = true;
+ }
+ internal Builder(Person cloneFrom) {
+ result = cloneFrom;
+ resultIsReadOnly = true;
+ }
- Person result = new Person();
+ private bool resultIsReadOnly;
+ private Person result;
+
+ private Person PrepareBuilder() {
+ if (resultIsReadOnly) {
+ Person original = result;
+ result = new Person();
+ resultIsReadOnly = false;
+ MergeFrom(original);
+ }
+ return result;
+ }
+
+ public override bool IsInitialized {
+ get { return result.IsInitialized; }
+ }
protected override Person MessageBeingBuilt {
- get { return result; }
+ get { return PrepareBuilder(); }
}
public override Builder Clear() {
- result = new Person();
+ result = DefaultInstance;
+ resultIsReadOnly = true;
return this;
}
public override Builder Clone() {
- return new Builder().MergeFrom(result);
+ if (resultIsReadOnly) {
+ return new Builder(result);
+ } else {
+ return new Builder().MergeFrom(result);
+ }
}
public override pbd::MessageDescriptor DescriptorForType {
@@ -563,13 +633,11 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override Person BuildPartial() {
- if (result == null) {
- throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+ if (resultIsReadOnly) {
+ return result;
}
- result.phone_.MakeReadOnly();
- Person returnMe = result;
- result = null;
- return returnMe;
+ resultIsReadOnly = true;
+ return result.MakeReadOnly();
}
public override Builder MergeFrom(pb::IMessage other) {
@@ -583,6 +651,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
public override Builder MergeFrom(Person other) {
if (other == global::Google.ProtocolBuffers.Examples.AddressBook.Person.DefaultInstance) return this;
+ PrepareBuilder();
if (other.HasName) {
Name = other.Name;
}
@@ -593,7 +662,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
Email = other.Email;
}
if (other.phone_.Count != 0) {
- base.AddRange(other.phone_, result.phone_);
+ result.phone_.Add(other.phone_);
}
this.MergeUnknownFields(other.UnknownFields);
return this;
@@ -604,6 +673,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+ PrepareBuilder();
pb::UnknownFieldSet.Builder unknownFields = null;
uint tag;
string field_name;
@@ -672,11 +742,13 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public Builder SetName(string value) {
pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
result.hasName = true;
result.name_ = value;
return this;
}
public Builder ClearName() {
+ PrepareBuilder();
result.hasName = false;
result.name_ = "";
return this;
@@ -690,11 +762,13 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
set { SetId(value); }
}
public Builder SetId(int value) {
+ PrepareBuilder();
result.hasId = true;
result.id_ = value;
return this;
}
public Builder ClearId() {
+ PrepareBuilder();
result.hasId = false;
result.id_ = 0;
return this;
@@ -709,18 +783,20 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public Builder SetEmail(string value) {
pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
result.hasEmail = true;
result.email_ = value;
return this;
}
public Builder ClearEmail() {
+ PrepareBuilder();
result.hasEmail = false;
result.email_ = "";
return this;
}
public pbc::IPopsicleList PhoneList {
- get { return result.phone_; }
+ get { return PrepareBuilder().phone_; }
}
public int PhoneCount {
get { return result.PhoneCount; }
@@ -730,29 +806,35 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public Builder SetPhone(int index, global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber value) {
pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
result.phone_[index] = value;
return this;
}
public Builder SetPhone(int index, global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber.Builder builderForValue) {
pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+ PrepareBuilder();
result.phone_[index] = builderForValue.Build();
return this;
}
public Builder AddPhone(global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber value) {
pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
result.phone_.Add(value);
return this;
}
public Builder AddPhone(global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber.Builder builderForValue) {
pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+ PrepareBuilder();
result.phone_.Add(builderForValue.Build());
return this;
}
public Builder AddRangePhone(scg::IEnumerable values) {
- base.AddRange(values, result.phone_);
+ PrepareBuilder();
+ result.phone_.Add(values);
return this;
}
public Builder ClearPhone() {
+ PrepareBuilder();
result.phone_.Clear();
return this;
}
@@ -766,7 +848,8 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.3.0.277")]
public sealed partial class AddressBook : pb::GeneratedMessage {
- private static readonly AddressBook defaultInstance = new Builder().BuildPartial();
+ private AddressBook() { }
+ private static readonly AddressBook defaultInstance = new AddressBook().MakeReadOnly();
private static readonly string[] _addressBookFieldNames = new string[] { "person" };
private static readonly uint[] _addressBookFieldTags = new uint[] { 10 };
public static AddressBook DefaultInstance {
@@ -774,7 +857,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override AddressBook DefaultInstanceForType {
- get { return defaultInstance; }
+ get { return DefaultInstance; }
}
protected override AddressBook ThisMessage {
@@ -865,11 +948,16 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
public static AddressBook ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
}
+ private AddressBook MakeReadOnly() {
+ person_.MakeReadOnly();
+ return this;
+ }
+
public static Builder CreateBuilder() { return new Builder(); }
public override Builder ToBuilder() { return CreateBuilder(this); }
public override Builder CreateBuilderForType() { return new Builder(); }
public static Builder CreateBuilder(AddressBook prototype) {
- return (Builder) new Builder().MergeFrom(prototype);
+ return new Builder(prototype);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -879,21 +967,48 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
protected override Builder ThisBuilder {
get { return this; }
}
- public Builder() {}
+ public Builder() {
+ result = DefaultInstance;
+ resultIsReadOnly = true;
+ }
+ internal Builder(AddressBook cloneFrom) {
+ result = cloneFrom;
+ resultIsReadOnly = true;
+ }
+
+ private bool resultIsReadOnly;
+ private AddressBook result;
- AddressBook result = new AddressBook();
+ private AddressBook PrepareBuilder() {
+ if (resultIsReadOnly) {
+ AddressBook original = result;
+ result = new AddressBook();
+ resultIsReadOnly = false;
+ MergeFrom(original);
+ }
+ return result;
+ }
+
+ public override bool IsInitialized {
+ get { return result.IsInitialized; }
+ }
protected override AddressBook MessageBeingBuilt {
- get { return result; }
+ get { return PrepareBuilder(); }
}
public override Builder Clear() {
- result = new AddressBook();
+ result = DefaultInstance;
+ resultIsReadOnly = true;
return this;
}
public override Builder Clone() {
- return new Builder().MergeFrom(result);
+ if (resultIsReadOnly) {
+ return new Builder(result);
+ } else {
+ return new Builder().MergeFrom(result);
+ }
}
public override pbd::MessageDescriptor DescriptorForType {
@@ -905,13 +1020,11 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override AddressBook BuildPartial() {
- if (result == null) {
- throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+ if (resultIsReadOnly) {
+ return result;
}
- result.person_.MakeReadOnly();
- AddressBook returnMe = result;
- result = null;
- return returnMe;
+ resultIsReadOnly = true;
+ return result.MakeReadOnly();
}
public override Builder MergeFrom(pb::IMessage other) {
@@ -925,8 +1038,9 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
public override Builder MergeFrom(AddressBook other) {
if (other == global::Google.ProtocolBuffers.Examples.AddressBook.AddressBook.DefaultInstance) return this;
+ PrepareBuilder();
if (other.person_.Count != 0) {
- base.AddRange(other.person_, result.person_);
+ result.person_.Add(other.person_);
}
this.MergeUnknownFields(other.UnknownFields);
return this;
@@ -937,6 +1051,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+ PrepareBuilder();
pb::UnknownFieldSet.Builder unknownFields = null;
uint tag;
string field_name;
@@ -985,7 +1100,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
public pbc::IPopsicleList PersonList {
- get { return result.person_; }
+ get { return PrepareBuilder().person_; }
}
public int PersonCount {
get { return result.PersonCount; }
@@ -995,29 +1110,35 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public Builder SetPerson(int index, global::Google.ProtocolBuffers.Examples.AddressBook.Person value) {
pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
result.person_[index] = value;
return this;
}
public Builder SetPerson(int index, global::Google.ProtocolBuffers.Examples.AddressBook.Person.Builder builderForValue) {
pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+ PrepareBuilder();
result.person_[index] = builderForValue.Build();
return this;
}
public Builder AddPerson(global::Google.ProtocolBuffers.Examples.AddressBook.Person value) {
pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
result.person_.Add(value);
return this;
}
public Builder AddPerson(global::Google.ProtocolBuffers.Examples.AddressBook.Person.Builder builderForValue) {
pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+ PrepareBuilder();
result.person_.Add(builderForValue.Build());
return this;
}
public Builder AddRangePerson(scg::IEnumerable values) {
- base.AddRange(values, result.person_);
+ PrepareBuilder();
+ result.person_.Add(values);
return this;
}
public Builder ClearPerson() {
+ PrepareBuilder();
result.person_.Clear();
return this;
}
diff --git a/src/ProtoGen.Test/DependencyResolutionTest.cs b/src/ProtoGen.Test/DependencyResolutionTest.cs
index 8ac5b348af..c4422b8c90 100644
--- a/src/ProtoGen.Test/DependencyResolutionTest.cs
+++ b/src/ProtoGen.Test/DependencyResolutionTest.cs
@@ -52,7 +52,7 @@ namespace Google.ProtocolBuffers.ProtoGen
{
FileDescriptorProto first = new FileDescriptorProto.Builder {Name = "First"}.Build();
FileDescriptorProto second = new FileDescriptorProto.Builder {Name = "Second"}.Build();
- FileDescriptorSet set = new FileDescriptorSet {FileList = {first, second}};
+ FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first, second } }.Build();
IList converted = Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);
Assert.AreEqual(2, converted.Count);
@@ -68,7 +68,7 @@ namespace Google.ProtocolBuffers.ProtoGen
FileDescriptorProto first =
new FileDescriptorProto.Builder {Name = "First", DependencyList = {"Second"}}.Build();
FileDescriptorProto second = new FileDescriptorProto.Builder {Name = "Second"}.Build();
- FileDescriptorSet set = new FileDescriptorSet {FileList = {first, second}};
+ FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first, second } }.Build();
IList converted = Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);
Assert.AreEqual(2, converted.Count);
Assert.AreEqual("First", converted[0].Name);
@@ -84,7 +84,7 @@ namespace Google.ProtocolBuffers.ProtoGen
FileDescriptorProto first = new FileDescriptorProto.Builder {Name = "First"}.Build();
FileDescriptorProto second =
new FileDescriptorProto.Builder {Name = "Second", DependencyList = {"First"}}.Build();
- FileDescriptorSet set = new FileDescriptorSet {FileList = {first, second}};
+ FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first, second } }.Build();
IList converted = Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);
Assert.AreEqual(2, converted.Count);
Assert.AreEqual("First", converted[0].Name);
@@ -101,7 +101,7 @@ namespace Google.ProtocolBuffers.ProtoGen
new FileDescriptorProto.Builder {Name = "First", DependencyList = {"Second"}}.Build();
FileDescriptorProto second =
new FileDescriptorProto.Builder {Name = "Second", DependencyList = {"First"}}.Build();
- FileDescriptorSet set = new FileDescriptorSet {FileList = {first, second}};
+ FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first, second } }.Build();
try
{
Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);
@@ -118,7 +118,7 @@ namespace Google.ProtocolBuffers.ProtoGen
{
FileDescriptorProto first =
new FileDescriptorProto.Builder {Name = "First", DependencyList = {"Second"}}.Build();
- FileDescriptorSet set = new FileDescriptorSet {FileList = {first}};
+ FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first } }.Build();
try
{
Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);
@@ -135,7 +135,7 @@ namespace Google.ProtocolBuffers.ProtoGen
{
FileDescriptorProto first =
new FileDescriptorProto.Builder {Name = "First", DependencyList = {"First"}}.Build();
- FileDescriptorSet set = new FileDescriptorSet {FileList = {first}};
+ FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first } }.Build();
try
{
Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);
diff --git a/src/ProtoGen/EnumFieldGenerator.cs b/src/ProtoGen/EnumFieldGenerator.cs
index 8b56b9e96b..8d70bc6765 100644
--- a/src/ProtoGen/EnumFieldGenerator.cs
+++ b/src/ProtoGen/EnumFieldGenerator.cs
@@ -49,10 +49,11 @@ namespace Google.ProtocolBuffers.ProtoGen
{
writer.WriteLine("private bool has{0};", PropertyName);
writer.WriteLine("private {0} {1}_ = {2};", TypeName, Name, DefaultValue);
+ AddDeprecatedFlag(writer);
writer.WriteLine("public bool Has{0} {{", PropertyName);
writer.WriteLine(" get {{ return has{0}; }}", PropertyName);
writer.WriteLine("}");
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return {0}_; }}", Name);
writer.WriteLine("}");
@@ -60,21 +61,25 @@ namespace Google.ProtocolBuffers.ProtoGen
public void GenerateBuilderMembers(TextGenerator writer)
{
+ AddDeprecatedFlag(writer);
writer.WriteLine("public bool Has{0} {{", PropertyName);
writer.WriteLine(" get {{ return result.has{0}; }}", PropertyName);
writer.WriteLine("}");
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return result.{0}; }}", PropertyName);
writer.WriteLine(" set {{ Set{0}(value); }}", PropertyName);
writer.WriteLine("}");
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public Builder Set{0}({1} value) {{", PropertyName, TypeName);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.has{0} = true;", PropertyName);
writer.WriteLine(" result.{0}_ = value;", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.has{0} = false;", PropertyName);
writer.WriteLine(" result.{0}_ = {1};", Name, DefaultValue);
writer.WriteLine(" return this;");
diff --git a/src/ProtoGen/FieldGeneratorBase.cs b/src/ProtoGen/FieldGeneratorBase.cs
index 54294196cd..93aee6cad9 100644
--- a/src/ProtoGen/FieldGeneratorBase.cs
+++ b/src/ProtoGen/FieldGeneratorBase.cs
@@ -251,6 +251,12 @@ namespace Google.ProtocolBuffers.ProtoGen
}
}
+ protected void AddPublicMemberAttributes(TextGenerator writer)
+ {
+ AddDeprecatedFlag(writer);
+ AddClsComplianceCheck(writer);
+ }
+
protected void AddClsComplianceCheck(TextGenerator writer)
{
if (!Descriptor.IsCLSCompliant && Descriptor.File.CSharpOptions.ClsCompliance)
@@ -259,6 +265,19 @@ namespace Google.ProtocolBuffers.ProtoGen
}
}
+ protected bool IsObsolete { get { return Descriptor.Options.Deprecated; } }
+
+ ///
+ /// Writes [global::System.ObsoleteAttribute()] if the member is obsolete
+ ///
+ protected void AddDeprecatedFlag(TextGenerator writer)
+ {
+ if (IsObsolete)
+ {
+ writer.WriteLine("[global::System.ObsoleteAttribute()]");
+ }
+ }
+
///
/// For encodings with fixed sizes, returns that size in bytes. Otherwise
/// returns -1. TODO(jonskeet): Make this less ugly.
diff --git a/src/ProtoGen/MessageFieldGenerator.cs b/src/ProtoGen/MessageFieldGenerator.cs
index b86f2c9adf..25b58a6057 100644
--- a/src/ProtoGen/MessageFieldGenerator.cs
+++ b/src/ProtoGen/MessageFieldGenerator.cs
@@ -48,38 +48,48 @@ namespace Google.ProtocolBuffers.ProtoGen
public void GenerateMembers(TextGenerator writer)
{
writer.WriteLine("private bool has{0};", PropertyName);
- writer.WriteLine("private {0} {1}_ = {2};", TypeName, Name, DefaultValue);
+ writer.WriteLine("private {0} {1}_;", TypeName, Name);
+ AddDeprecatedFlag(writer);
writer.WriteLine("public bool Has{0} {{", PropertyName);
writer.WriteLine(" get {{ return has{0}; }}", PropertyName);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
- writer.WriteLine(" get {{ return {0}_; }}", Name);
+ writer.WriteLine(" get {{ return {0}_ ?? {1}; }}", Name, DefaultValue);
writer.WriteLine("}");
}
public void GenerateBuilderMembers(TextGenerator writer)
{
+ AddDeprecatedFlag(writer);
writer.WriteLine("public bool Has{0} {{", PropertyName);
writer.WriteLine(" get {{ return result.has{0}; }}", PropertyName);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return result.{0}; }}", PropertyName);
writer.WriteLine(" set {{ Set{0}(value); }}", PropertyName);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Set{0}({1} value) {{", PropertyName, TypeName);
AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.has{0} = true;", PropertyName);
writer.WriteLine(" result.{0}_ = value;", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Set{0}({1}.Builder builderForValue) {{", PropertyName, TypeName);
AddNullCheck(writer, "builderForValue");
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.has{0} = true;", PropertyName);
writer.WriteLine(" result.{0}_ = builderForValue.Build();", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Merge{0}({1} value) {{", PropertyName, TypeName);
AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" if (result.has{0} &&", PropertyName);
writer.WriteLine(" result.{0}_ != {1}) {{", Name, DefaultValue);
writer.WriteLine(" result.{0}_ = {1}.CreateBuilder(result.{0}_).MergeFrom(value).BuildPartial();", Name,
@@ -90,9 +100,11 @@ namespace Google.ProtocolBuffers.ProtoGen
writer.WriteLine(" result.has{0} = true;", PropertyName);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.has{0} = false;", PropertyName);
- writer.WriteLine(" result.{0}_ = {1};", Name, DefaultValue);
+ writer.WriteLine(" result.{0}_ = null;", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
}
diff --git a/src/ProtoGen/MessageGenerator.cs b/src/ProtoGen/MessageGenerator.cs
index 83004da923..e9a037bf6d 100644
--- a/src/ProtoGen/MessageGenerator.cs
+++ b/src/ProtoGen/MessageGenerator.cs
@@ -181,8 +181,9 @@ namespace Google.ProtocolBuffers.ProtoGen
Descriptor.Proto.ExtensionRangeCount > 0 ? "Extendable" : "Generated",
RuntimeSuffix);
writer.Indent();
+ writer.WriteLine("private {0}() {{ }}", ClassName);
// Must call BuildPartial() to make sure all lists are made read-only
- writer.WriteLine("private static readonly {0} defaultInstance = new Builder().BuildPartial();", ClassName);
+ writer.WriteLine("private static readonly {0} defaultInstance = new {0}().MakeReadOnly();", ClassName);
if (OptimizeSpeed)
{
@@ -203,7 +204,7 @@ namespace Google.ProtocolBuffers.ProtoGen
writer.WriteLine("}");
writer.WriteLine();
writer.WriteLine("public override {0} DefaultInstanceForType {{", ClassName);
- writer.WriteLine(" get { return defaultInstance; }");
+ writer.WriteLine(" get { return DefaultInstance; }");
writer.WriteLine("}");
writer.WriteLine();
writer.WriteLine("protected override {0} ThisMessage {{", ClassName);
@@ -551,11 +552,22 @@ namespace Google.ProtocolBuffers.ProtoGen
private void GenerateBuilder(TextGenerator writer)
{
+ writer.WriteLine("private {0} MakeReadOnly() {{", ClassName);
+ writer.Indent();
+ foreach (FieldDescriptor field in Descriptor.Fields)
+ {
+ CreateFieldGenerator(field).GenerateBuildingCode(writer);
+ }
+ writer.WriteLine("return this;");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+
writer.WriteLine("public static Builder CreateBuilder() { return new Builder(); }");
writer.WriteLine("public override Builder ToBuilder() { return CreateBuilder(this); }");
writer.WriteLine("public override Builder CreateBuilderForType() { return new Builder(); }");
writer.WriteLine("public static Builder CreateBuilder({0} prototype) {{", ClassName);
- writer.WriteLine(" return (Builder) new Builder().MergeFrom(prototype);");
+ writer.WriteLine(" return new Builder(prototype);");
writer.WriteLine("}");
writer.WriteLine();
if (Descriptor.File.CSharpOptions.AddSerializable)
@@ -590,21 +602,52 @@ namespace Google.ProtocolBuffers.ProtoGen
private void GenerateCommonBuilderMethods(TextGenerator writer)
{
- writer.WriteLine("public Builder() {{}}", ClassAccessLevel);
+ //default constructor
+ writer.WriteLine("public Builder() {");
+ //Durring static initialization of message, DefaultInstance is expected to return null.
+ writer.WriteLine(" result = DefaultInstance;");
+ writer.WriteLine(" resultIsReadOnly = true;");
+ writer.WriteLine("}");
+ //clone constructor
+ writer.WriteLine("internal Builder({0} cloneFrom) {{", ClassName);
+ writer.WriteLine(" result = cloneFrom;");
+ writer.WriteLine(" resultIsReadOnly = true;");
+ writer.WriteLine("}");
writer.WriteLine();
- writer.WriteLine("{0} result = new {0}();", ClassName);
+ writer.WriteLine("private bool resultIsReadOnly;");
+ writer.WriteLine("private {0} result;", ClassName);
+ writer.WriteLine();
+ writer.WriteLine("private {0} PrepareBuilder() {{", ClassName);
+ writer.WriteLine(" if (resultIsReadOnly) {");
+ writer.WriteLine(" {0} original = result;", ClassName);
+ writer.WriteLine(" result = new {0}();", ClassName);
+ writer.WriteLine(" resultIsReadOnly = false;");
+ writer.WriteLine(" MergeFrom(original);");
+ writer.WriteLine(" }");
+ writer.WriteLine(" return result;");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("public override bool IsInitialized {");
+ writer.WriteLine(" get { return result.IsInitialized; }");
+ writer.WriteLine("}");
writer.WriteLine();
writer.WriteLine("protected override {0} MessageBeingBuilt {{", ClassName);
- writer.WriteLine(" get { return result; }");
+ writer.WriteLine(" get { return PrepareBuilder(); }");
writer.WriteLine("}");
writer.WriteLine();
+ //Not actually expecting that DefaultInstance would ever be null here; however, we will ensure it does not break
writer.WriteLine("public override Builder Clear() {");
- writer.WriteLine(" result = new {0}();", ClassName);
+ writer.WriteLine(" result = DefaultInstance;", ClassName);
+ writer.WriteLine(" resultIsReadOnly = true;");
writer.WriteLine(" return this;");
writer.WriteLine("}");
writer.WriteLine();
writer.WriteLine("public override Builder Clone() {");
- writer.WriteLine(" return new Builder().MergeFrom(result);");
+ writer.WriteLine(" if (resultIsReadOnly) {");
+ writer.WriteLine(" return new Builder(result);");
+ writer.WriteLine(" } else {");
+ writer.WriteLine(" return new Builder().MergeFrom(result);");
+ writer.WriteLine(" }");
writer.WriteLine("}");
writer.WriteLine();
if (!UseLiteRuntime)
@@ -621,17 +664,11 @@ namespace Google.ProtocolBuffers.ProtoGen
writer.WriteLine("public override {0} BuildPartial() {{", ClassName);
writer.Indent();
- writer.WriteLine("if (result == null) {");
- writer.WriteLine(
- " throw new global::System.InvalidOperationException(\"build() has already been called on this Builder\");");
+ writer.WriteLine("if (resultIsReadOnly) {");
+ writer.WriteLine(" return result;");
writer.WriteLine("}");
- foreach (FieldDescriptor field in Descriptor.Fields)
- {
- CreateFieldGenerator(field).GenerateBuildingCode(writer);
- }
- writer.WriteLine("{0} returnMe = result;", ClassName);
- writer.WriteLine("result = null;");
- writer.WriteLine("return returnMe;");
+ writer.WriteLine("resultIsReadOnly = true;");
+ writer.WriteLine("return result.MakeReadOnly();");
writer.Outdent();
writer.WriteLine("}");
writer.WriteLine();
@@ -652,6 +689,7 @@ namespace Google.ProtocolBuffers.ProtoGen
// fields are set so we can skip the merge.
writer.Indent();
writer.WriteLine("if (other == {0}.DefaultInstance) return this;", FullClassName);
+ writer.WriteLine("PrepareBuilder();");
foreach (FieldDescriptor field in Descriptor.Fields)
{
CreateFieldGenerator(field).GenerateMergingCode(writer);
@@ -684,6 +722,7 @@ namespace Google.ProtocolBuffers.ProtoGen
writer.WriteLine(
"public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {");
writer.Indent();
+ writer.WriteLine("PrepareBuilder();");
if (!UseLiteRuntime)
{
writer.WriteLine("pb::UnknownFieldSet.Builder unknownFields = null;");
diff --git a/src/ProtoGen/PrimitiveFieldGenerator.cs b/src/ProtoGen/PrimitiveFieldGenerator.cs
index e945bf877f..69e0d4d933 100644
--- a/src/ProtoGen/PrimitiveFieldGenerator.cs
+++ b/src/ProtoGen/PrimitiveFieldGenerator.cs
@@ -50,10 +50,11 @@ namespace Google.ProtocolBuffers.ProtoGen
{
writer.WriteLine("private bool has{0};", PropertyName);
writer.WriteLine("private {0} {1}_{2};", TypeName, Name, HasDefaultValue ? " = " + DefaultValue : "");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public bool Has{0} {{", PropertyName);
writer.WriteLine(" get {{ return has{0}; }}", PropertyName);
writer.WriteLine("}");
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return {0}_; }}", Name);
writer.WriteLine("}");
@@ -61,22 +62,26 @@ namespace Google.ProtocolBuffers.ProtoGen
public void GenerateBuilderMembers(TextGenerator writer)
{
+ AddDeprecatedFlag(writer);
writer.WriteLine("public bool Has{0} {{", PropertyName);
writer.WriteLine(" get {{ return result.has{0}; }}", PropertyName);
writer.WriteLine("}");
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return result.{0}; }}", PropertyName);
writer.WriteLine(" set {{ Set{0}(value); }}", PropertyName);
writer.WriteLine("}");
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public Builder Set{0}({1} value) {{", PropertyName, TypeName);
AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.has{0} = true;", PropertyName);
writer.WriteLine(" result.{0}_ = value;", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.has{0} = false;", PropertyName);
writer.WriteLine(" result.{0}_ = {1};", Name, DefaultValue);
writer.WriteLine(" return this;");
diff --git a/src/ProtoGen/RepeatedEnumFieldGenerator.cs b/src/ProtoGen/RepeatedEnumFieldGenerator.cs
index 5880390b99..8c9f17b8dc 100644
--- a/src/ProtoGen/RepeatedEnumFieldGenerator.cs
+++ b/src/ProtoGen/RepeatedEnumFieldGenerator.cs
@@ -52,15 +52,18 @@ namespace Google.ProtocolBuffers.ProtoGen
writer.WriteLine("private int {0}MemoizedSerializedSize;", Name);
}
writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
+ AddDeprecatedFlag(writer);
writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return pbc::Lists.AsReadOnly({0}_); }}", Name);
writer.WriteLine("}");
// TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option.
+ AddDeprecatedFlag(writer);
writer.WriteLine("public int {0}Count {{", PropertyName);
writer.WriteLine(" get {{ return {0}_.Count; }}", Name);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
writer.WriteLine(" return {0}_[index];", Name);
writer.WriteLine("}");
@@ -70,28 +73,39 @@ namespace Google.ProtocolBuffers.ProtoGen
{
// Note: We can return the original list here, because we make it unmodifiable when we build
// We return it via IPopsicleList so that collection initializers work more pleasantly.
+ AddDeprecatedFlag(writer);
writer.WriteLine("public pbc::IPopsicleList<{0}> {1}List {{", TypeName, PropertyName);
- writer.WriteLine(" get {{ return result.{0}_; }}", Name);
+ writer.WriteLine(" get {{ return PrepareBuilder().{0}_; }}", Name);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public int {0}Count {{", PropertyName);
writer.WriteLine(" get {{ return result.{0}Count; }}", PropertyName);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
writer.WriteLine(" return result.Get{0}(index);", PropertyName);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Set{0}(int index, {1} value) {{", PropertyName, TypeName);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.{0}_[index] = value;", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Add{0}({1} value) {{", PropertyName, TypeName);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.{0}_.Add(value);", Name, TypeName);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder AddRange{0}(scg::IEnumerable<{1}> values) {{", PropertyName, TypeName);
- writer.WriteLine(" base.AddRange(values, result.{0}_);", Name);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Add(values);", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.{0}_.Clear();", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
@@ -100,13 +114,13 @@ namespace Google.ProtocolBuffers.ProtoGen
public void GenerateMergingCode(TextGenerator writer)
{
writer.WriteLine("if (other.{0}_.Count != 0) {{", Name);
- writer.WriteLine(" base.AddRange(other.{0}_, result.{0}_);", Name);
+ writer.WriteLine(" result.{0}_.Add(other.{0}_);", Name);
writer.WriteLine("}");
}
public void GenerateBuildingCode(TextGenerator writer)
{
- writer.WriteLine("result.{0}_.MakeReadOnly();", Name);
+ writer.WriteLine("{0}_.MakeReadOnly();", Name);
}
public void GenerateParsingCode(TextGenerator writer)
diff --git a/src/ProtoGen/RepeatedMessageFieldGenerator.cs b/src/ProtoGen/RepeatedMessageFieldGenerator.cs
index bfa0763f6f..a9a0143ca8 100644
--- a/src/ProtoGen/RepeatedMessageFieldGenerator.cs
+++ b/src/ProtoGen/RepeatedMessageFieldGenerator.cs
@@ -48,15 +48,18 @@ namespace Google.ProtocolBuffers.ProtoGen
public void GenerateMembers(TextGenerator writer)
{
writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
+ AddDeprecatedFlag(writer);
writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return {0}_; }}", Name);
writer.WriteLine("}");
// TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option.
+ AddDeprecatedFlag(writer);
writer.WriteLine("public int {0}Count {{", PropertyName);
writer.WriteLine(" get {{ return {0}_.Count; }}", Name);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
writer.WriteLine(" return {0}_[index];", Name);
writer.WriteLine("}");
@@ -66,42 +69,57 @@ namespace Google.ProtocolBuffers.ProtoGen
{
// Note: We can return the original list here, because we make it unmodifiable when we build
// We return it via IPopsicleList so that collection initializers work more pleasantly.
+ AddDeprecatedFlag(writer);
writer.WriteLine("public pbc::IPopsicleList<{0}> {1}List {{", TypeName, PropertyName);
- writer.WriteLine(" get {{ return result.{0}_; }}", Name);
+ writer.WriteLine(" get {{ return PrepareBuilder().{0}_; }}", Name);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public int {0}Count {{", PropertyName);
writer.WriteLine(" get {{ return result.{0}Count; }}", PropertyName);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
writer.WriteLine(" return result.Get{0}(index);", PropertyName);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Set{0}(int index, {1} value) {{", PropertyName, TypeName);
AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.{0}_[index] = value;", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
// Extra overload for builder (just on messages)
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Set{0}(int index, {1}.Builder builderForValue) {{", PropertyName, TypeName);
AddNullCheck(writer, "builderForValue");
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.{0}_[index] = builderForValue.Build();", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Add{0}({1} value) {{", PropertyName, TypeName);
AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.{0}_.Add(value);", Name, TypeName);
writer.WriteLine(" return this;");
writer.WriteLine("}");
// Extra overload for builder (just on messages)
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Add{0}({1}.Builder builderForValue) {{", PropertyName, TypeName);
AddNullCheck(writer, "builderForValue");
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.{0}_.Add(builderForValue.Build());", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder AddRange{0}(scg::IEnumerable<{1}> values) {{", PropertyName, TypeName);
- writer.WriteLine(" base.AddRange(values, result.{0}_);", Name);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Add(values);", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.{0}_.Clear();", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
@@ -110,13 +128,13 @@ namespace Google.ProtocolBuffers.ProtoGen
public void GenerateMergingCode(TextGenerator writer)
{
writer.WriteLine("if (other.{0}_.Count != 0) {{", Name);
- writer.WriteLine(" base.AddRange(other.{0}_, result.{0}_);", Name);
+ writer.WriteLine(" result.{0}_.Add(other.{0}_);", Name);
writer.WriteLine("}");
}
public void GenerateBuildingCode(TextGenerator writer)
{
- writer.WriteLine("result.{0}_.MakeReadOnly();", Name);
+ writer.WriteLine("{0}_.MakeReadOnly();", Name);
}
public void GenerateParsingCode(TextGenerator writer)
diff --git a/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs b/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs
index 9e7f5f641f..b795f3b64f 100644
--- a/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs
+++ b/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs
@@ -52,17 +52,18 @@ namespace Google.ProtocolBuffers.ProtoGen
writer.WriteLine("private int {0}MemoizedSerializedSize;", Name);
}
writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return pbc::Lists.AsReadOnly({0}_); }}", Name);
writer.WriteLine("}");
// TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option.
+ AddDeprecatedFlag(writer);
writer.WriteLine("public int {0}Count {{", PropertyName);
writer.WriteLine(" get {{ return {0}_.Count; }}", Name);
writer.WriteLine("}");
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
writer.WriteLine(" return {0}_[index];", Name);
writer.WriteLine("}");
@@ -72,35 +73,41 @@ namespace Google.ProtocolBuffers.ProtoGen
{
// Note: We can return the original list here, because we make it unmodifiable when we build
// We return it via IPopsicleList so that collection initializers work more pleasantly.
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public pbc::IPopsicleList<{0}> {1}List {{", TypeName, PropertyName);
- writer.WriteLine(" get {{ return result.{0}_; }}", Name);
+ writer.WriteLine(" get {{ return PrepareBuilder().{0}_; }}", Name);
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public int {0}Count {{", PropertyName);
writer.WriteLine(" get {{ return result.{0}Count; }}", PropertyName);
writer.WriteLine("}");
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
writer.WriteLine(" return result.Get{0}(index);", PropertyName);
writer.WriteLine("}");
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public Builder Set{0}(int index, {1} value) {{", PropertyName, TypeName);
AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.{0}_[index] = value;", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public Builder Add{0}({1} value) {{", PropertyName, TypeName);
AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.{0}_.Add(value);", Name, TypeName);
writer.WriteLine(" return this;");
writer.WriteLine("}");
- AddClsComplianceCheck(writer);
+ AddPublicMemberAttributes(writer);
writer.WriteLine("public Builder AddRange{0}(scg::IEnumerable<{1}> values) {{", PropertyName, TypeName);
- writer.WriteLine(" base.AddRange(values, result.{0}_);", Name);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Add(values);", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
writer.WriteLine(" result.{0}_.Clear();", Name);
writer.WriteLine(" return this;");
writer.WriteLine("}");
@@ -109,13 +116,13 @@ namespace Google.ProtocolBuffers.ProtoGen
public void GenerateMergingCode(TextGenerator writer)
{
writer.WriteLine("if (other.{0}_.Count != 0) {{", Name);
- writer.WriteLine(" base.AddRange(other.{0}_, result.{0}_);", Name);
+ writer.WriteLine(" result.{0}_.Add(other.{0}_);", Name);
writer.WriteLine("}");
}
public void GenerateBuildingCode(TextGenerator writer)
{
- writer.WriteLine("result.{0}_.MakeReadOnly();", Name);
+ writer.WriteLine("{0}_.MakeReadOnly();", Name);
}
public void GenerateParsingCode(TextGenerator writer)
diff --git a/src/ProtoGen/UmbrellaClassGenerator.cs b/src/ProtoGen/UmbrellaClassGenerator.cs
index 57a7844b69..e425045876 100644
--- a/src/ProtoGen/UmbrellaClassGenerator.cs
+++ b/src/ProtoGen/UmbrellaClassGenerator.cs
@@ -138,8 +138,8 @@ namespace Google.ProtocolBuffers.ProtoGen
private void WriteIntroduction(TextGenerator writer)
{
- writer.WriteLine("// Generated by {0}. DO NOT EDIT!", this.GetType().Assembly.FullName);
- writer.WriteLine("#pragma warning disable 1591");
+ writer.WriteLine("// Generated by {0}. DO NOT EDIT!", this.GetType().Assembly.FullName);
+ writer.WriteLine("#pragma warning disable 1591, 0612");
writer.WriteLine("#region Designer generated code");
writer.WriteLine();
diff --git a/src/ProtocolBuffers.Serialization/AbstractReader.cs b/src/ProtocolBuffers.Serialization/AbstractReader.cs
index f54c270713..f3e6fd6f4d 100644
--- a/src/ProtocolBuffers.Serialization/AbstractReader.cs
+++ b/src/ProtocolBuffers.Serialization/AbstractReader.cs
@@ -17,12 +17,6 @@ namespace Google.ProtocolBuffers.Serialization
/// Constructs a new reader
protected AbstractReader() { MaxDepth = DefaultMaxDepth; }
- /// Constructs a new child reader
- protected AbstractReader(AbstractReader copyFrom)
- {
- _depth = copyFrom._depth + 1;
- MaxDepth = copyFrom.MaxDepth;
- }
/// Gets or sets the maximum recursion depth allowed
public int MaxDepth { get; set; }
@@ -112,6 +106,16 @@ namespace Google.ProtocolBuffers.Serialization
/// Merges the input stream into the provided IBuilderLite
///
protected abstract bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry);
+
+ ///
+ /// Reads the root-message preamble specific to this formatter
+ ///
+ public abstract void ReadMessageStart();
+
+ ///
+ /// Reads the root-message close specific to this formatter
+ ///
+ public abstract void ReadMessageEnd();
///
/// Merges the input stream into the provided IBuilderLite
diff --git a/src/ProtocolBuffers.Serialization/AbstractTextReader.cs b/src/ProtocolBuffers.Serialization/AbstractTextReader.cs
index 59b9057bee..ddfa643643 100644
--- a/src/ProtocolBuffers.Serialization/AbstractTextReader.cs
+++ b/src/ProtocolBuffers.Serialization/AbstractTextReader.cs
@@ -11,10 +11,6 @@ namespace Google.ProtocolBuffers.Serialization
{
/// Constructs a new reader
protected AbstractTextReader() { }
- /// Constructs a new child reader
- protected AbstractTextReader(AbstractTextReader copyFrom)
- : base(copyFrom)
- { }
///
/// Reads a typed field as a string
diff --git a/src/ProtocolBuffers.Serialization/AbstractWriter.cs b/src/ProtocolBuffers.Serialization/AbstractWriter.cs
index 6592c1dde1..1e087ec676 100644
--- a/src/ProtocolBuffers.Serialization/AbstractWriter.cs
+++ b/src/ProtocolBuffers.Serialization/AbstractWriter.cs
@@ -12,36 +12,39 @@ namespace Google.ProtocolBuffers.Serialization
///
/// Provides a base class for writers that performs some basic type dispatching
///
- public abstract class AbstractWriter : ICodedOutputStream, IDisposable
+ public abstract class AbstractWriter : ICodedOutputStream
{
///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// Completes any pending write operations
///
- public void Dispose()
+ public virtual void Flush()
{
- GC.SuppressFinalize(this);
- Flush();
- Dispose(true);
}
///
- /// Completes any pending write operations
+ /// Writes the message to the the formatted stream.
///
- public virtual void Flush()
- {
- }
+ public abstract void WriteMessage(IMessageLite message);
///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// Used to write any nessary root-message preamble. After this call you can call
+ /// IMessageLite.MergeTo(...) and complete the message with a call to WriteMessageEnd().
+ /// These three calls are identical to just calling WriteMessage(message);
///
- protected virtual void Dispose(bool disposing)
- {
- }
+ ///
+ /// AbstractWriter writer;
+ /// writer.WriteMessageStart();
+ /// message.WriteTo(writer);
+ /// writer.WriteMessageEnd();
+ /// // ... or, but not both ...
+ /// writer.WriteMessage(message);
+ ///
+ public abstract void WriteMessageStart();
///
- /// Writes the message to the the formatted stream.
+ /// Used to complete a root-message previously started with a call to WriteMessageStart()
///
- public abstract void WriteMessage(IMessageLite message);
+ public abstract void WriteMessageEnd();
///
/// Writes a Boolean value
diff --git a/src/ProtocolBuffers.Serialization/DictionaryReader.cs b/src/ProtocolBuffers.Serialization/DictionaryReader.cs
index cc5c680cb3..bb83ef9c75 100644
--- a/src/ProtocolBuffers.Serialization/DictionaryReader.cs
+++ b/src/ProtocolBuffers.Serialization/DictionaryReader.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Globalization;
using Google.ProtocolBuffers.Descriptors;
@@ -22,6 +22,18 @@ namespace Google.ProtocolBuffers.Serialization
_ready = _input.MoveNext();
}
+ ///
+ /// No-op
+ ///
+ public override void ReadMessageStart()
+ { }
+
+ ///
+ /// No-op
+ ///
+ public override void ReadMessageEnd()
+ { }
+
///
/// Merges the contents of stream into the provided message builder
///
diff --git a/src/ProtocolBuffers.Serialization/DictionaryWriter.cs b/src/ProtocolBuffers.Serialization/DictionaryWriter.cs
index 96175a7e57..6d823301a2 100644
--- a/src/ProtocolBuffers.Serialization/DictionaryWriter.cs
+++ b/src/ProtocolBuffers.Serialization/DictionaryWriter.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections;
using System.Collections.Generic;
using Google.ProtocolBuffers.Descriptors;
@@ -53,6 +53,19 @@ namespace Google.ProtocolBuffers.Serialization
message.WriteTo(this);
}
+
+ ///
+ /// No-op
+ ///
+ public override void WriteMessageStart()
+ { }
+
+ ///
+ /// No-op
+ ///
+ public override void WriteMessageEnd()
+ { }
+
///
/// Writes a Boolean value
///
diff --git a/src/ProtocolBuffers.Serialization/Http/FormUrlEncodedReader.cs b/src/ProtocolBuffers.Serialization/Http/FormUrlEncodedReader.cs
new file mode 100644
index 0000000000..508d76a941
--- /dev/null
+++ b/src/ProtocolBuffers.Serialization/Http/FormUrlEncodedReader.cs
@@ -0,0 +1,162 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace Google.ProtocolBuffers.Serialization.Http
+{
+ ///
+ /// Allows reading messages from a name/value dictionary
+ ///
+ public class FormUrlEncodedReader : AbstractTextReader
+ {
+ private readonly TextReader _input;
+ private string _fieldName, _fieldValue;
+ private bool _ready;
+
+ ///
+ /// Creates a dictionary reader from an enumeration of KeyValuePair data, like an IDictionary
+ ///
+ FormUrlEncodedReader(TextReader input)
+ {
+ _input = input;
+ int ch = input.Peek();
+ if (ch == '?')
+ {
+ input.Read();
+ }
+ _ready = ReadNext();
+ }
+
+ #region CreateInstance overloads
+ ///
+ /// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
+ ///
+ public static FormUrlEncodedReader CreateInstance(Stream stream)
+ {
+ return new FormUrlEncodedReader(new StreamReader(stream, Encoding.UTF8, false));
+ }
+
+ ///
+ /// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
+ ///
+ public static FormUrlEncodedReader CreateInstance(byte[] bytes)
+ {
+ return new FormUrlEncodedReader(new StreamReader(new MemoryStream(bytes, false), Encoding.UTF8, false));
+ }
+
+ ///
+ /// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
+ ///
+ public static FormUrlEncodedReader CreateInstance(string text)
+ {
+ return new FormUrlEncodedReader(new StringReader(text));
+ }
+
+ ///
+ /// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message.
+ ///
+ public static FormUrlEncodedReader CreateInstance(TextReader input)
+ {
+ return new FormUrlEncodedReader(input);
+ }
+ #endregion
+
+ private bool ReadNext()
+ {
+ StringBuilder field = new StringBuilder(32);
+ StringBuilder value = new StringBuilder(64);
+ int ch;
+ while (-1 != (ch = _input.Read()) && ch != '=' && ch != '&')
+ {
+ field.Append((char)ch);
+ }
+
+ if (ch != -1 && ch != '&')
+ {
+ while (-1 != (ch = _input.Read()) && ch != '&')
+ {
+ value.Append((char)ch);
+ }
+ }
+
+ _fieldName = field.ToString();
+ _fieldValue = Uri.UnescapeDataString(value.Replace('+', ' ').ToString());
+
+ return !String.IsNullOrEmpty(_fieldName);
+ }
+
+ ///
+ /// No-op
+ ///
+ public override void ReadMessageStart()
+ { }
+
+ ///
+ /// No-op
+ ///
+ public override void ReadMessageEnd()
+ { }
+
+ ///
+ /// Merges the contents of stream into the provided message builder
+ ///
+ public override TBuilder Merge(TBuilder builder, ExtensionRegistry registry)
+ {
+ builder.WeakMergeFrom(this, registry);
+ return builder;
+ }
+
+ ///
+ /// Causes the reader to skip past this field
+ ///
+ protected override void Skip()
+ {
+ _ready = ReadNext();
+ }
+
+ ///
+ /// Peeks at the next field in the input stream and returns what information is available.
+ ///
+ ///
+ /// This may be called multiple times without actually reading the field. Only after the field
+ /// is either read, or skipped, should PeekNext return a different value.
+ ///
+ protected override bool PeekNext(out string field)
+ {
+ field = _ready ? _fieldName : null;
+ return field != null;
+ }
+
+ ///
+ /// Returns true if it was able to read a String from the input
+ ///
+ protected override bool ReadAsText(ref string value, Type typeInfo)
+ {
+ if (_ready)
+ {
+ value = _fieldValue;
+ _ready = ReadNext();
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// It's unlikely this will work for anything but text data as bytes UTF8 are transformed to text and back to bytes
+ ///
+ protected override ByteString DecodeBytes(string bytes)
+ { return ByteString.CopyFromUtf8(bytes); }
+
+ ///
+ /// Not Supported
+ ///
+ public override bool ReadGroup(IBuilderLite value, ExtensionRegistry registry)
+ { throw new NotSupportedException(); }
+
+ ///
+ /// Not Supported
+ ///
+ protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry)
+ { throw new NotSupportedException(); }
+ }
+}
\ No newline at end of file
diff --git a/src/ProtocolBuffers.Serialization/Http/MessageFormatFactory.cs b/src/ProtocolBuffers.Serialization/Http/MessageFormatFactory.cs
new file mode 100644
index 0000000000..52fff83fc3
--- /dev/null
+++ b/src/ProtocolBuffers.Serialization/Http/MessageFormatFactory.cs
@@ -0,0 +1,153 @@
+using System;
+using System.IO;
+using System.Xml;
+using System.Text;
+
+namespace Google.ProtocolBuffers.Serialization.Http
+{
+ ///
+ /// Extensions and helpers to abstract the reading/writing of messages by a client-specified content type.
+ ///
+ public static class MessageFormatFactory
+ {
+ ///
+ /// Constructs an ICodedInputStream from the input stream based on the contentType provided
+ ///
+ /// Options specific to reading this message and/or content type
+ /// The mime type of the input stream content
+ /// The stream to read the message from
+ /// The ICodedInputStream that can be given to the IBuilder.MergeFrom(...) method
+ public static ICodedInputStream CreateInputStream(MessageFormatOptions options, string contentType, Stream input)
+ {
+ ICodedInputStream codedInput = ContentTypeToInputStream(contentType, options, input);
+
+ if (codedInput is XmlFormatReader)
+ {
+ XmlFormatReader reader = (XmlFormatReader)codedInput;
+ reader.RootElementName = options.XmlReaderRootElementName;
+ reader.Options = options.XmlReaderOptions;
+ }
+
+ return codedInput;
+ }
+
+ ///
+ /// Merges the message from the input stream based on the contentType provided
+ ///
+ /// A type derived from IBuilderLite
+ /// An instance of a message builder
+ /// Options specific to reading this message and/or content type
+ /// The mime type of the input stream content
+ /// The stream to read the message from
+ /// The same builder instance that was supplied in the builder parameter
+ public static TBuilder MergeFrom(this TBuilder builder, MessageFormatOptions options, string contentType, Stream input) where TBuilder : IBuilderLite
+ {
+ ICodedInputStream codedInput = CreateInputStream(options, contentType, input);
+ codedInput.ReadMessageStart();
+ builder.WeakMergeFrom(codedInput, options.ExtensionRegistry);
+ codedInput.ReadMessageEnd();
+ return builder;
+ }
+
+ ///
+ /// Writes the message instance to the stream using the content type provided
+ ///
+ /// Options specific to writing this message and/or content type
+ /// The mime type of the content to be written
+ /// The stream to write the message to
+ /// If you do not dispose of ICodedOutputStream some formats may yield incomplete output
+ public static ICodedOutputStream CreateOutputStream(MessageFormatOptions options, string contentType, Stream output)
+ {
+ ICodedOutputStream codedOutput = ContentTypeToOutputStream(contentType, options, output);
+
+ if (codedOutput is JsonFormatWriter)
+ {
+ JsonFormatWriter writer = (JsonFormatWriter)codedOutput;
+ if (options.FormattedOutput)
+ {
+ writer.Formatted();
+ }
+ }
+ else if (codedOutput is XmlFormatWriter)
+ {
+ XmlFormatWriter writer = (XmlFormatWriter)codedOutput;
+ if (options.FormattedOutput)
+ {
+ XmlWriterSettings settings = new XmlWriterSettings()
+ {
+ CheckCharacters = false,
+ NewLineHandling = NewLineHandling.Entitize,
+ OmitXmlDeclaration = true,
+ Encoding = new UTF8Encoding(false),
+ Indent = true,
+ IndentChars = " ",
+ NewLineChars = Environment.NewLine,
+ };
+ // Don't know how else to change xml writer options?
+ codedOutput = writer = XmlFormatWriter.CreateInstance(XmlWriter.Create(output, settings));
+ }
+ writer.RootElementName = options.XmlWriterRootElementName;
+ writer.Options = options.XmlWriterOptions;
+ }
+
+ return codedOutput;
+ }
+
+ ///
+ /// Writes the message instance to the stream using the content type provided
+ ///
+ /// An instance of a message
+ /// Options specific to writing this message and/or content type
+ /// The mime type of the content to be written
+ /// The stream to write the message to
+ public static void WriteTo(this IMessageLite message, MessageFormatOptions options, string contentType, Stream output)
+ {
+ ICodedOutputStream codedOutput = CreateOutputStream(options, contentType, output);
+
+ // Output the appropriate message preamble
+ codedOutput.WriteMessageStart();
+
+ // Write the message content to the output
+ message.WriteTo(codedOutput);
+
+ // Write the closing message fragment
+ codedOutput.WriteMessageEnd();
+ codedOutput.Flush();
+ }
+
+ private static ICodedInputStream ContentTypeToInputStream(string contentType, MessageFormatOptions options, Stream input)
+ {
+ contentType = (contentType ?? String.Empty).Split(';')[0].Trim();
+
+ Converter factory;
+ if(!options.MimeInputTypesReadOnly.TryGetValue(contentType, out factory) || factory == null)
+ {
+ if(String.IsNullOrEmpty(options.DefaultContentType) ||
+ !options.MimeInputTypesReadOnly.TryGetValue(options.DefaultContentType, out factory) || factory == null)
+ {
+ throw new ArgumentOutOfRangeException("contentType");
+ }
+ }
+
+ return factory(input);
+ }
+
+ private static ICodedOutputStream ContentTypeToOutputStream(string contentType, MessageFormatOptions options, Stream output)
+ {
+ contentType = (contentType ?? String.Empty).Split(';')[0].Trim();
+
+ Converter factory;
+ if (!options.MimeOutputTypesReadOnly.TryGetValue(contentType, out factory) || factory == null)
+ {
+ if (String.IsNullOrEmpty(options.DefaultContentType) ||
+ !options.MimeOutputTypesReadOnly.TryGetValue(options.DefaultContentType, out factory) || factory == null)
+ {
+ throw new ArgumentOutOfRangeException("contentType");
+ }
+ }
+
+ return factory(output);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/ProtocolBuffers.Serialization/Http/MessageFormatOptions.cs b/src/ProtocolBuffers.Serialization/Http/MessageFormatOptions.cs
new file mode 100644
index 0000000000..72d737171d
--- /dev/null
+++ b/src/ProtocolBuffers.Serialization/Http/MessageFormatOptions.cs
@@ -0,0 +1,167 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using Google.ProtocolBuffers.Collections;
+
+namespace Google.ProtocolBuffers.Serialization.Http
+{
+ ///
+ /// Defines control information for the various formatting used with HTTP services
+ ///
+ public class MessageFormatOptions
+ {
+ /// The mime type for xml content
+ /// Other valid xml mime types include: application/binary, application/x-protobuf
+ public const string ContentTypeProtoBuffer = "application/vnd.google.protobuf";
+
+ /// The mime type for xml content
+ /// Other valid xml mime types include: text/xml
+ public const string ContentTypeXml = "application/xml";
+
+ /// The mime type for json content
+ ///
+ /// Other valid json mime types include: application/json, application/x-json,
+ /// application/x-javascript, text/javascript, text/x-javascript, text/x-json, text/json
+ ///
+ public const string ContentTypeJson = "application/json";
+
+ /// The mime type for query strings and x-www-form-urlencoded content
+ /// This mime type is input-only
+ public const string ContentFormUrlEncoded = "application/x-www-form-urlencoded";
+
+ ///
+ /// Default mime-type handling for input
+ ///
+ private static readonly IDictionary> MimeInputDefaults =
+ new ReadOnlyDictionary>(
+ new Dictionary>(StringComparer.OrdinalIgnoreCase)
+ {
+ {"application/json", JsonFormatReader.CreateInstance},
+ {"application/x-json", JsonFormatReader.CreateInstance},
+ {"application/x-javascript", JsonFormatReader.CreateInstance},
+ {"text/javascript", JsonFormatReader.CreateInstance},
+ {"text/x-javascript", JsonFormatReader.CreateInstance},
+ {"text/x-json", JsonFormatReader.CreateInstance},
+ {"text/json", JsonFormatReader.CreateInstance},
+ {"text/xml", XmlFormatReader.CreateInstance},
+ {"application/xml", XmlFormatReader.CreateInstance},
+ {"application/binary", CodedInputStream.CreateInstance},
+ {"application/x-protobuf", CodedInputStream.CreateInstance},
+ {"application/vnd.google.protobuf", CodedInputStream.CreateInstance},
+ {"application/x-www-form-urlencoded", FormUrlEncodedReader.CreateInstance},
+ }
+ );
+
+ ///
+ /// Default mime-type handling for output
+ ///
+ private static readonly IDictionary> MimeOutputDefaults =
+ new ReadOnlyDictionary>(
+ new Dictionary>(StringComparer.OrdinalIgnoreCase)
+ {
+ {"application/json", JsonFormatWriter.CreateInstance},
+ {"application/x-json", JsonFormatWriter.CreateInstance},
+ {"application/x-javascript", JsonFormatWriter.CreateInstance},
+ {"text/javascript", JsonFormatWriter.CreateInstance},
+ {"text/x-javascript", JsonFormatWriter.CreateInstance},
+ {"text/x-json", JsonFormatWriter.CreateInstance},
+ {"text/json", JsonFormatWriter.CreateInstance},
+ {"text/xml", XmlFormatWriter.CreateInstance},
+ {"application/xml", XmlFormatWriter.CreateInstance},
+ {"application/binary", CodedOutputStream.CreateInstance},
+ {"application/x-protobuf", CodedOutputStream.CreateInstance},
+ {"application/vnd.google.protobuf", CodedOutputStream.CreateInstance},
+ }
+ );
+
+
+
+
+ private string _defaultContentType;
+ private string _xmlReaderRootElementName;
+ private string _xmlWriterRootElementName;
+ private ExtensionRegistry _extensionRegistry;
+ private Dictionary> _mimeInputTypes;
+ private Dictionary> _mimeOutputTypes;
+
+ /// Provides access to modify the mime-type input stream construction
+ public IDictionary> MimeInputTypes
+ {
+ get
+ {
+ return _mimeInputTypes ??
+ (_mimeInputTypes = new Dictionary>(
+ MimeInputDefaults, StringComparer.OrdinalIgnoreCase));
+ }
+ }
+
+ /// Provides access to modify the mime-type input stream construction
+ public IDictionary> MimeOutputTypes
+ {
+ get
+ {
+ return _mimeOutputTypes ??
+ (_mimeOutputTypes = new Dictionary>(
+ MimeOutputDefaults, StringComparer.OrdinalIgnoreCase));
+ }
+ }
+
+ internal IDictionary> MimeInputTypesReadOnly
+ { get { return _mimeInputTypes ?? MimeInputDefaults; } }
+
+ internal IDictionary> MimeOutputTypesReadOnly
+ { get { return _mimeOutputTypes ?? MimeOutputDefaults; } }
+
+ ///
+ /// The default content type to use if the input type is null or empty. If this
+ /// value is not supplied an ArgumentOutOfRangeException exception will be raised.
+ ///
+ public string DefaultContentType
+ {
+ get { return _defaultContentType ?? String.Empty; }
+ set { _defaultContentType = value; }
+ }
+
+ ///
+ /// The extension registry to use when reading messages
+ ///
+ public ExtensionRegistry ExtensionRegistry
+ {
+ get { return _extensionRegistry ?? ExtensionRegistry.Empty; }
+ set { _extensionRegistry = value; }
+ }
+
+ ///
+ /// The name of the xml root element when reading messages
+ ///
+ public string XmlReaderRootElementName
+ {
+ get { return _xmlReaderRootElementName ?? XmlFormatReader.DefaultRootElementName; }
+ set { _xmlReaderRootElementName = value; }
+ }
+
+ ///
+ /// Xml reader options
+ ///
+ public XmlReaderOptions XmlReaderOptions { get; set; }
+
+ ///
+ /// True to use formatted output including new-lines and default indentation
+ ///
+ public bool FormattedOutput { get; set; }
+
+ ///
+ /// The name of the xml root element when writing messages
+ ///
+ public string XmlWriterRootElementName
+ {
+ get { return _xmlWriterRootElementName ?? XmlFormatWriter.DefaultRootElementName; }
+ set { _xmlWriterRootElementName = value; }
+ }
+
+ ///
+ /// Xml writer options
+ ///
+ public XmlWriterOptions XmlWriterOptions { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/ProtocolBuffers.Serialization/Http/ServiceExtensions.cs b/src/ProtocolBuffers.Serialization/Http/ServiceExtensions.cs
new file mode 100644
index 0000000000..6177d9dbdf
--- /dev/null
+++ b/src/ProtocolBuffers.Serialization/Http/ServiceExtensions.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+using System.Text;
+using Google.ProtocolBuffers;
+using System.IO;
+
+namespace Google.ProtocolBuffers.Serialization.Http
+{
+ ///
+ /// Extensions for the IRpcServerStub
+ ///
+ public static class ServiceExtensions
+ {
+ ///
+ /// Used to implement a service endpoint on an HTTP server. This works with services generated with the
+ /// service_generator_type option set to IRPCDISPATCH.
+ ///
+ /// The service execution stub
+ /// The name of the method being invoked
+ /// optional arguments for the format reader/writer
+ /// The mime type for the input stream
+ /// The input stream
+ /// The mime type for the output stream
+ /// The output stream
+ public static void HttpCallMethod(this IRpcServerStub stub, string methodName, MessageFormatOptions options,
+ string contentType, Stream input, string responseType, Stream output)
+ {
+ ICodedInputStream codedInput = MessageFormatFactory.CreateInputStream(options, contentType, input);
+ codedInput.ReadMessageStart();
+ IMessageLite response = stub.CallMethod(methodName, codedInput, options.ExtensionRegistry);
+ codedInput.ReadMessageEnd();
+ response.WriteTo(options, responseType, output);
+ }
+ }
+}
diff --git a/src/ProtocolBuffers.Serialization/JsonFormatReader.cs b/src/ProtocolBuffers.Serialization/JsonFormatReader.cs
index d4505d709d..7b88cafeb2 100644
--- a/src/ProtocolBuffers.Serialization/JsonFormatReader.cs
+++ b/src/ProtocolBuffers.Serialization/JsonFormatReader.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
@@ -11,6 +11,7 @@ namespace Google.ProtocolBuffers.Serialization
public class JsonFormatReader : AbstractTextReader
{
private readonly JsonCursor _input;
+ // The expected token that ends the current item, either ']' or '}'
private readonly Stack _stopChar;
private enum ReaderState
@@ -101,17 +102,33 @@ namespace Google.ProtocolBuffers.Serialization
}
///
- /// Merges the contents of stream into the provided message builder
+ /// Reads the root-message preamble specific to this formatter
///
- public override TBuilder Merge(TBuilder builder, ExtensionRegistry registry)
+ public override void ReadMessageStart()
{
_input.Consume('{');
_stopChar.Push('}');
_state = ReaderState.BeginObject;
- builder.WeakMergeFrom(this, registry);
- _input.Consume((char) _stopChar.Pop());
+ }
+
+ ///
+ /// Reads the root-message close specific to this formatter
+ ///
+ public override void ReadMessageEnd()
+ {
+ _input.Consume((char)_stopChar.Pop());
_state = ReaderState.EndValue;
+ }
+
+ ///
+ /// Merges the contents of stream into the provided message builder
+ ///
+ public override TBuilder Merge(TBuilder builder, ExtensionRegistry registry)
+ {
+ ReadMessageStart();
+ builder.WeakMergeFrom(this, registry);
+ ReadMessageEnd();
return builder;
}
diff --git a/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs b/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs
index d54507cc42..d7fd9e7b8e 100644
--- a/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs
+++ b/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
@@ -101,7 +101,7 @@ namespace Google.ProtocolBuffers.Serialization
private class JsonStreamWriter : JsonFormatWriter
{
#if SILVERLIGHT2 || COMPACT_FRAMEWORK_35
- static readonly Encoding Encoding = Encoding.UTF8;
+ static readonly Encoding Encoding = new UTF8Encoding(false);
#else
private static readonly Encoding Encoding = Encoding.ASCII;
#endif
@@ -168,7 +168,9 @@ namespace Google.ProtocolBuffers.Serialization
#endregion
+ //Tracks the writer depth and the array element count at that depth.
private readonly List _counter;
+ //True if the top-level of the writer is an array as opposed to a single message.
private bool _isArray;
///
@@ -243,7 +245,7 @@ namespace Google.ProtocolBuffers.Serialization
{
if (_counter.Count == 0)
{
- throw new InvalidOperationException("Missmatched open/close in Json writer.");
+ throw new InvalidOperationException("Mismatched open/close in Json writer.");
}
int index = _counter.Count - 1;
@@ -444,6 +446,18 @@ namespace Google.ProtocolBuffers.Serialization
/// Writes the message to the the formatted stream.
///
public override void WriteMessage(IMessageLite message)
+ {
+ WriteMessageStart();
+ message.WriteTo(this);
+ WriteMessageEnd();
+ }
+
+ ///
+ /// Used to write the root-message preamble, in json this is the left-curly brace '{'.
+ /// After this call you can call IMessageLite.MergeTo(...) and complete the message with
+ /// a call to WriteMessageEnd().
+ ///
+ public override void WriteMessageStart()
{
if (_isArray)
{
@@ -451,7 +465,13 @@ namespace Google.ProtocolBuffers.Serialization
}
WriteToOutput("{");
_counter.Add(0);
- message.WriteTo(this);
+ }
+
+ ///
+ /// Used to complete a root-message previously started with a call to WriteMessageStart()
+ ///
+ public override void WriteMessageEnd()
+ {
_counter.RemoveAt(_counter.Count - 1);
WriteLine("}");
Flush();
diff --git a/src/ProtocolBuffers.Serialization/ProtocolBuffers.Serialization.csproj b/src/ProtocolBuffers.Serialization/ProtocolBuffers.Serialization.csproj
index 0c53577c38..972fb149b5 100644
--- a/src/ProtocolBuffers.Serialization/ProtocolBuffers.Serialization.csproj
+++ b/src/ProtocolBuffers.Serialization/ProtocolBuffers.Serialization.csproj
@@ -98,6 +98,10 @@
+
+
+
+
diff --git a/src/ProtocolBuffers.Serialization/XmlFormatReader.cs b/src/ProtocolBuffers.Serialization/XmlFormatReader.cs
index cb2cb2ea70..4bf6423c6c 100644
--- a/src/ProtocolBuffers.Serialization/XmlFormatReader.cs
+++ b/src/ProtocolBuffers.Serialization/XmlFormatReader.cs
@@ -1,7 +1,8 @@
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
+using System.Diagnostics;
namespace Google.ProtocolBuffers.Serialization
{
@@ -14,8 +15,25 @@ namespace Google.ProtocolBuffers.Serialization
{
public const string DefaultRootElementName = XmlFormatWriter.DefaultRootElementName;
private readonly XmlReader _input;
+ // Tracks the message element for each nested message read
+ private readonly Stack _elements;
+ // The default element name for ReadMessageStart
private string _rootElementName;
+ private struct ElementStackEntry
+ {
+ public readonly string LocalName;
+ public readonly int Depth;
+ public readonly bool IsEmpty;
+
+ public ElementStackEntry(string localName, int depth, bool isEmpty) : this()
+ {
+ LocalName = localName;
+ IsEmpty = isEmpty;
+ Depth = depth;
+ }
+ }
+
private static XmlReaderSettings DefaultSettings
{
get
@@ -72,20 +90,10 @@ namespace Google.ProtocolBuffers.Serialization
{
_input = input;
_rootElementName = DefaultRootElementName;
+ _elements = new Stack();
Options = XmlReaderOptions.None;
}
- ///
- /// Constructs the XmlFormatReader with the XmlReader and options
- ///
- protected XmlFormatReader(XmlFormatReader copyFrom, XmlReader input)
- : base(copyFrom)
- {
- _input = input;
- _rootElementName = copyFrom._rootElementName;
- Options = copyFrom.Options;
- }
-
///
/// Gets or sets the options to use when reading the xml
///
@@ -113,26 +121,61 @@ namespace Google.ProtocolBuffers.Serialization
}
}
- private XmlFormatReader CloneWith(XmlReader rdr)
+ [DebuggerNonUserCode]
+ private static void Assert(bool cond)
{
- XmlFormatReader copy = new XmlFormatReader(this, rdr);
- return copy;
+ if (!cond)
+ {
+ throw new FormatException();
+ }
}
- private void NextElement()
+ ///
+ /// Reads the root-message preamble specific to this formatter
+ ///
+ public override void ReadMessageStart()
+ {
+ ReadMessageStart(_rootElementName);
+ }
+
+ ///
+ /// Reads the root-message preamble specific to this formatter
+ ///
+ public void ReadMessageStart(string element)
{
while (!_input.IsStartElement() && _input.Read())
{
continue;
}
+ Assert(_input.IsStartElement() && _input.LocalName == element);
+ _elements.Push(new ElementStackEntry(element, _input.Depth, _input.IsEmptyElement));
+ _input.Read();
}
- private static void Assert(bool cond)
+ ///
+ /// Reads the root-message close specific to this formatter, MUST be called
+ /// on the reader obtained from ReadMessageStart(string element).
+ ///
+ public override void ReadMessageEnd()
{
- if (!cond)
+ Assert(_elements.Count > 0);
+
+ ElementStackEntry stop = _elements.Peek();
+ while (_input.NodeType != XmlNodeType.EndElement && _input.NodeType != XmlNodeType.Element
+ && _input.Depth > stop.Depth && _input.Read())
{
- throw new FormatException();
+ continue;
+ }
+
+ if (!stop.IsEmpty)
+ {
+ Assert(_input.NodeType == XmlNodeType.EndElement
+ && _input.LocalName == stop.LocalName
+ && _input.Depth == stop.Depth);
+
+ _input.Read();
}
+ _elements.Pop();
}
///
@@ -157,9 +200,9 @@ namespace Google.ProtocolBuffers.Serialization
public TBuilder Merge(string element, TBuilder builder, ExtensionRegistry registry)
where TBuilder : IBuilderLite
{
- string field;
- Assert(PeekNext(out field) && field == element);
- ReadMessage(builder, registry);
+ ReadMessageStart(element);
+ builder.WeakMergeFrom(this, registry);
+ ReadMessageEnd();
return builder;
}
@@ -172,7 +215,21 @@ namespace Google.ProtocolBuffers.Serialization
///
protected override bool PeekNext(out string field)
{
- NextElement();
+ ElementStackEntry stopNode;
+ if (_elements.Count == 0)
+ {
+ stopNode = new ElementStackEntry(null, _input.Depth - 1, false);
+ }
+ else
+ {
+ stopNode = _elements.Peek();
+ }
+
+ while (!_input.IsStartElement() && _input.Depth > stopNode.Depth && _input.Read())
+ {
+ continue;
+ }
+
if (_input.IsStartElement())
{
field = _input.LocalName;
@@ -235,20 +292,9 @@ namespace Google.ProtocolBuffers.Serialization
protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry)
{
Assert(_input.IsStartElement());
-
- if (!_input.IsEmptyElement)
- {
- int depth = _input.Depth;
- XmlReader child = _input.ReadSubtree();
- while (!child.IsStartElement() && child.Read())
- {
- continue;
- }
- child.Read();
- builder.WeakMergeFrom(CloneWith(child), registry);
- Assert(depth == _input.Depth && _input.NodeType == XmlNodeType.EndElement);
- }
- _input.Read();
+ ReadMessageStart(_input.LocalName);
+ builder.WeakMergeFrom(this, registry);
+ ReadMessageEnd();
return true;
}
@@ -270,27 +316,20 @@ namespace Google.ProtocolBuffers.Serialization
{
yield return item;
}
- yield break;
}
- if (!_input.IsEmptyElement)
+ else
{
- int depth = _input.Depth;
- XmlReader child = _input.ReadSubtree();
-
- while (!child.IsStartElement() && child.Read())
+ string found;
+ ReadMessageStart(field);
+ if (PeekNext(out found) && found == "item")
{
- continue;
- }
- child.Read();
-
- foreach (string item in CloneWith(child).NonNestedArrayItems("item"))
- {
- yield return item;
+ foreach (string item in NonNestedArrayItems("item"))
+ {
+ yield return item;
+ }
}
- Assert(depth == _input.Depth && _input.NodeType == XmlNodeType.EndElement);
+ ReadMessageEnd();
}
- _input.Read();
- yield break;
}
}
}
\ No newline at end of file
diff --git a/src/ProtocolBuffers.Serialization/XmlFormatWriter.cs b/src/ProtocolBuffers.Serialization/XmlFormatWriter.cs
index fd36c1de01..4bd27562cb 100644
--- a/src/ProtocolBuffers.Serialization/XmlFormatWriter.cs
+++ b/src/ProtocolBuffers.Serialization/XmlFormatWriter.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections;
using System.IO;
using System.Text;
@@ -14,10 +14,14 @@ namespace Google.ProtocolBuffers.Serialization
///
public class XmlFormatWriter : AbstractTextWriter
{
+ private static readonly Encoding DefaultEncoding = new UTF8Encoding(false);
public const string DefaultRootElementName = "root";
- private const int NestedArrayFlag = 0x0001;
+
private readonly XmlWriter _output;
+ // The default element name used for WriteMessageStart
private string _rootElementName;
+ // Used to assert matching WriteMessageStart/WriteMessageEnd calls
+ private int _messageOpenCount;
private static XmlWriterSettings DefaultSettings(Encoding encoding)
{
@@ -43,7 +47,7 @@ namespace Google.ProtocolBuffers.Serialization
///
public static XmlFormatWriter CreateInstance(Stream output)
{
- return new XmlFormatWriter(XmlWriter.Create(output, DefaultSettings(Encoding.UTF8)));
+ return new XmlFormatWriter(XmlWriter.Create(output, DefaultSettings(DefaultEncoding)));
}
///
@@ -65,20 +69,10 @@ namespace Google.ProtocolBuffers.Serialization
protected XmlFormatWriter(XmlWriter output)
{
_output = output;
+ _messageOpenCount = 0;
_rootElementName = DefaultRootElementName;
}
- ///
- /// Closes the underlying XmlTextWriter
- ///
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- _output.Close();
- }
- }
-
///
/// Gets or sets the default element name to use when using the Merge<TBuilder>()
///
@@ -112,17 +106,30 @@ namespace Google.ProtocolBuffers.Serialization
}
///
- /// Writes a message as an element using the name defined in
+ /// Completes any pending write operations
///
- public override void WriteMessage(IMessageLite message)
+ public override void Flush()
{
- WriteMessage(_rootElementName, message);
+ _output.Flush();
+ base.Flush();
}
///
- /// Writes a message as an element with the given name
+ /// Used to write the root-message preamble, in xml this is open element for RootElementName,
+ /// by default "<root>". After this call you can call IMessageLite.MergeTo(...) and
+ /// complete the message with a call to WriteMessageEnd().
///
- public void WriteMessage(string elementName, IMessageLite message)
+ public override void WriteMessageStart()
+ {
+ WriteMessageStart(_rootElementName);
+ }
+
+ ///
+ /// Used to write the root-message preamble, in xml this is open element for elementName.
+ /// After this call you can call IMessageLite.MergeTo(...) and complete the message with
+ /// a call to WriteMessageEnd().
+ ///
+ public void WriteMessageStart(string elementName)
{
if (TestOption(XmlWriterOptions.OutputJsonTypes))
{
@@ -133,10 +140,40 @@ namespace Google.ProtocolBuffers.Serialization
{
_output.WriteStartElement(elementName);
}
+ _messageOpenCount++;
+ }
+
+ ///
+ /// Used to complete a root-message previously started with a call to WriteMessageStart()
+ ///
+ public override void WriteMessageEnd()
+ {
+ if (_messageOpenCount <= 0)
+ {
+ throw new InvalidOperationException();
+ }
- message.WriteTo(this);
_output.WriteEndElement();
_output.Flush();
+ _messageOpenCount--;
+ }
+
+ ///
+ /// Writes a message as an element using the name defined in
+ ///
+ public override void WriteMessage(IMessageLite message)
+ {
+ WriteMessage(_rootElementName, message);
+ }
+
+ ///
+ /// Writes a message as an element with the given name
+ ///
+ public void WriteMessage(string elementName, IMessageLite message)
+ {
+ WriteMessageStart(elementName);
+ message.WriteTo(this);
+ WriteMessageEnd();
}
///
diff --git a/src/ProtocolBuffers.Test/CodedInputStreamTest.cs b/src/ProtocolBuffers.Test/CodedInputStreamTest.cs
index c3ca0a10ff..64656b196f 100644
--- a/src/ProtocolBuffers.Test/CodedInputStreamTest.cs
+++ b/src/ProtocolBuffers.Test/CodedInputStreamTest.cs
@@ -35,6 +35,7 @@
#endregion
using System;
+using System.Collections.Generic;
using System.IO;
using Google.ProtocolBuffers.TestProtos;
using NUnit.Framework;
@@ -532,5 +533,77 @@ namespace Google.ProtocolBuffers
return base.Read(buffer, offset, Math.Min(count, blockSize));
}
}
+
+ enum TestNegEnum { None = 0, Value = -2 }
+
+ [Test]
+ public void TestNegativeEnum()
+ {
+ byte[] bytes = new byte[10] { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 };
+ CodedInputStream input = CodedInputStream.CreateInstance(bytes);
+ object unk;
+ TestNegEnum val = TestNegEnum.None;
+
+ Assert.IsTrue(input.ReadEnum(ref val, out unk));
+ Assert.IsTrue(input.IsAtEnd);
+ Assert.AreEqual(TestNegEnum.Value, val);
+ }
+
+ [Test]
+ public void TestNegativeEnumPackedArray()
+ {
+ int arraySize = 1 + (10 * 5);
+ int msgSize = 1 + 1 + arraySize;
+ byte[] bytes = new byte[msgSize];
+ CodedOutputStream output = CodedOutputStream.CreateInstance(bytes);
+ output.WritePackedInt32Array(8, "", arraySize, new int[] { 0, -1, -2, -3, -4, -5 });
+
+ Assert.AreEqual(0, output.SpaceLeft);
+
+ CodedInputStream input = CodedInputStream.CreateInstance(bytes);
+ uint tag;
+ string name;
+ Assert.IsTrue(input.ReadTag(out tag, out name));
+
+ List values = new List();
+ ICollection